Derek Hill
Derek Hill

Reputation: 6454

Nokogiri: How does nested xpath access outer loop?

Trying to get my head around Nokogiri and XPath, and hoping you can help explain this behaviour. This code:

data = Nokogiri::XML(%{
  <veg>
    <peas>
      <color>"green"</color>
    </peas>
    <peas>
      <color>"yellow"</color>
    </peas>
  </veg>
})

data.xpath('//peas').each do |p|
  puts p                            
  puts p.xpath('color/text()')        
  puts p.xpath('//color/text()')    # output not as expected 
end

Gives this output:

<peas>
  <color>"green"</color>
</peas>

"green"

"green"
"yellow"

<peas>
  <color>"yellow"</color>
</peas>

"yellow"

"green"
"yellow"

How does puts p.xpath('//color/text()') end up retrieving both green and yellow, while p only contains one or the other?

Upvotes: 0

Views: 491

Answers (1)

JWiley
JWiley

Reputation: 3209

Since it's breaking down the <peas> nodes into p, and iterating through them, it is first displaying the node itself

<peas>
  <color>"green"</color>
</peas>

and

<peas>
  <color>"yellow"</color>
</peas>

and then the <color> node's text of each p as well.

THEN, we get to //color/text(), and '//' says start over at the root, and get all <color> nodes, and the text() associated with them, which is why you get both Green and Yellow colors, even while iterating through each <peas> node separately.

So for another example, if we had iterated to the node veg/peas[color='green'], and then said find //peas, we would get back both <peas> nodes for yellow and green.

color/text() says "start from current node, and grab me the text of the child node <color>" and //color/text() says "give me the text of all <color> nodes in the XML, regardless of current location"

Let me know if I need to clarify anything...

Upvotes: 1

Related Questions