开发者

Select a only first matching node in XPath

I have the following XML:

<parent>
   <pet>
      <data开发者_运维问答>
         <birthday/>
      </data>
   </pet>
   <pet>
      <data>
         <birthday/>
      </data>
   </pet>
</parent> 

And now I want to select the first birthday element via parent//birthday[1] but this returns both birthday elements because bothof them are the first child of their parents.

How can I only select the first birthday element of the entire document no matter where it is located. I've tried parent//birthday[position()=1] but that doesn't work either.


You mean (note the parentheses!)

(/parent/pet/data/birthday)[1]

or, a shorter, but less specific variation:

(/*/*/*/birthday)[1]
(//birthday)[1]

or, more semantic, the "birthday of the first pet":

/parent/pet[1]/data/birthday

or, if not all pets have birthday entries, the "birthday of the first pet that for which a birthday is set":

/parent/pet[data/birthday][1]/data/birthday

If you work from a context node, you can abbreviate the expression by making it relative to that context node.

Explanation:

  • /parent/pet/data/birthday[1] selects all <birthday> nodes that are the first in their respective parents (the <data> nodes), throughout the document
  • (/parent/pet/data/birthday)[1] selects all <birthday> nodes, and of those (that's what the parentheses do, they create an intermediary node-set), it takes the first one


FYI: you can visualize the results of the various Xpath queries with the (free) XPathVisualizer tool. Works on Windows only.

Select a only first matching node in XPath


Ok, I admit this is horrendous and there must be a better way, but it appears to work.

/*/*[descendant::birthday and not(preceding-sibling::*[descendant::birthday])]

I look for all elements at the second level in the tree that have a descendant element called birthday that do not have a preceding sibling element that has a birthday element as a descendant.


<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:template match="/">
        <xsl:variable name="birthdays" select="//birthday"/>
        <xsl:value-of select="$birthdays[1]"/>
    </xsl:template>

</xsl:stylesheet>


try

//birthday[position()=1]

// finds nodes no matter where there are in the hierarchy

you could also do

pet[position()=1]/data/birthday
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜