Python + Expat: ошибка в & # 0; юридические лица

Я написал небольшую функцию, которая использует ElementTree и xpath для извлечения текстового содержимого определенных элементов в XML-файл:

#!/usr/bin/env python2.5

import doctest
from xml.etree import ElementTree
from StringIO import StringIO

def parse_xml_etree(sin, xpath):
  """
Takes as input a stream containing XML and an XPath expression.
Applies the XPath expression to the XML and returns a generator
yielding the text contents of each element returned.

>>> parse_xml_etree(
...   StringIO('<test><elem1>one</elem1><elem2>two</elem2></test>'),
...   '//elem1').next()
'one'
>>> parse_xml_etree(
...   StringIO('<test><elem1>one</elem1><elem2>two</elem2></test>'),
...   '//elem2').next()
'two'
>>> parse_xml_etree(
...   StringIO('<test><null>&#0;</null><elem3>three</elem3></test>'),
...   '//elem2').next()
'three'
"""

  tree = ElementTree.parse(sin)
  for element in tree.findall(xpath):
    yield element.text  

if __name__ == '__main__':
  doctest.testmod(verbose=True)

Третий тест не пройден со следующим исключением:

ExpatError: ссылка на недопустимый номер символа: строка 1, столбец 13

Это &#0; сущность нелегального XML? Независимо от того, есть это или нет, файлы, которые я хочу проанализировать, содержат его, и мне нужен какой-то способ их проанализировать. Любые предложения для другого парсера, чем Expat, или настройки для Expat, которые позволили бы мне сделать это?


Обновление: я только что обнаружил BeautifulSoup, анализатор супа тегов, как отмечено ниже в комментарии к ответу, и для забавы я вернулся к этой проблеме и попытался использовать ее как XML-очиститель перед ElementTree, но он покорно преобразовал &#0; в недействительный нулевой байт.:-)

cleaned_s = StringIO(
  BeautifulStoneSoup('<test><null>&#0;</null><elem3>three</elem3></test>',
                     convertEntities=BeautifulStoneSoup.XML_ENTITIES
  ).renderContents()
)
tree = ElementTree.parse(cleaned_s)

... дает

xml.parsers.expat.ExpatError: not well-formed (invalid token): line 1, column 12

Однако в моем конкретном случае мне не нужно было разбирать XPath как таковой, я мог бы использовать сам BeautifulSoup и его довольно простой стиль адресации узлов. parsed_tree.test.elem1.contents[0],

2 ответа

Решение

&#0; не находится в допустимом диапазоне символов, определенном спецификацией XML. Увы, мои навыки работы с Python довольно просты, поэтому я не сильно помогаю там.

&#0; не является допустимым символом XML. В идеале вы могли бы заставить создателя файла изменить свой процесс, чтобы файл не был недействительным, как этот.

Если вы должны принять эти файлы, вы можете предварительно обработать их, чтобы включить &#0 во что-то еще. Например, выберите @ в качестве escape-символа, превратите "@" в "@@" и "&#0;"в"@0".

Затем, когда вы получаете текстовые данные из анализатора, вы можете полностью изменить отображение. Это всего лишь пример, вы можете придумать любой подходящий вам синтаксис.

Другие вопросы по тегам