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

Есть ли способ заставить lxml обрабатывать строки Unicode, которые указывают кодировку в теге?

У меня есть XML файл, который указывает кодировку, и я использую UnicodeDammit для преобразования в unicode (по причинам хранения я не могу хранить его как строку). Я позже передаю его в lxml, но он отказывается игнорировать кодировку, указанную в файле, и анализирует ее как Unicode, и она вызывает исключение.

Как заставить lxml анализировать документ? Такое поведение кажется слишком ограничительным.

4b9b3361

Ответ 1

Вы не можете анализировать строки unicode И иметь в кодировке объявление кодировки. Таким образом, либо вы делаете его кодированной строкой (поскольку вы, по-видимому, не можете хранить ее как строку, вам придется перекодировать ее перед разбором. Или вы сериализуете дерево как unicode с помощью lxml самостоятельно: etree.tostring(tree, encoding=unicode), WITHOUT xml декларация. Вы можете легко снова проанализировать результат с помощью файла etree.fromunicode

см. http://lxml.de/parsing.html#python-unicode-strings

Изменить: если, судя по всему, у вас уже есть строка юникода и не может контролировать, как это было сделано. Вам придется снова закодировать его и предоставить парсеру используемую вами кодировку:

utf8_parser = etree.XMLParser(encoding='utf-8')

def parse_from_unicode(unicode_str):
    s = unicode_str.encode('utf-8')
    return etree.fromstring(s, parser=utf8_parser)

Это гарантирует, что все, что было внутри объявления xml, игнорируется, потому что парсер всегда будет использовать utf-8.

Ответ 2

В основном, решение должно выполняться:

if isinstance(mystring, unicode):
    mystring = mystring.encode("utf-8")

Серьезно. Хорошая работа, lxml.

EDIT: Оказывается, что в этом случае lxml автоматически не определяет кодировку. Похоже, мне придется вручную искать и удалять "charset" и "encoding" со страницы.

Ответ 3

Решение НЕ перекодирует строку. Объявление кодировки внутри строки может говорить не что иное, как UTF8. Не слепо перекодировать в utf8 и ожидать, что он будет работать все время.

Решение состоит в том, чтобы просто удалить объявление кодирования. У вас уже есть строка в формате unicode, она больше не нужна!

# this is from lxml/apihelpers.pxi
RE_XML_ENCODING = re.compile(
    ur'^(<\?xml[^>]+)\s+encoding\s*=\s*["\'][^"\']*["\'](\s*\?>|)', re.U)

RE_XML_ENCODING.sub("", broken_xml_string, count=1)

В худшем случае (где не найдено объявления кодировки xml) сложность времени здесь O (n), что довольно плохо (но все же лучше, чем слепое кодирование в двоичном формате), поэтому я открыт для предложений здесь.

PS: Некоторые интересные анализы проблемы кодирования xml:

стандартная кодировка для XML - это UTF-8 или UTF-16?

Как по умолчанию используется стандартная кодировка (UTF-8) в XML-декларации?