获取父节点where child = x

时间:2015-02-26 16:43:05

标签: ruby arrays nokogiri

当我找到匹配的孩子时,我想从XML源返回一个“父”节点。

如果我搜索'ddd':

@doc.xpath('//item[contains(., "ddd")]')

我想返回'第2节'

我找不到关于Nokogiri'where'类型代码的文档。 这甚至可能吗?

<entry>
  <match>
    <field>Section 1</field>
    <child>
      <item>aaa</item>
      <item>bbb</item>
      <item>ccc</item>
     </child>
  </match>
  <match>
    <field>Section 2</field>
    <child>
      <item>ddd</item>
      <item>eee</item>
      <item>fff</item>
     </child>
  </match>
  <match>
    <field>Section 3</field>
    <child>
      <item>hhh</item>
      <item>iii</item>
      <item>jjj</item>
     </child>
  </match>
</entry>

这是一种更准确的XML格式。 我需要在节点树上上下移动以获得第2节。 这可能吗?

<entry>
  <match>
    <field>
      <foo>Section 1</foo>
    </field>
    <child>
      <item>aaa</item>
      <item>bbb</item>
      <item>ccc</item>
     </child>
  </match>
  <match>
    <field>
      <foo>Section 2</foo>
    </field>
    <child>
      <item>ddd</item>
      <item>eee</item>
      <item>fff</item>
     </child>
  </match>
  <match>
    <field>
      <foo>Section 3</foo>
    </field>
    <child>
      <item>hhh</item>
      <item>iii</item>
      <item>jjj</item>
     </child>
  </match>
</entry>

3 个答案:

答案 0 :(得分:1)

有一种名为#previous_element的方法:

# #xpath gives all the matched nodes as a collection.
@doc.xpath('//child[./item[contains(., "ddd")]]').map do |child|
  child.previous_element.text
end
# #at_xpath gives first matched node
@doc.at_xpath('//child[./item[contains(., "ddd")]]').previous_element.text
# => Section 2
根据您提供的XML,

Section 2不是,它是<child>节点的 sibling 节点。

尝试并测试:

require 'nokogiri'

@doc = Nokogiri::XML.parse <<-XML
<entry>
  <match>
    <field>Section 1</field>
    <child>
      <item>aaa</item>
      <item>bbb</item>
      <item>ccc</item>
     </child>
  </match>
  <match>
    <field>Section 2</field>
    <child>
      <item>ddd</item>
      <item>eee</item>
      <item>fff</item>
     </child>
  </match>
  <match>
    <field>Section 3</field>
    <child>
      <item>hhh</item>
      <item>iii</item>
      <item>jjj</item>
     </child>
  </match>
</entry>
XML

@doc.at_xpath('//child[./item[contains(., "ddd")]]').previous_element.text # => "Section 2"

答案 1 :(得分:1)

您可以在XPath中执行此操作:

@doc.xpath("/entry/match[child/item[contains(., 'ddd')]]/field/foo")

这是使用你的第二个样本。它首先找到match包含child/item包含item后代的ddd个元素,然后查找foo元素的match个元素。

答案 2 :(得分:0)

您可以使用“..”语法(类似于目录文件夹)轻松遍历树。

所以这应该有效:

@doc.xpath('//item[contains(., "ddd")]/..')

or

@doc.xpath('//item[contains(., "ddd")]/../field')