SoSimple
SoSimple

Reputation: 701

Get node by attribute value

I'm trying to get a node by its attribute value. The XML was generated by someone else and looks like this:

<destination atlas_id = "val">
  <history>
    <history>
      <history>
        <![CDATA[content]]>
      </history>
      <history>
        <![CDATA[content]]>
      </history>
      <history>
        <![CDATA[content]]>
      </history>
    </history>
  </history>
</destination>

<destination atlas_id = "val2">
  <history>
    <history>
      <history>
        <![CDATA[content]]>
      </history>
      <history>
        <![CDATA[content]]>
      </history>
      <history>
        <![CDATA[content]]>
      </history>
    </history>
  </history>
</destination>

<destination atlas_id = "val3">
  <history>
    <history>
      <history>
        <![CDATA[content]]>
      </history>
      <history>
        <![CDATA[content]]>
      </history>
      <history>
        <![CDATA[content]]>
      </history>
    </history>
  </history>
</destination>

My code has the variables dest_file and id which are set earlier to reference the correct file and value respectively. I tested them in IRB and their values are correct:

node = dest_file.xpath("//destination[@atlas_id = #{id}]").first
doc.text node.xpath("//history/history/history").text unless node.nil?

I want to fetch the content/text of the third nested <history>, the one that contains CDATA belonging to the the <destination> node with the relevant atlas_id value.

Even when id = val2, I'm getting the content of <history> belonging to <destination atlas_id = "val1">. I was referencing "How to search by attribute value" when I wrote the code to find nodes by attribute value.

Why am I getting the content for the wrong history node? After testing in IRB

node = dest_file.xpath("//destination[@atlas_id = #{id}]").first

seems to be returning the correct node but the following line gets the wrong content. The problem might be small or silly but I can't spot it.

Upvotes: 2

Views: 271

Answers (1)

matt
matt

Reputation: 79733

In your second XPath expression, //history/history/history, since it starts with / it will search from the root of the document, and since you use // you will get all nodes that match from anywhere in the document.

What you probably want to do is select only those nodes under the context node, which is the destination node you have already selected. You can use . at the start of the expression for this:

.//history/history/history

Upvotes: 2

Related Questions