【问题标题】:python etree with xpath and namespaces with prefix带有 xpath 和带有前缀的命名空间的 python etree
【发布时间】:2015-01-15 12:03:09
【问题描述】:

我找不到信息,如何使用命名空间解析我的 XML:

我有这个 xml:

<par:Request xmlns:par="http://somewhere.net/actual">
  <par:actual>blabla</par:actual>
  <par:documentType>string</par:documentType>
</par:Request>

并试图解析它:

dom = ET.parse(u'C:\\filepath\\1.xml')
rootxml = dom.getroot()
for subtag in rootxml.xpath(u'//par:actual'):
    #do something
    print(subtag)

得到了异常,因为它不知道命名空间前缀。 有没有最好的方法来解决这个问题,计算脚本不会知道它要解析的文件和标签要搜索的文件?

搜索网页和stackoverflow我发现,如果我会在那里添加:

namespace = {u'par': u"http://somewhere.net/actual"}
for subtag in rootxml.xpath(u'//par:actual', namespaces=namespace):
    #do something
    print(subtag)

这行得通。完美的。但我不知道我将解析哪个 XML,并且我的脚本也不知道搜索标记(例如 //par:actual)。所以,我需要想办法从 XML 中提取命名空间。

我找到了很多方法,如何提取命名空间URI,比如:

print(rootxml.tag)
print(rootxml.xpath('namespace-uri(.)'))
print(rootxml.xpath('namespace-uri(/*)'))

但是我应该如何提取前缀来创建 ElementTree 想要的字典呢?我不想在 xml 正文上使用正则表达式怪物来提取前缀,我相信必须存在支持的方式,不是吗?

也许必须存在一些方法让我通过 ETree 命名空间从 XML 中提取为字典(正如 ETree 所希望的那样!)而无需手动操作?

【问题讨论】:

    标签: python xml-namespaces elementtree prefix


    【解决方案1】:

    在 Python 3.8.2 中,我发现这个问题与相同的问题。

    这是我找到的解决方案,将命名空间放在 XPath 查询中。 (在 {} 之间)

    ApplicationArea = BOD_IN_tree.find('.//ApplicationArea', ns)
    if(ApplicationArea is None):
      ApplicationArea = BOD_IN_tree.find('.//{http://www.defaultNamespace.com/2}ApplicationArea', ns)
    

    我搜索没有命名空间的元素,如果没有找到则再次搜索。我无法控制入站文档,有些有命名空间,有些没有。

    我希望这会有所帮助!

    【讨论】:

      【解决方案2】:

      哦,我找到了。

      我们这样做之后:

      dom = ET.parse(u'C:\\filepath\\1.xml')
      rootxml = dom.getroot()
      

      Object rootxml 包含字典 nsmap,其中包含我想要的所有命名空间。

      所以,我找到了最简单的解决方案:

      dom = ET.parse(u'C:\\filepath\\1.xml')
      rootxml = dom.getroot()
      nss = rootxml.nsmap
      for subtag in rootxml.xpath(u'//par:actual', namespaces=nss):
          #do something
          print(subtag)
      

      这行得通。

      UPD: 如果用户理解他使用的 XML 中的“par”是什么意思,那么它就可以工作。例如,在任何其他操作之前将假定的命名空间与现有的命名空间进行比较。

      不过,我还是喜欢 XPath 的许多变体,它可以理解{...}实际,这就是我试图实现的目标。

      【讨论】:

      • 我未能使 .nsmap 与 py3.6 一起使用 `Traceback(最近一次调用最后一次):文件“ElementTree_Xpath_xmlns_namespace.py”,第 61 行,在 nss = root.nsmap AttributeError: 'xml.etree.ElementTree.Element' 对象没有属性 'nsmap' `
      • 它是 python 2.7...如果你能找到 3.6 问题的解决方案,请在此回复。
      【解决方案3】:

      您不能依赖根元素上的命名空间声明:不能保证声明甚至会存在,或者文档将始终具有相同命名空间的相同前缀。 假设您将通过某种方式传递要搜索的标签(因为您说脚本不知道它),您还应该提供一种传递名称空间映射的方法。或使用 James Clark 表示法,如 {http://somewhere.net/actual}actualETXPath 支持此语法,而“普通”xpath 不支持,但如果您不需要完整的 xpath,您也可以使用其他方法,如 .findall()

      如果你根本不关心前缀,你也可以在 xpath 中使用local-name() 函数,例如。 //*[local-name()="actual"](但你不会“真的”确定它是正确的“实际”)

      【讨论】:

      • 是的,我想过。首先,我什至试图诱导用户使用{http://somewhere.net/actual}actual,以确保他了解他使用的“实际”内容。但这也不起作用,并且 etree 不理解 '//{...}actual',抛出异常。但是后来我只是从用户添加了输入命名空间并将其与现有的 xml 命名空间进行比较,所以,这个问题就解决了。
      • ETXPath 类应该可以解决不理解 {} 语法的问题,但是你将无法与.xpath() 方法一起使用它,你应该像 XPath 类一样使用它(当使用编译的 xpath 表达式)。示例:path = etree.ETXPath('//{http://somewhere.net/actual}actual') 然后使用它results = path(rootxml)
      • 确实如此。我会用你的建议:-)
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-06-05
      • 2021-07-27
      • 2011-04-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-09
      相关资源
      最近更新 更多