Python: анализ XML-документа при сохранении сущностей

Я хотел спросить, какие известные существующие библиотеки Python 2.x существуют для синтаксического анализа XML-документа со встроенным DTD без автоматического расширения сущностей. (Файл для любопытных: JMdict.)

Кажется, в lxml есть некоторая возможность не анализировать объекты, но в последний раз, когда я пытался, объекты просто были преобразованы в пустые. Я только что погуглил и нашел pxdom в качестве еще одной альтернативы, которую я могу попробовать, но, поскольку это чистый Python, он кажется намного медленнее, чем мне хотелось бы.

Что-нибудь еще там?


person Vultaire    schedule 17.08.2010    source источник
comment
Я думал, что xml.parsers.expat.XML_PARAM_ENTITY_PARSING_NEVER в expat сделает это, но это не имело никакого эффекта. Чем он хорош, интересно.   -  person melissa_boiko    schedule 20.02.2013


Ответы (4)


lxml упоминается в вопросе, и, насколько я могу судить, он делает то, что вы хотите. Тестовый код:

from lxml import etree

XML = """
<!DOCTYPE root [
<!ENTITY abc "123">
]>
<root>
&abc;
</root>"""

parser = etree.XMLParser(resolve_entities=False)

root = etree.fromstring(XML, parser)
print "Entity not resolved:"
print etree.tostring(root)
print

print "Entity resolved:"
root = etree.fromstring(XML)
print etree.tostring(root)

Выход:

Entity not resolved:
<root>
&abc;
</root>

Entity resolved:
<root>
123
</root>
person mzjn    schedule 20.02.2013
comment
Я бы очень хотел, чтобы это работало с expat, чтобы избежать другой зависимости и переписать мой текущий код. Но да, это решает проблему. - person melissa_boiko; 21.02.2013

Кажется, что вариант использования довольно ненормальный; нерасширение объектов, кажется, идет вразрез с тем, как парсеры обычно должны работать в соответствии со спецификацией XML.

Итак, я думаю, что проще всего просто забить это, возможно. Я вручную извлек теги с помощью re.finditer и составил словарь сопоставлений. Отсюда нужно просто сканировать проанализированный вывод и делать правильные вещи для моего приложения. Я думаю, достаточно хорошо для моего варианта использования.

person Vultaire    schedule 19.08.2010

Во-первых, BeautifulStoneSoup из BeautifulSoup по умолчанию не расширяет объекты.

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

person Jukka Matilainen    schedule 19.08.2010

У меня была аналогичная проблема, которую нужно было решить. Мне нужно было прочитать XML-файл TEI, содержащий такие объекты, как

&some_exotic_char;

которые были объявлены в отдельном файле DTD. Задача заключалась в том, чтобы добавить какой-либо атрибут в определенные теги и записать измененный файл, сохранив при этом специальные сущности и не испортив XML-макет.

BeautifulSoup работал хорошо, пока я не захотел снова записать XML-файл:

with open('outfile.xml','w') as outfile:
    outfile.write(soup.prettify())

Тогда он не оставил бы сущности «как есть», а вместо этого расширил бы их до символов utf8, чего я не хотел. Кроме того, он испортил исходную разметку XML независимо от prettify-метода (без него еще хуже).

В конце концов я сдался и нашел хорошее решение с использованием Perl и XML::LibXML. Методом

$parser->expand_entities(0);

объекты не будут расширены. А запись XML обратно в файл сохранит исходный макет нетронутым.

use XML::LibXML;
my $parser = new XML::LibXML;
$parser->validation(0);
$parser->load_ext_dtd(1);
$parser->expand_entities(0);
my $doc  = $parser->parse_file('infile.xml');

... # do whatever you need to do

open my $out, '>', 'outfile.xml';
binmode $out;
print $out $doc->toString();
close $out;

Perl XML::LibXML спас меня.

person Swen Vermeul    schedule 13.06.2018