【问题标题】:lxml xpath() function does not work with correct XPath querylxml xpath() 函数不适用于正确的 XPath 查询
【发布时间】:2021-05-27 09:35:36
【问题描述】:

我正在尝试使用 lxml 库评估一些 XPath 查询,但是,由于某种原因,它似乎不起作用。这是代码

if __name__ == '__main__':
    xml = r'''<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<unit xmlns="http://www.srcML.org/srcML/src" revision="0.9.5" language="Java" filename="File.java"><package>package <name><name>com</name><operator>.</operator><name>samples</name><operator>.</operator><name>e978092668</name></name>;</package>
<class><annotation>@<name>Path</name></annotation>
<specifier>public</specifier> class <name>Correct</name> <block>{
    <decl_stmt><decl><annotation>@<name>Inject</name></annotation>
    <specifier>private</specifier> <type><name>JsonWebToken</name></type> <name>field</name></decl>;</decl_stmt>
}</block></class>
</unit>'''.encode("UTF-8")

    xpath = '''unit/class[((descendant-or-self::decl_stmt/decl[(type[name[text()='JsonWebToken']] and annotation[name[text()='Inject']])]) and (annotation[name[text()='Path']]))]'''
    tree = etree.fromstring(xml)
    a = tree.xpath(xpath)
    print(len(a)) # returns 0 (matches)

我在freeformatter.com 上使用完全相同的 XML 字符串尝试了完全相同的 xpath 查询,它可以工作并显示匹配。我不知道我自己的代码有什么问题,因为大部分情况下我是按照网站上的官方教程进行的。

编辑 1:

尝试使用命名空间。

    xpath = '''src:unit/src:class[((descendant-or-self::src:decl_stmt/src:decl[(src:type[src:name[text()='JsonWebToken']] and src:annotation[src:name[text()='Inject']])]) and (src:annotation[src:name[text()='Path']]))]'''
    tree = etree.fromstring(xml)
    a = tree.xpath(xpath, namespaces={
        "src": "http://www.srcML.org/srcML/src"
    })
    print(len(a)) # returns 0 (matches)

谢谢!

【问题讨论】:

  • 我测试了你的 xpath。它错过了要使用的命名空间。看到这个答案:stackoverflow.com/a/32127488/3710053
  • 您的预期输出究竟是什么?
  • @SiebeJongebloed 添加了命名空间,还是不行。
  • @JackFleeting 如果print len(a) 返回0,则表示没有匹配。预期输出为正值。
  • 更新您的代码,您可以在其中展示您如何使用命名空间,以便我们为您提供帮助。

标签: python xpath lxml


【解决方案1】:

问题是当你这样做时:

tree = etree.fromstring(xml)

tree 具有上下文src:unit,因此您的xpath 正在src:unit 中寻找一个孩子src:unit。 (如果你是print(tree.tag),你会看到{http://www.srcML.org/srcML/src}unit。)

尝试在 src:class... 启动 xpath。

xpath = '''src:class[((descendant-or-self::src:decl_stmt/src:decl[(src:type[src:name[text()='JsonWebToken']] and src:annotation[src:name[text()='Inject']])]) and (src:annotation[src:name[text()='Path']]))]'''

【讨论】:

  • 谢谢!是的,它适用于您的建议。现在,我想知道是否有办法让 xpath 保持原样,但将树上下文更改为更高的级别,以便 src:unit 也可以工作。通过查看 XML,我发现 unit 无论如何都是最顶层的节点。但我只是好奇是否有可能为此创建一个伪根。不确定这是否有意义。
  • @MansurGulami - 这是有道理的。您可以尝试tree = etree.ElementTree(etree.fromstring(xml))tree = etree.parse(io.BytesIO(xml)),但在这两种情况下,我都必须通过在开头添加/ (/src:unit...) 来使xpath 成为绝对路径。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-27
相关资源
最近更新 更多