В настоящее время я сериализую некоторые большие XML-файлы в Python с помощью lxml Я хочу использовать инкрементный писатель для этого. Мой формат XML в значительной степени опирается на пространства имен и атрибуты. Когда я запускаю следующий код
from io import BytesIO
from lxml import etree
sink = BytesIO()
nsmap = {
'test': 'http://test.org',
'foo': 'http://foo.org',
'bar': 'http://bar.org',
}
with etree.xmlfile(sink) as xf:
with xf.element("test:testElement", nsmap=nsmap):
name = etree.QName(nsmap["foo"], "fooElement")
elem = etree.Element(name)
xf.write(elem)
print(sink.getvalue().decode('utf-8'))
тогда я получаю следующий вывод:
<test:testElement xmlns:bar="http://bar.org"
xmlns:foo="http://foo.org"
xmlns:test="http://test.org">
<ns0:fooElement xmlns:ns0="http://foo.org"/>
</test:testElement>
Как видите, пространство имен для foo
повторяется, а не мой префикс:
<ns0:fooElement xmlns:ns0="http://foo.org"/>
Как мне сделать так, чтобы lxml только добавил пространство имен в корень, и потом дети использовали правильный префикс оттуда? Я думаю, что мне нужно использовать etree.Element
, так как мне нужно добавить некоторые атрибуты для узла.
Что не сработало:
1) Использование register_namespace
for prefix, uri in nsmap.items():
etree.register_namespace(prefix, uri)
Это все еще повторяется, но делает префикс правильным. Мне это не очень нравится, потому что оно меняет вещи во всем мире.
2) Указание nsmap
в элементе:
elem = etree.Element(name, nsmap=nsmap)
выходы
<foo:fooElement xmlns:bar="http://bar.org"
xmlns:foo="http://foo.org"
xmlns:test="http://test.org"/>
для fooElement
.
Я также просмотрел документацию и исходный код lxml, но это Cython, поэтому его очень трудно читать и искать. Диспетчер контекста xf.element
не возвращает элемент. например
with xf.element('foo:fooElement') as e:
print(e)
отпечатков None
.