【问题标题】:More compact ElementTree or lxml Namespaces更紧凑的 ElementTree 或 lxml 命名空间
【发布时间】:2013-04-12 20:20:19
【问题描述】:

当子元素与父元素位于不同的命名空间时,我试图在 ElementTree 或 lxml 中获得命名空间的紧凑表示。这是基本示例:

from lxml import etree

country = etree.Element("country")

name = etree.SubElement(country, "{urn:test}name")
name.text = "Canada"
population = etree.SubElement(country, "{urn:test}population")
population.text = "34M"
etree.register_namespace('tst', 'urn:test')

print( etree.tostring(country, pretty_print=True) )

我也试过这种方法:

ns = {"test" : "urn:test"}

country = etree.Element("country", nsmap=ns)

name = etree.SubElement(country, "{test}name")
name.text = "Canada"
population = etree.SubElement(country, "{test}population")
population.text = "34M"

print( etree.tostring(country, pretty_print=True) )

在这两种情况下,我都会得到这样的结果:

<country>
    <ns0:name xmlns:ns0="urn:test">Canada</ns0:name>
    <ns1:population xmlns:ns1="urn:test">34M</ns1:population>
</country>

虽然这是正确的,但我希望它不那么冗长 - 这可能会成为大型数据集的真正问题(尤其是因为我使用的 NS 比 'urn:test' 大得多)。

如果我认为“国家”位于“urn:test”命名空间内并可以这样声明(在上面的第一个示例中):

country = etree.Element("{test}country")

然后我得到以下输出:

<ns0:country xmlns:ns0="urn:test">
    <ns0:name>Canada</ns0:name>
    <ns0:population>34M</ns0:population>
</ns0:country>

但我真正想要的是:

<country xmlns:ns0="urn:test">
    <ns0:name>Canada</ns0:name>
    <ns0:population>34M</ns0:population>
<country>

有什么想法吗?

【问题讨论】:

    标签: python xml lxml elementtree


    【解决方案1】:
    1. 元素的全名包含{namespace-url}elementName,而不是{prefix}elementName

      >>> from lxml import etree as ET
      >>> r = ET.Element('root', nsmap={'tst': 'urn:test'})
      >>> ET.SubElement(r, "{urn:test}child")
      <Element {urn:test}child at 0x2592a80>
      >>> ET.tostring(r)
      '<root xmlns:tst="urn:test"><tst:child/></root>'
      
    2. 在您的情况下,如果您更新默认命名空间,则可能会更紧凑。可惜lxml好像不允许空的XML命名空间,但是你说可以把父标签和子元素放在同一个命名空间,这样就可以把默认命名空间设置为子元素的命名空间:

      >>> r = ET.Element('{urn:test}root', nsmap={None: 'urn:test'})
      >>> ET.SubElement(r, "{urn:test}child")
      <Element {urn:test}child at 0x2592b20>
      >>> ET.SubElement(r, "{urn:test}child")
      <Element {urn:test}child at 0x25928f0>
      >>> ET.tostring(r)
      '<root xmlns="urn:test"><child/><child/></root>'
      

    【讨论】:

      【解决方案2】:
      from xml.etree import cElementTree as ET
      ##ET.register_namespace('tst', 'urn:test')
      country = ET.Element("country")
      name = ET.SubElement(country, "{urn:test}name")
      name.text = "Canada"
      population = ET.SubElement(country, "{urn:test}population")
      population.text = "34M"
      print prettify(country)
      

      上面将给出(不注册任何命名空间):

      <?xml version="1.0" ?>
      <country xmlns:ns0="urn:test">
        <ns0:name>Canada</ns0:name>
        <ns0:population>34M</ns0:population>
      </country>
      

      而且,当我删除评论部分时,它会给出::

      <?xml version="1.0" ?>
      <country xmlns:tst="urn:test">
        <tst:name>Canada</tst:name>
        <tst:population>34M</tst:population>
      </country>
      

      注意:prettify 函数是 here

      【讨论】:

        【解决方案3】:

        这段代码:

        from lxml import etree
        
        ns = {"ns0" : "urn:test"}
        country = etree.Element("country", nsmap=ns)
        
        name = etree.SubElement(country, "{urn:test}name")
        name.text = "Canada"
        
        population = etree.SubElement(country, "{urn:test}population")
        population.text = "34M"
        
        print(etree.tostring(country, pretty_print=True))
        

        似乎提供了所需的输出:

        <country xmlns:ns0="urn:test">
          <ns0:name>Canada</ns0:name>
          <ns0:population>34M</ns0:population>
        </country>
        

        但您仍然需要自己维护nsmap

        【讨论】:

          猜你喜欢
          • 2011-06-20
          • 2023-04-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-12-26
          • 2012-05-08
          相关资源
          最近更新 更多