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

时间:2016-10-06 14:06:29

标签: ruby xml xpath nokogiri

我有一些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']")

2 个答案:

答案 0 :(得分:3)

此XPath

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

将选择employeename的<{1}}元素。

为什么OP可能会使用上述XPath获得“无效表达式”?

  1. 转录错误。

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

  2. 单引号附近的单引号。

    解决方案:使用外部双引号:Employee 1

  3. 智能引号。

    解决方案:将"/sys/lang/employee[name = 'Employee 1']"替换为单引号

  4. 错误解释错误消息。

    解决方案:仔细检查错误中提到的任何行号,或尽可能多地删除周围的代码,并查看错误是否消失。

  5. 如果上述任何一种可能性都不适用,请发布MCVE(Minimal, Complete, and Verifiable Example,包括提供的XPath 主叫代码 - 完成 在MCVE中)产生无效的表达错误,有人可能会立即发现问题。

答案 1 :(得分:1)

出于可读性原因,我非常喜欢使用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