Warning: file_get_contents(/data/phpspider/zhask/data//catemap/0/xml/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Python lmxl增量XML序列化重复名称空间_Python_Xml_Xml Serialization_Lxml_Xml Namespaces - Fatal编程技术网

Python lmxl增量XML序列化重复名称空间

Python lmxl增量XML序列化重复名称空间,python,xml,xml-serialization,lxml,xml-namespaces,Python,Xml,Xml Serialization,Lxml,Xml Namespaces,我目前正在用lxml在Python中序列化一些较大的XML文件。我想使用增量编写器来实现这一点。我的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

我目前正在用lxml在Python中序列化一些较大的XML文件。我想使用增量编写器来实现这一点。我的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>
如何使lxml只在根目录中添加名称空间,子目录使用正确的前缀?我想我需要使用
etree.Element
,因为我需要向节点添加一些属性

什么不起作用:

1) 使用
register\u名称空间

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"/>

打印
None

您需要创建一个子元素:

_nsmap={
    'test': 'http://test.org',
    'foo': 'http://foo.org',
    'bar': 'http://bar.org',
}

root = etree.Element(
    "{http://bar.org}test",
    creator='SO',
    nsmap=_nsmap
)

doc = etree.ElementTree(root)
name = etree.QName(_nsmap["foo"], "fooElement")
elem = etree.SubElement(root, name)

doc.write('/tmp/foo.xml', xml_declaration=True, encoding='utf-8', pretty_print=True)
print (open('/tmp/foo.xml').read())
返回:

<?xml version='1.0' encoding='UTF-8'?>
<bar:test xmlns:bar="http://bar.org" xmlns:foo="http://foo.org" xmlns:test="http://test.org" creator="SO">
  <foo:fooElement/>
</bar:test>

有可能生产出与您想要的产品相近的产品:

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):
        with xf.element("foo:fooElement"):
            pass

print(sink.getvalue().decode('utf-8'))
这将生成XML:

<test:testElement xmlns:bar="http://bar.org" xmlns:foo="http://foo.org" xmlns:test="http://test.org"><foo:fooElement></foo:fooElement></test:testElement>

额外的名称空间声明消失了,但是您得到的不是立即结束元素,而是
foo:fooElement
的一对开始和结束标记


我查看了
lxml.etree.xmlfile
的源代码,没有看到那里的代码维护着这样一种状态,即它将检查以了解已经声明了哪些名称空间,并避免不必要地再次声明它们。有可能我错过了什么,但我真的不认为我错过了。增量XML序列化程序的要点是在不使用内存的情况下运行。当内存不是问题时,您只需创建一个表示XML文档的对象树,并将其序列化即可。您需要付出巨大的内存成本,因为在序列化树之前,整个树都必须在内存中可用。通过使用增量序列化程序,可以避免内存问题。为了最大限度地节省内存,序列化程序必须最小化它维护的状态量。如果它在序列化中生成一个元素时要考虑该元素的父元素,那么它必须“记住”父元素是什么,并保持状态。在最坏的情况下,它将保持如此多的状态,以至于与仅仅创建一个XML对象树并进行序列化相比没有任何好处。

我如何将
子元素
etree.xmlfile
一起使用?我没有根,使用
xf
会给出
TypeError:参数“\u parent”的类型不正确(应为lxml.etree.\u元素,获得lxml.etree.\u IncrementalFileWriter)
这个问题有很多好处,但OP似乎忘记了它。也许这个答案并不能解决问题,但值得投票表决。
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):
        with xf.element("foo:fooElement"):
            pass

print(sink.getvalue().decode('utf-8'))
<test:testElement xmlns:bar="http://bar.org" xmlns:foo="http://foo.org" xmlns:test="http://test.org"><foo:fooElement></foo:fooElement></test:testElement>