lxml.etree 元素在副本上删除命名空间

问题描述 投票:0回答:1

我正在使用 lxml.etree 库将 XML 文件拼接在一起,并且命名空间在写入时被删除。

Input.xml

<?xml version="1.0" encoding="UTF-8"?>
<haul>
    <uuid>abc</uuid>
    <port xmlns="hello"
          xmlns:a="hello">
        <v>
            <a:value>0</a:value>
            <type>int</type>
        </v>
    </port>
</haul>

我尝试了这段代码:

test.py

tree = load_tree_from_file('Input.xml')
port = tree.find('{hello}port')
v = port.find('{hello}v')
v2=copy.deepcopy(v)
port.append(v2)

d = os.path.dirname(__file__)
tree.write(os.path.join(d, 'Output.xml'))

我得到了这个输出:

Output.xml

<haul>
    <uuid>abc</uuid>
    <port xmlns="hello" xmlns:a="hello">
        <v>
            <a:value>0</a:value>
            <type>int</type>
        </v>
        <v>
            <value>0</value>
            <type>int</type>
        </v>
    </port>
</haul>

我期望并且需要

<value>
元素与第一个元素一样
<a:value>

python xml lxml elementtree
1个回答
0
投票

命名空间不会被删除,因为特定节点的

a
命名空间为
hello
,这也与使用
xmlns="hello"
指定的默认命名空间相同。 这允许省略标签的
a:
前缀,因为
<a:value/>
<value/>
是相同的表示。如果
a
命名空间绑定到其他内容,执行类似的操作将显示您期望的输出类型:

>>> from lxml import etree
>>> ixml = b'''<?xml version="1.0" encoding="UTF-8"?>
... <haul>
...     <uuid>abc</uuid>
...     <port xmlns="hello"
...           xmlns:a="goodbye">
...         <v>
...             <a:value>0</a:value>
...             <type>int</type>
...         </v>
...     </port>
... </haul>'''
>>> tree = etree.fromstring(ixml)
>>> port = tree.find('{hello}port')
>>> v = port.find('{hello}v')
>>> v2 = copy.deepcopy(v)
>>> port.append(v2)
>>> print(etree.tostring(tree).decode())
<haul>
    <uuid>abc</uuid>
    <port xmlns="hello" xmlns:a="goodbye">
        <v>
            <a:value>0</a:value>
            <type>int</type>
        </v>
    <v>
            <a:value>0</a:value>
            <type>int</type>
        </v>
    </port>
</haul>

虽然这个示例自然有两个独立的命名空间,所以它可能不能代表您想要做的事情。在任何情况下,提供的输出

lxml
对于这里的两种情况都是正确的,因为问题中的版本默认命名空间和
a
命名空间是相同的,因此可以安全地省略它,而这个答案中的上述示例有两个单独的命名空间,因此必须包含它们。 有关这些表示如何工作的更多示例可以在此答案中找到

© www.soinside.com 2019 - 2024. All rights reserved.