Подтвердить что ты не робот

Python: Unicode и ElementTree.parse

Я пытаюсь перейти на Python 2.7, и поскольку Unicode - это большая сделка, я бы попытался разобраться с ними с файлами и текстами XML и проанализировать их с помощью библиотеки xml.etree.cElementTree. Но я столкнулся с этой ошибкой:

>>> 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

То же самое происходит при использовании io.open('filename.xml', encoding='utf-8') для перехода к 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

Есть ли что-то о unicode и синтаксическом анализе ET, которое я здесь отсутствует?

edit. По-видимому, парсер ET не хорошо работает с входным потоком Unicode? Следующие работы:

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

Но это также означает, что я не могу использовать io.StringIO, если я хочу анализировать текст в памяти, если я не сначала его закодирую в буфере в памяти?

4b9b3361

Ответ 1

Не можете ли вы использовать

doc = ET.fromstring(source)

в вашем первом примере?

Ответ 2

Ваша проблема в том, что вы кормите ElementTree unicode, но предпочитаете потреблять байты. Он предоставит вам unicode в любом случае.

В Python 2.x он может потреблять только байты. Вы можете сказать, в чем кодировка этих байтов, но что это. Итак, если вы буквально должны работать с объектом, представляющим текстовый файл, например io.StringIO, сначала вам нужно будет преобразовать его в нечто другое.

Если вы буквально начинаете с 2.x- str (AKA bytes) в кодировке UTF-8, в памяти, как в вашем примере, используйте xml.etree.cElementTree.XML для синтаксического анализа его в XML одним махом и не беспокойтесь об этом: -).

Если вам нужен интерфейс, который может обрабатывать данные, которые постепенно считываются из файла, используйте xml.etree.cElementTree.parse с io.BytesIO, чтобы преобразовать его в поток байтов в памяти, а не строка символов в памяти. Если вы хотите использовать io.open, используйте его с флагом b, чтобы получить потоки байтов.

В Python 3.x вы можете передать unicode непосредственно в ElementTree, что немного более удобно, и, возможно, более новая версия ElementTree является более правильной, чтобы разрешить это. Однако вы все равно не захотите, и версия Python 3 все еще принимает байты в качестве входных данных. Вы все равно начинаете с байтов: передавая их напрямую из вашего источника входного сигнала в ElementTree, вы можете позволить ему делать свою кодировку или декодирование разумно внутри механизма синтаксического анализа XML, а также выполнять "на лету" обнаружение объявлений кодирования внутри входного потока, который вы можете использовать с XML, но вы не можете делать с произвольными текстовыми данными. Поэтому позволить парсеру XML делать работу по расшифровке - это правильное место, чтобы возложить эту ответственность.

Ответ 3

Я столкнулся с той же проблемой, что и в Python 2.6.

Похоже, что кодировка "utf-8" для cElementTree.parse в версиях Python 2.x и 3.x отличается. В Python 2.x мы можем использовать XMLParser для кодирования unicode. Например:

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)

Вы можете ссылаться на эту страницу для метода XMLParser (раздел "XMLParser" ): http://effbot.org/zone/elementtree-13-intro.htm

Хотя для версии Python 3.x работает следующий метод:

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)

Надеюсь, это поможет вам.