2010-08-05 30 views
10

Tôi đang cố gắng chuyển sang Python 2.7 và vì Unicode là một Giao dịch lớn ở đó, tôi sẽ thử xử lý chúng với các tệp và văn bản XML và phân tích chúng bằng thư viện xml.etree.cElementTree. Nhưng tôi chạy qua lỗi này:Python: Unicode và ElementTree.parse

>>> import xml.etree.cElementTree as ET 
>>> from io import StringIO 
>>> source = """\ 
... <?xml version="1.0" encoding="UTF-8" standalone="yes" ?> 
... <root> 
... <Parent> 
...  <Child> 
...  <Element>Text</Element> 
...  </Child> 
... </Parent> 
... </root> 
... """ 
>>> srcbuf = StringIO(source.decode('utf-8')) 
>>> doc = ET.parse(srcbuf) 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<string>", line 56, in parse 
    File "<string>", line 35, in parse 
cElementTree.ParseError: no element found: line 1, column 0 

Điều tương tự cũng xảy ra sử dụng io.open('filename.xml', encoding='utf-8') để vượt qua để ET.parse:

>>> with io.open('test.xml', mode='w', encoding='utf-8') as fp: 
...  fp.write(source.decode('utf-8')) 
... 
150L 
>>> with io.open('test.xml', mode='r', encoding='utf-8') as fp: 
...  fp.read() 
... 
u'<?xml version="1.0" encoding="UTF-8" standalone="yes" ?>\n<root>\n <Parent>\n 
    <Child>\n  <Element>Text</Element>\n </Child>\n </Parent>\n</root>\n 
' 
>>> with io.open('test.xml', mode='r', encoding='utf-8') as fp: 
...  ET.parse(fp) 
... 
Traceback (most recent call last): 
    File "<stdin>", line 2, in <module> 
    File "<string>", line 56, in parse 
    File "<string>", line 35, in parse 
cElementTree.ParseError: no element found: line 1, column 0 

Có điều gì đó về unicode và ET phân tích cú pháp mà tôi đang thiếu ở đây?

chỉnh sửa: Rõ ràng, trình phân tích cú pháp ET không hoạt động tốt với luồng đầu vào unicode? Các công trình sau đây:

>>> with io.open('test.xml', mode='rb') as fp: 
...  ET.parse(fp) 
... 
<ElementTree object at 0x0180BC10> 

Nhưng điều này cũng có nghĩa là tôi không thể sử dụng io.StringIO nếu tôi muốn phân tích cú pháp từ một văn bản trong bộ nhớ, trừ khi tôi mã hóa nó đầu tiên vào một bộ đệm trong bộ nhớ?

Trả lời

3

bạn không thể sử dụng

doc = ET.fromstring(source) 

trong ví dụ đầu tiên của bạn?

+0

Tôi không nhận ra rằng chức năng đó đã tồn tại. Mặc dù điểm nhỏ: 'fromstring' trả về' Element', trong khi 'parse' trả về' ElementTree'. – Santa

+1

Chức năng này còn được gọi là bí danh của nó, 'XML', tức là' từ xml.etree.cElementTree nhập XML'. Bí danh này có sẵn để nó sẽ đọc độc đáo nếu bạn có một hằng số XML trong mã của bạn; bạn chỉ có thể làm 'fooDocument = XML (" "" ... "" ")'. – Glyph

6

Tôi gặp phải vấn đề tương tự như bạn trong Python 2.6.

Dường như mã hóa "utf-8" cho cElementTree.parse trong phiên bản Python 2.x và 3.x là khác nhau. Trong Python 2.x, chúng ta có thể sử dụng XMLParser để mã hóa unicode. Ví dụ:

import xml.etree.cElementTree as etree 

parser = etree.XMLParser(encoding="utf-8") 
targetTree = etree.parse("./targetPageID.xml", parser=parser) 
pageIds = targetTree.find("categorymembers") 
print "pageIds:",etree.tostring(pageIds) 

Bạn có thể tham khảo trang này cho phương pháp XMLParser (Mục "XMLParser"): http://effbot.org/zone/elementtree-13-intro.htm

Trong khi phương pháp sau đây làm việc cho Python 3.x phiên bản:

import xml.etree.cElementTree as etree 
import codecs 

target_file = codecs.open("./targetPageID.xml",mode='r',encoding='utf-8') 

targetTree = etree.parse(target_file) 
pageIds = targetTree.find("categorymembers") 
print "pageIds:",etree.tostring(pageIds) 

Hy vọng điều này có thể giúp bạn.

+1

Đây là loại quyền, nhưng các phiên bản ElementTree tương tự hơn giữa Python 2 và Python 3 hơn bạn cho chúng tín dụng. Tôi sẽ viết một câu trả lời khác, tôi nghĩ vậy. – Glyph

13

Vấn đề của bạn là bạn đang cho ăn ElementTree unicode, nhưng nó thích để tiêu thụ byte. Nó sẽ cung cấp bạn với unicode trong mọi trường hợp.

Trong Python 2.x, nó có thể chỉ tiêu thụ byte. Bạn có thể cho nó biết những gì mã hóa các byte đó, nhưng đó là nó. Vì vậy, nếu bạn theo nghĩa đen phải làm việc với một đối tượng đại diện cho tệp văn bản , như io.StringIO, trước tiên bạn sẽ cần phải chuyển đổi nó thành một thứ khác.

Nếu bạn đang theo nghĩa đen bắt đầu với một 2.x- str (AKA bytes) trong mã UTF-8, trong ký ức, như trong ví dụ của bạn, sử dụng xml.etree.cElementTree.XML để phân tích nó thành XML trong một ngã swoop và đừng lo lắng về bất kỳ điều này :-).

Nếu bạn muốn một giao diện mà có thể đối phó với dữ liệu được từng bước đọc từ một tập tin, sử dụng xml.etree.cElementTree.parse với một io.BytesIO để chuyển đổi nó thành một dòng trong bộ nhớ của byte chứ không phải là một chuỗi trong bộ nhớ của nhân vật.Nếu bạn muốn sử dụng io.open, hãy sử dụng nó với cờ b để bạn nhận được luồng byte.

Trong Python 3.x, bạn có thể chuyển trực tiếp mã unicode vào ElementTree, thuận tiện hơn một chút và được cho là phiên bản mới hơn của ElementTree chính xác hơn để cho phép điều này. Tuy nhiên, bạn vẫn có thể không muốn, và phiên bản Python 3 vẫn chấp nhận byte làm đầu vào. Bạn luôn bắt đầu với các byte: bằng cách chuyển chúng trực tiếp từ nguồn đầu vào của bạn tới ElementTree, bạn có thể cho phép mã hóa hoặc giải mã thông minh bên trong công cụ phân tích cú pháp XML, cũng như phát hiện các khai báo mã hóa một cách nhanh chóng trong luồng đầu vào, mà bạn có thể làm với XML nhưng bạn không thể làm với dữ liệu văn bản tùy ý. Vì vậy, để cho trình phân tích cú pháp XML thực hiện công việc giải mã là đúng nơi để đặt trách nhiệm đó.

+6

Tôi ước rằng bạn đã thêm một số mã ví dụ – Mawg