在lxml中更改子元素的默认命名空间

时间:2013-04-09 06:16:23

标签: python lxml xml-namespaces

我想用lxml

生成这个xml
<aroot xmlns="http://a/">
  <broot xmlns="http://b/" xmlns:a="http://a/">
    <child1/>
    <child2/>
    <a:smalltag1/>
    <a:smalltag2/>
  </broot>
</aroot>

但是下面的代码(对于这个输出似乎是正确的),不会生成上面的xml。

from lxml import etree
from lxml.builder import ElementMaker

NS_A = 'http://a/'
NS_B = 'http://b/'

A = ElementMaker(namespace=NS_A, nsmap={None: NS_A, 'b': NS_B})
B = ElementMaker(namespace=NS_B, nsmap={None: NS_B, 'a': NS_A})

elem = A.aroot(
    B.broot(
        B.child1,
        B.child2,
        A.smalltag1,
        A.smalltag2,
    ),
)

print(etree.tostring(elem, pretty_print=True).decode('ascii'))

这会产生:

<aroot xmlns:b="http://b/" xmlns="http://a/">
  <b:broot>
    <b:child1/>
    <b:child2/>
    <smalltag1/>
    <smalltag1/>
  </b:broot>
</aroot>

这是一个有效的xml,但我无法更改subelemnt broot上的默认命名空间。

如果我按以下方式更改A ElementMaker

A = ElementMaker(namespace=NS_A, nsmap={None: NS_A})

输出变为:

<aroot xmlns="http://a/">
  <broot xmlns="http://b/">
    <child1/>
    <child2/>
    <smalltag1/>
    <smalltag2/>
  </broot>
</aroot>

这是一个无效的xml(smalltag1的命名空间现在是b)

如果我按如下方式更改AB

A = ElementMaker(namespace=NS_A, nsmap={None: NS_A})
B = ElementMaker(namespace=NS_B, nsmap={None: NS_B})

输出是:

<aroot xmlns="http://a/">
  <broot xmlns="http://b/">
    <child1/>
    <child2/>
    <smalltag1 xmlns="http://a/"/>
    <smalltag2 xmlns="http://a/"/>
  </broot>
</aroot>

哪个是有效的,但不是理想的输出。

1 个答案:

答案 0 :(得分:3)

使用etree:

from lxml import etree

NS_A = 'http://a/'
NS_B = 'http://b/'

aroot = Element('{%s}aroot' % (NS_A), nsmap={None: NS_A})
broot = etree.SubElement(aroot, '{%s}broot' % (NS_B), nsmap={None: NS_B, 'a': NS_A})
etree.SubElement(broot, '{%s}child1' % (NS_B))
etree.SubElement(broot, '{%s}child2' % (NS_B))
etree.SubElement(broot, '{%s}smalltag1' % (NS_A))
etree.SubElement(broot, '{%s}smalltag2' % (NS_A))

print etree.tostring(aroot, pretty_print=True)

你得到:

<aroot xmlns="http://a/">
  <broot xmlns:a="http://a/" xmlns="http://b/">
    <child1/>
    <child2/>
    <a:smalltag1/>
    <a:smalltag2/>
  </broot>
</aroot>