2010-11-18 40 views
19

Tôi đang cố phân tích nội dung trong bảng tính ODS của OpenOffice. Định dạng ods về cơ bản chỉ là một tệp zip với một số tài liệu. Nội dung của bảng tính được lưu trữ trong 'content.xml'.Làm cách nào để sử dụng không gian tên xml với tìm/tìm thấy trong lxml?

import zipfile 
from lxml import etree 

zf = zipfile.ZipFile('spreadsheet.ods') 
root = etree.parse(zf.open('content.xml')) 

Nội dung của bảng tính là trong một tế bào:

table = root.find('.//{urn:oasis:names:tc:opendocument:xmlns:table:1.0}table') 

Chúng tôi cũng có thể đi thẳng cho các hàng:

rows = root.findall('.//{urn:oasis:names:tc:opendocument:xmlns:table:1.0}table-row') 

Các yếu tố cá nhân biết về không gian tên:

>>> table.nsmap['table'] 
'urn:oasis:names:tc:opendocument:xmlns:table:1.0' 

Cách thực hiện Tôi sử dụng các không gian tên trực tiếp trong find/findall?

Giải pháp rõ ràng không hoạt động.

Đang cố gắng để có được các hàng từ bảng:

>>> root.findall('.//table:table') 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "lxml.etree.pyx", line 1792, in lxml.etree._ElementTree.findall (src/lxml/lxml.etree.c:41770) 
    File "lxml.etree.pyx", line 1297, in lxml.etree._Element.findall (src/lxml/lxml.etree.c:37027) 
    File "/usr/lib/python2.6/dist-packages/lxml/_elementpath.py", line 225, in findall 
    return list(iterfind(elem, path)) 
    File "/usr/lib/python2.6/dist-packages/lxml/_elementpath.py", line 200, in iterfind 
    selector = _build_path_iterator(path) 
    File "/usr/lib/python2.6/dist-packages/lxml/_elementpath.py", line 184, in _build_path_iterator 
    selector.append(ops[token[0]](_next, token)) 
KeyError: ':' 
+0

Bạn đã cố gắng sử dụng Python API cho OpenOffice để xử lý bảng tính? – jfs

+0

Xin chào, tôi đang sử dụng etree.QName để truy cập Phần tử và thuộc tính với Không gian tên. một cách gọn gàng với sự giúp đỡ của một từ điển không gian tên, và nó hoạt động với phương pháp find và findall. để biết thêm thông tin, vui lòng tham khảo: http://lxml.de/tutorial.html#namespaces –

Trả lời

16

Nếu root.nsmap chứa tiền tố table namespace sau đó bạn có thể:

root.xpath('.//table:table', namespaces=root.nsmap) 

findall(path) chấp nhận {namespace}name cú pháp thay vì namespace:name. Do đó, path phải được xử lý trước bằng cách sử dụng từ điển không gian tên thành biểu mẫu {namespace}name trước khi chuyển đến findall().

+0

Thú vị, nhưng dường như có một vấn đề cấp thấp hơn: table.xpath ('.// ​​table: table-row', nsmap = table.nsmap) *** XPathResultError: Loại trả về không xác định: dict – saffsd

+0

@saffsd: Lưu ý: * namespaces = * not * nsmap = *. Hãy thử: 'root.xpath ('.// ​​table: table-row', namespaces = {'table': 'urn: ốc đảo: tên: tc: opendocument: xmlns: table: 1.0'})' – jfs

6

Đây là cách để có được tất cả các không gian tên trong tài liệu XML (và giả sử không có xung đột tiền tố).

Tôi sử dụng điều này khi phân tích cú pháp tài liệu XML nơi tôi biết trước URL không gian tên là gì và chỉ tiền tố.

 doc = etree.XML(XML_string) 

     # Getting all the name spaces. 
     nsmap = {} 
     for ns in doc.xpath('//namespace::*'): 
      if ns[0]: # Removes the None namespace, neither needed nor supported. 
       nsmap[ns[0]] = ns[1] 
     doc.xpath('//prefix:element', namespaces=nsmap) 
5

Có lẽ điều đầu tiên cần chú ý đó là các không gian tên được quy định tại Yếu tố mức, không Document cấp.

Thông thường tuy nhiên, tất cả các không gian tên được khai báo trong phần tử gốc của tài liệu (office:document-content đây), mà cứu chúng ta phân tích nó tất cả để thu thập nội xmlns phạm vi.

Sau đó một nsmap yếu tố bao gồm:

  • một không gian tên mặc định, với None tiền tố (không phải luôn luôn)
  • tất cả tổ tiên không gian tên, trừ khi ghi đè.

Nếu, như ChrisR mentionned, không gian tên mặc định không được hỗ trợ, bạn có thể sử dụng một dict comprehension để lọc nó ra trong một biểu thức nhỏ gọn hơn.

Bạn có một cú pháp hơi khác cho xpath và ElementPath.


Vì vậy, đây là mã bạn có thể sử dụng để có được tất cả các hàng bảng đầu tiên của bạn (thử nghiệm với: lxml=3.4.2):

import zipfile 
from lxml import etree 

# Open and parse the document 
zf = zipfile.ZipFile('spreadsheet.ods') 
tree = etree.parse(zf.open('content.xml')) 

# Get the root element 
root = tree.getroot() 

# get its namespace map, excluding default namespace 
nsmap = {k:v for k,v in root.nsmap.iteritems() if k} 

# use defined prefixes to access elements 
table = tree.find('.//table:table', nsmap) 
rows = table.findall('table:table-row', nsmap) 

# or, if xpath is needed: 
table = tree.xpath('//table:table', namespaces=nsmap)[0] 
rows = table.xpath('table:table-row', namespaces=nsmap) 
+0

Nếu bạn cần nsmap bao gồm không gian tên mặc định, sử dụng (Python 3): 'nsmap = {k nếu k không phải là None else 'default': v cho k, v trong root.nsmap.items()}' – skelliam

+0

Đối với Python 3 rename iteritems () ở trên để chỉ các mục(). – skelliam

Các vấn đề liên quan