首页 > 解决方案 > ElementTree 是否会生成自己的 nsmap 而 lxml.etree 不会?

问题描述

该线程解释了nsmapin 的性质lxml.etree。鉴于以下 XML 和解析代码,我尝试ElementTree.dump查看etree.dump。来自 ET 的显示显示了各种命名空间ns1ns2等等。这是否意味着 ET 实际上生成了内部命名空间?如果是这样,我们是否可以或如何使用它,例如,搜索我们知道其名称但不知道其 URI 的元素?

my_xml.xml

<?xml version="1.0" encoding="UTF-8"?>
<data>
  <country name="Liechtenstein" xmlns="aaa:bbb:ccc:liechtenstein:eee">
    <rank updated="yes">2</rank>
    <holidays>
      <christmas>Yes</christmas>
    </holidays>
    <year>2008</year>
    <gdppc>141100</gdppc>
    <neighbor name="Austria" direction="E"/>
    <neighbor name="Switzerland" direction="W"/>
  </country>
  <country name="Singapore" xmlns="aaa:bbb:ccc:singapore:eee">
    <continent>Asia</continent>
    <holidays>
      <christmas>Yes</christmas>
    </holidays>
    <rank updated="yes">5</rank>
    <year>2011</year>
    <gdppc>59900</gdppc>
    <neighbor name="Malaysia" direction="N"/>
  </country>
  <country name="Panama" xmlns="aaa:bbb:ccc:panama:eee">
    <rank updated="yes">69</rank>
    <year>2011</year>
    <gdppc>13600</gdppc>
    <neighbor name="Costa Rica" direction="W"/>
    <neighbor name="Colombia" direction="E"/>
  </country>
</data>

parsing.py

import lxml.etree as etree

tree = etree.parse('my_xml.xml')
root = tree.getroot()

ET.dump

<ns0:data xmlns:ns0="aaa:bbb:ccc:ddd:eee" xmlns:ns1="aaa:bbb:ccc:liechtenstein:eee" xmlns:ns2="aaa:bbb:ccc:singapore:eee" xmlns:ns3="aaa:bbb:ccc:panama:eee">
  <ns1:country name="Liechtenstein">
    <ns1:rank updated="yes">2</ns1:rank>
    <ns1:year>2008</ns1:year>
    <ns1:gdppc>141100</ns1:gdppc>
    <ns1:neighbor name="Austria" direction="E" />
    <ns1:neighbor name="Switzerland" direction="W" />
  </ns1:country>
  <ns2:country name="Singapore">
    <ns2:continent>Asia</ns2:continent>
    <ns2:holidays>
      <ns2:christmas>Yes</ns2:christmas>
    </ns2:holidays>
    <ns2:rank updated="yes">5</ns2:rank>
    <ns2:year>2011</ns2:year>
    <ns2:gdppc>59900</ns2:gdppc>
    <ns2:neighbor name="Malaysia" direction="N" />
  </ns2:country>
  <ns3:country name="Panama">
    <ns3:rank updated="yes">69</ns3:rank>
    <ns3:year>2011</ns3:year>
    <ns3:gdppc>13600</ns3:gdppc>
    <ns3:neighbor name="Costa Rica" direction="W" />
    <ns3:neighbor name="Colombia" direction="E" />
  </ns3:country>
</ns0:data>

etree.dump

<data xmlns="aaa:bbb:ccc:ddd:eee">
  <country xmlns="aaa:bbb:ccc:liechtenstein:eee" name="Liechtenstein">
    <rank updated="yes">2</rank>
    <year>2008</year>
    <gdppc>141100</gdppc>
    <neighbor name="Austria" direction="E"/>
    <neighbor name="Switzerland" direction="W"/>
  </country>
  <country xmlns="aaa:bbb:ccc:singapore:eee" name="Singapore">
    <continent>Asia</continent>
    <holidays>
      <christmas>Yes</christmas>
    </holidays>
    <rank updated="yes">5</rank>
    <year>2011</year>
    <gdppc>59900</gdppc>
    <neighbor name="Malaysia" direction="N"/>
  </country>
  <country xmlns="aaa:bbb:ccc:panama:eee" name="Panama">
    <rank updated="yes">69</rank>
    <year>2011</year>
    <gdppc>13600</gdppc>
    <neighbor name="Costa Rica" direction="W"/>
    <neighbor name="Colombia" direction="E"/>
  </country>
</data>

标签: pythonxmllxmlelementtree

解决方案


ElementTree (ET) 和 lxml 在处理命名空间的方式上有所不同

ET 通常不保留输入文档中定义的命名空间前缀,也不存储命名空间是否为默认命名空间。ET 还将所有命名空间声明移动到最外层元素。

lxml 通常保留前缀和默认命名空间。

例如,如果您的输入文档是:

<root xmlns:myprefix="https://www.myuri.com">

或者如果输入具有默认命名空间:

<root xmlns="https://www.myuri.com">

然后 lxml 将保留有关此文档的所有内容,而 ET 可以将其转换为

<root xmlns:ns0="https://www.myuri.com">

ET 的修改不会改变文档的语义,但如果您想防止这种情况发生,我认为在解析 XML 文件之前注册所有命名空间是唯一的解决方案。

ET 命名空间映射不是更好或更有用

这是否意味着 ET 实际上会生成内部命名空间?如果是这样,我们是否可以或如何使用它,例如,搜索我们知道其名称但不知道其 URI 的元素?

不,我不认为 ET 命名空间映射比从 lxml 获得的映射更有用(或更少)。在这两种情况下,基本上定义了相同的命名空间并使用了相同的映射。

正如我之前提到的,知道元素的名称而不知道其名称空间 URI 是不常见的。如果元素的命名空间 URI 是不可预测的并且是先验未知的,这是一个原因

  • 更改您的 XML 格式(如果您自己负责)
  • 抱怨此类文件并坚持更改(如果其他人负责)

在任何情况下,在您展示的 XML 文档中,命名空间肯定不会以预期的方式使用。不需要每个country元素都驻留在自己的命名空间中。


推荐阅读