【问题标题】:How to select the following specific XML nodes using XPath?如何使用 XPath 选择以下特定的 XML 节点?
【发布时间】:2016-05-25 04:30:34
【问题描述】:

我有一个如下的 XML 文档:

<Objects>
  <object distName="a/b">  </object>
  <object distName="a/b/c1">  </object>
  <object distName="a/b/c4/d/e">  </object>
  <object distName="a/b/c2">  </object>
  <object distName="a/b/c6/d">  </object>
</Objects>

我需要选择路径以 "c" + number 结尾的所有节点。喜欢:“a/b/c1”和“a/b/c2”,但不喜欢“a/b/c6/d” ,也不是“a/b/c4/d/e”。

如果我尝试以下操作:

      `cNodes = xmlDoc.xpath("//object[contains(@path, `a/b/c`)]")`

那么这将包括我不需要的“a/b/c6/d”和“a/b/c4/d/e”。

那么有没有办法在一行或两行代码中完成这项工作。我的意思是我可以用循环之类的东西来做到这一点,我不想这样做。那是因为真正的 XML 文档是数千个节点。

PS:Python 2.7,lxml

【问题讨论】:

  • 不,路径只是一个属性。它与内容无关。
  • @JeffMercado 我将名称从 path 更改为 distName。因为我只是举个例子。它与我拥有的 XML 文档不完全一样。
  • @JeffMercado 对不起,我的错误。我会编辑。
  • 好的,现在说得通了。 :)

标签: python xml python-2.7 xpath lxml


【解决方案1】:

不幸的是,使用 XPath 1.0 表达匹配模式的条件并不是很简单。但是,如果您可以对要查找的内容做出某些假设,则可以制作这样的查询。

//object[starts-with(@distName, 'a/b/c') and substring-after(@distName, 'a/b/c') >= 0]

分解它,我们首先检查distName 属性是否以a/b/c 开头。然后,如果该字符串之后的所有内容都是某个数字。根据您的需要,这可能就足够了。

【讨论】:

    【解决方案2】:

    恐怕这不能使用纯 XPath 1.0 来完成,这是 lxml 支持的 XPath 版本。

    作为替代方案,您可以尝试通过/ 拆分属性,获取最后一个拆分结果,并检查它是否以c 开头,使用列表推导全部在一行中,例如:

    >>> raw = '''<Objects>
    ...   <object distName="a/b">  </object>
    ...   <object distName="a/b/c1">  </object>
    ...   <object distName="a/b/c4/d/e">  </object>
    ...   <object distName="a/b/c2">  </object>
    ...   <object distName="a/b/c6/d">  </object>
    ... </Objects>'''
    ... 
    >>> from lxml import etree
    >>> xmlDoc = etree.fromstring(raw)
    >>> cNodes = xmlDoc.xpath("//object[contains(@path, 'a/b/c')]")
    >>> result = [etree.tostring(n) for n in cNodes if n.attrib["distName"].split('/')[-1].startswith("c")]
    >>> print result
    ['<object distName="a/b/c1">  </object>\n  ', '<object distName="a/b/c2">  </object>\n  ']
    

    【讨论】:

    • 问题是这些 cNode 只是真实 XML 文件中其他节点的父节点。我关心自己选择节点。但看起来除了循环之外别无他法。无论如何,谢谢你的回答:)
    • 不,看起来有解决方案。接受的答案正是我所需要的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多