如何使用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
元素 name
是 Employee 1
.
为什么 OP 使用上述 XPath 可能会得到 "Invalid expression"?
转录错误。
解决方案:使用复制和粘贴。
单引号外加单引号。
解决方案:使用外双引号:"/sys/lang/employee[name = 'Employee 1']"
弯引号。
解决方案:将‘
和’
替换为单引号'
。
对错误信息的误解。
解决方法:仔细检查错误中提到的行号,或者尽可能去掉周围的代码,看错误是否消失。
如果 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
.
我有一些 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
元素 name
是 Employee 1
.
为什么 OP 使用上述 XPath 可能会得到 "Invalid expression"?
转录错误。
解决方案:使用复制和粘贴。
单引号外加单引号。
解决方案:使用外双引号:
"/sys/lang/employee[name = 'Employee 1']"
弯引号。
解决方案:将
‘
和’
替换为单引号'
。对错误信息的误解。
解决方法:仔细检查错误中提到的行号,或者尽可能去掉周围的代码,看错误是否消失。
如果 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
.