Есть ли способ заставить lxml обрабатывать строки Unicode, которые указывают кодировку в теге?
У меня есть XML файл, который указывает кодировку, и я использую UnicodeDammit для преобразования в unicode (по причинам хранения я не могу хранить его как строку). Я позже передаю его в lxml, но он отказывается игнорировать кодировку, указанную в файле, и анализирует ее как Unicode, и она вызывает исключение.
Как заставить lxml анализировать документ? Такое поведение кажется слишком ограничительным.
Ответы
Ответ 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-декларации?