Comments 55
да, elementree конечно вкуснее, чем стандартный dom api.
но скажите, зачем вот это?:
app_window = etree.tostring(root)
…
root.append(etree.XML(app_window))
но скажите, зачем вот это?:
app_window = etree.tostring(root)
…
root.append(etree.XML(app_window))
поглядел в мануал.
у _ElementInterface есть методы эмуляции списков, и есть метод .append(childelement)
у _ElementInterface есть методы эмуляции списков, и есть метод .append(childelement)
Это конкретно у меня в коде, ибо эти две части находятся в разных функциях, а передавать строку нагляднее и проще. Да и потом, я же тоже изучал новые возможности модуля, вот, собственно, такое простое и красивое преобразование — тоже хорошая вещь :)
Спасибо! вижу что есть смысл попробовать lxml.
Сам довольно долго промучался с minidom, особенно с проблемами кодировки, однако задача была решена.
Кстати, toprettyxml() является лишь оберткой toxml(), а у последнего есть еще параметры, задающие символы отступа строки (по умолчанию \t) и разделитель самих строк (\n). Однако опять-таки это не всегда может помочь.
Сам довольно долго промучался с minidom, особенно с проблемами кодировки, однако задача была решена.
Кстати, toprettyxml() является лишь оберткой toxml(), а у последнего есть еще параметры, задающие символы отступа строки (по умолчанию \t) и разделитель самих строк (\n). Однако опять-таки это не всегда может помочь.
В избранное! =) Пока не надо, но уверен, что понадобится.
Насколько я помню, он предназначен для парсинга HTML с незакрытыми тэгами и прочим говном. Поэтому медленный. И использовать его для XML никто в здравом уме не будет.
Ну и не факт, что он является обёрткой над кодом на Си, как lxml. Отсюда тоже могут быть потери производительности (скорее всего так и есть).
а не эффективнее ль будет tidy-фицировать исходный html в xhtml и потом работать как с xml?
То есть парсить в два прохода? Не думаю, что получится эффективнее.
Если вы о том, чтобы исходный HTML tidy-фицировать заранее, то это не всегда возможно (например, если парсим чужой сайт). Надеюсь, понятно о чём я, не люблю допоздна сидеть, в голове всё путаться начинает.
Если вы о том, чтобы исходный HTML tidy-фицировать заранее, то это не всегда возможно (например, если парсим чужой сайт). Надеюсь, понятно о чём я, не люблю допоздна сидеть, в голове всё путаться начинает.
обнаружился еще один неприятный баг — со времен Python 2.4 функция toprettyxml() <…> зачем-то добавляет к каждой строчке символ перевода каретки.
Это не баг, она потому и называется pretty, что выводит отформатированный по-человечески xml. Однако ее можно заставить не делать индентацию и не вставлять символ строки:
app_xml.toprettyxml(indent='', newl='')
.Тогда главный вопрос — почему этого не сделали по умолчанию? Это играет роль только тогда, когда вы собираетесь читать потом xml какими-нибудь нестандартными средствами, например, регэкспами. А так — и вы нормально прочитаете, и любой парсер нормально распознает.
Все pretty-функции в питоне по умолчанию выводят читабельные строки. В вашем случае, лучше было использовать
app_xml.toxml()
, который бы выдал простую строку. Думаю, здесь надо просто запомнить, что pretty — это всегда для людей. Даже такой модуль есть pprint
— от pretty print.В питоне все функции, имеющие
Почти всегда существуют неpretty-функции. В вашем случае это
pretty
в названии, предназначены для людей. Это что-то вроде общественного договора. Существует даже специальный модуль pprint
(от pretty print), который позволяет по-человечески форматировать и выводить стандартные объекты питона.Почти всегда существуют неpretty-функции. В вашем случае это
app_xml.toxml()
, которая выдаст просто обычную строку.Эмм… а никто не задумывался, что тем самым функция ИЗМЕНЯЕТ содержимое xml node. Все-таки добавление в тело ноды доп. символов перевода каретки и символов табуляции\пробела — это некорректно.
Теги форматировать можно как угодно, но содержимое — нельзя. Потому как с точки зрения любого парсера вот эти 2 ноды:
Мама мыла раму
и
Мама мыла раму
разные, причем сильно. Т.е. ни хранить такой результат ни передавать для дальнейшей обрабтки нельзя -только показать человеку. И машине плевать что человек не видит whitespace символы и перевод каретки, она проводит анализ по своим правилам, «не-человеческим».
И правильно делают парсеры которые на это ругаются.
Я не читал документации по prettyprint, но если доки писались вменяемыми людьми — там должна быть оговорка крупными буквами — недопустимо применять результаты работы функции для какой-либо машинной обработки, только для вывода информации, потому что информация искажена.
Такое поведение (дописывание текста XML ноды), в моем понимании равносильно тому, что в строки базы данных при каждом селекте некая хрень дописывала бы теги форматирования html, мотивируя это тем, что человек то все равно их не увидит…
Теги форматировать можно как угодно, но содержимое — нельзя. Потому как с точки зрения любого парсера вот эти 2 ноды:
Мама мыла раму
и
Мама мыла раму
разные, причем сильно. Т.е. ни хранить такой результат ни передавать для дальнейшей обрабтки нельзя -только показать человеку. И машине плевать что человек не видит whitespace символы и перевод каретки, она проводит анализ по своим правилам, «не-человеческим».
И правильно делают парсеры которые на это ругаются.
Я не читал документации по prettyprint, но если доки писались вменяемыми людьми — там должна быть оговорка крупными буквами — недопустимо применять результаты работы функции для какой-либо машинной обработки, только для вывода информации, потому что информация искажена.
Такое поведение (дописывание текста XML ноды), в моем понимании равносильно тому, что в строки базы данных при каждом селекте некая хрень дописывала бы теги форматирования html, мотивируя это тем, что человек то все равно их не увидит…
Хотелось бы увидеть сравнение скорости парсинга xml с помощью различных библиотек.
Есть немного по этому поводу на самом сайте lxml: codespeak.net/lxml/dev/performance.html
И вот тут еще немного: www.onlamp.com/pub/wlg/6291?page=last&x-order=date
Преимущество ElementTree — подхода очевидно
И вот тут еще немного: www.onlamp.com/pub/wlg/6291?page=last&x-order=date
Преимущество ElementTree — подхода очевидно
Преимущество ElementTree — подхода очевидно.
Не соглашусь. В первой ссылке сравнивают ElementTree с lxml и данные там представлены количеством милисекунд на каждый проход, т.е. чем меньше, тем лучше. lxml в разы быстрее (~10) при сериализации и примерно в два раза медленее при парсинге, чем cElementTree. Без си-оптимизаций ElementTree вообще не стоит принимать во внимание. Во второй ссылке сравнивают cElementTree и sax. Sax медленне в ~5 раз.
В целом:
Если есть возможность установить libxml2, тогда лучше использовать lxml.
Если нет, стоит обратиться к cElementTree.
Sax можно использовать тогда, когда данных мало; еще он, по-моему, несколько удобнее в обращении.
Я про то, что lxml использует тот же подход, просто через сишные библиотеки :) А сам алгоритм получается заметно быстрее dom'а
Sax, в отличие от dom-подходов, не формирует никакой модели документа, это потоковый событийный парсер.
sax нужен, когда данных много. много-много-много, сотни мегабайт — dom умирает в таких случаях.
lxml является не чистым python-модулем, а интерфейсом к C-библиотекам libxml2 и libxslt. Поэтому он очень быстр, что особенно заметно на больших объемах данных.
Вот из-за всех таких заморочек предпочитаю пользоваться атрибутами, а текстовыми нодами. Хотя в данном случае приходится работать с тем, что есть.
> зачем-то добавляет к каждой строчке символ перевода каретки
Не существует pretty-стандарта xml, так что прямой вины описанного парсера тут нет.
В любом случае, используя pretty вы рискуете накосячить с итоговым xml.
> зачем-то добавляет к каждой строчке символ перевода каретки
Не существует pretty-стандарта xml, так что прямой вины описанного парсера тут нет.
В любом случае, используя pretty вы рискуете накосячить с итоговым xml.
Да, с текстовыми нодами та ещё беда. Иногда манипуляция с ними вообще нелогична. Например, вот случай:
<a>текст1<b/>текст2</a>
Пусть элемент <a> хранится в объекте под именем a, а элемент <a> — в b. Тогда текст1 попадёт в атрибут a.text, а текст2 — в b.tail.
<a>текст1<b/>текст2</a>
Пусть элемент <a> хранится в объекте под именем a, а элемент <a> — в b. Тогда текст1 попадёт в атрибут a.text, а текст2 — в b.tail.
Опечатался.
элемент <b> — в b
элемент <b> — в b
Так, насколько я понимаю, тут вы вообще стандарт нарушаете.
Правилами XML допустима вложенность типа 1<b />2, но никак не some<b />text.
А невалидный xml обрабатывается черте как.
Правилами XML допустима вложенность типа 1<b />2, но никак не some<b />text.
А невалидный xml обрабатывается черте как.
Парсер — лох.
<a><b>111</b><b /></a>
И, соответственно
<a>some<b />text</a>
<a><b>111</b><b /></a>
И, соответственно
<a>some<b />text</a>
Почему это невалидный? Возьмите хоть XHTML для примера: Привет
!

Действительно, парсер лох.
<p>Привет <img src=«smile.gif» />! </p>
<p>Привет <img src=«smile.gif» />! </p>
Это допускается, т.к. в текст (с точки зрения libxml и xml в целом) — это та же нода, только текстовая. В libxml чистом было бы p.childNodes() == Node[b: TextNode[Привет ], Node[img], TextNode[! ]]. Соответственно «хвост» — это следующий текстовый атрибут после текущего в lxml. Не вижу способа сделать это иным образом, посему lxml молодец и в этом случае.
А вообще с точки зрения xhtml/xml «внутренне» (для браузера) ваш пример аналогичен этому:
Вот только парсить его один фиг сложнее чем через text/tail.
А вообще с точки зрения xhtml/xml «внутренне» (для браузера) ваш пример аналогичен этому:
<p><span>Привет </span><img src="ass.bmp" /><span>!</span></p>
Вот только парсить его один фиг сложнее чем через text/tail.
Ещё во всех питоновских библиотеках для XML, которые я встречал (lxml тоже) не очень приятно работать с XML namespaces.
Если входной XML весь лежит в каком-то безымянном пространстве имён (к примеру, обычный XHTML), то во всех селекторах в коде придётся указывать URI этого пространства имён. Иными словами, плохо, что нет возможности задать дефолтный URI.
Когда-то при генерации XHTML я препопочёл использовать хак и просто задать атрибут xmlns :-)
html = etree.Element('html')
# HACK. Use this because lxml library lacks functions to set default
# XML namespace without inserting namespace URI's into each XML element
# name. For example:
#
# * element.findall('{%s}something' % namespace)
#
# * element.xpath('prefix:something', prefixMap)
#
# Also it seems imposible to use element names that does not have prefix,
# but have namespace (i.e., non-default anonymous namespace) in xpath().
# The xpath() method complains when prefixMap has None key and does not
# consider prefixMap[''] when it is specified… We require anonymous
# namespace in order not to get too verbose output
#
html.set('xmlns', 'http://www.w3.org/1999/xhtml')
head = etree.SubElement(html, 'head')
Если входной XML весь лежит в каком-то безымянном пространстве имён (к примеру, обычный XHTML), то во всех селекторах в коде придётся указывать URI этого пространства имён. Иными словами, плохо, что нет возможности задать дефолтный URI.
Когда-то при генерации XHTML я препопочёл использовать хак и просто задать атрибут xmlns :-)
html = etree.Element('html')
# HACK. Use this because lxml library lacks functions to set default
# XML namespace without inserting namespace URI's into each XML element
# name. For example:
#
# * element.findall('{%s}something' % namespace)
#
# * element.xpath('prefix:something', prefixMap)
#
# Also it seems imposible to use element names that does not have prefix,
# but have namespace (i.e., non-default anonymous namespace) in xpath().
# The xpath() method complains when prefixMap has None key and does not
# consider prefixMap[''] when it is specified… We require anonymous
# namespace in order not to get too verbose output
#
html.set('xmlns', 'http://www.w3.org/1999/xhtml')
head = etree.SubElement(html, 'head')
Спасибо за новость — уже больше года использую эту либу для парсинга xml :)
Если серьезно, то либа довольно приятная, легко разбирать пропарсенное. Есть только одна серьезная проблема — память подтекает.
Если серьезно, то либа довольно приятная, легко разбирать пропарсенное. Есть только одна серьезная проблема — память подтекает.
lxml — обвязка над libxml2\libxslt, так что ничего странного в его скорости нет. Ещё не упомянут 4Suite, но поскольку он целиком написан на питоне, то работает на порядок медленее.
В lxml нельзя достучаться до чистого sax-интерфейса, даже при iterparse приходится вставать на голову и применять такие трюки, например, для экономии памяти — www.ibm.com/developerworks/xml/library/x-hiperfparse/
Но у lxml есть очень большое преимущество — активная разработка и обратная связь. Штефан (Stefan Behnel) всегда оперативно реагирует на просьбы о помощи и на feature requests. В общем, мы используем именно lxml и довольны настолько, насколько можно быть довольными при работе с xml.
В lxml нельзя достучаться до чистого sax-интерфейса, даже при iterparse приходится вставать на голову и применять такие трюки, например, для экономии памяти — www.ibm.com/developerworks/xml/library/x-hiperfparse/
Но у lxml есть очень большое преимущество — активная разработка и обратная связь. Штефан (Stefan Behnel) всегда оперативно реагирует на просьбы о помощи и на feature requests. В общем, мы используем именно lxml и довольны настолько, насколько можно быть довольными при работе с xml.
А как прописать доктайп с помощью lxml?
Или просто потом открыть файл для записи и добавить туда строку с доктайпом?
Или просто потом открыть файл для записи и добавить туда строку с доктайпом?
Так у toprettyxml() в minidom есть параметр newl="\n". Можно заменить его чем хочется. Хотя с elementree/lxml работать всё одно поприятнее.
Sign up to leave a comment.
Как я учился работать с XML