如何使用XPath通过匹配文本找到父节点

How to find the parent node by matching text using XPath

我有一些 XML:

<sys>
  <lang>
    <employee>
      <name>Employee 1</name>
      <code>4fdaa994-7015-4ec1-b365-de4ee0279966</code>
    </employee>
    <employee>
      <name>Employee 2</name>
      <code>1d960bdc-0853-49af-bb83-18cf92493897</code>
    </employee>
</lang>
</syz>

如何搜索并获取 name ="Employee 1" 所在的员工节点?

我试过了,但没用:

 obj.xpath("//sys/lang[/employee/name = 'Employee 1']")

这个 XPath

/sys/lang/employee[name = 'Employee 1']

将 select employee 元素 nameEmployee 1.


为什么 OP 使用上述 XPath 可能会得到 "Invalid expression"?

  1. 转录错误。

    解决方案:使用复制和粘贴。

  2. 单引号外加单引号。

    解决方案:使用外双引号:"/sys/lang/employee[name = 'Employee 1']"

  3. 弯引号。

    解决方案:将替换为单引号'

  4. 对错误信息的误解。

    解决方法:仔细检查错误中提到的行号,或者尽可能去掉周围的代码,看错误是否消失。

如果 none 以上可能性适用,post MCVE(Minimal, Complete, and Verifiable Example,包括提供的 XPath 调用代码 - - MCVE 中的 complete)会产生无效表达式错误,有人可能会立即发现问题。

出于可读性原因,我非常喜欢使用 CSS 而不是 XPath。 Nokogiri 实现了一些 jQuery 的扩展,以便更容易地使用 CSS 处理我们通常使用 XPath 的事情。

我会这样做:

require 'nokogiri'

doc = Nokogiri::XML(<<EOT)
<sys>
  <lang>
    <employee>
      <name>Employee 1</name>
      <code>4fdaa994-7015-4ec1-b365-de4ee0279966</code>
    </employee>
    <employee>
      <name>Employee 2</name>
      <code>1d960bdc-0853-49af-bb83-18cf92493897</code>
    </employee>
</lang>
</syz>
EOT

emp1 = doc.at('employee name:contains("Employee 1")') # => #<Nokogiri::XML::Element:0x3ffed05285b4 name="name" children=[#<Nokogiri::XML::Text:0x3ffed05283d4 "Employee 1">]>
emp1.to_xml # => "<name>Employee 1</name>"
emp1.parent.to_xml # => "<employee>\n      <name>Employee 1</name>\n      <code>4fdaa994-7015-4ec1-b365-de4ee0279966</code>\n    </employee>"

另请注意,在选择器中为节点定义完整路径不是好的做法。如果 HTML 或 XML 更改选择器将破坏的结构。相反,找到有用的地标并从一个跳到下一个。这样你的选择器更有可能在标记的变化中存活下来。我只关心找到合适的 <employee>...<name> 组合,而不是 <sys><lang>.

下嵌入的两个标签

有时获取所需信息的另一种方法是使用 search 并查看特定索引:

doc.search('employee').first.to_xml # => "<employee>\n      <name>Employee 1</name>\n      <code>4fdaa994-7015-4ec1-b365-de4ee0279966</code>\n    </employee>"

或:

doc.at('employee').to_xml           # => "<employee>\n      <name>Employee 1</name>\n      <code>4fdaa994-7015-4ec1-b365-de4ee0279966</code>\n    </employee>"

at('some selector') 等同于 search('some selector').first.