Using xslt get node value at X position
Asked Answered
B

4

9

How can I get using xslt, node value at X position, without using foreach

<items>
<item1>x</item1>
<item2>x</item2>
<item3>x</item3>
</items>

This is explained in programming sense:

<xsl:value-of select="Items/Item[2]"/>

==================================================

Just to little expand question, in the following xml:

<items>
    <about>xyz</about>
    <item1>
       <title>t1</title>
       <body>b1</body>
    </item1>
    <item2>
       <title>t2</title>
       <body>b2</body>
    </item2>
    <item3>
       <title>3</title>
       <body>3</body>
   </item3>
</items>

How can I select second's item title.

Bergama answered 17/9, 2011 at 14:47 Comment(1)
Good question, +1. Do note that most answers contain expressions that, depending on the XML document, can potentially select a title that isn'r a child of an itemXYZ parent.Leslee
S
18

Answer to expanded question. You can use the positional value if you select a node-set of the wanted elements:

<xsl:value-of select="(items//title)[2]"/>

or:

<xsl:value-of select="(items/*/title)[2]"/>

Note the usage of the parenthesis required to return wanted node-set before selecting by position.


You can use what you called "in programming sense". However you need * due to the unknown name of the children elements:

<xsl:value-of select="items/*[2]"/>

Note that nodes-sets in XSLT are not zero-based. In the way above you are selecting the second item, not the third one.

You really need position() when you want compare the current position with a number as in:

<xsl:value-of select="items/*[position()>2]"/>

to select all item with position grater than 2. Other case where position() is indespensible is when position value is a variable of type string:

<xsl:variable name="pos" select="'2'"/>
<xsl:value-of select="items/*[position()=$pos]"/>
Serrato answered 17/9, 2011 at 15:6 Comment(2)
I've answered the expanded question. Hope it helps.Serrato
This helped me a lot with a similar problem. Great, simple solution, thanks.Ascribe
L
4

Just to little expand question, in the following xml:

<items> 
    <about>xyz</about> 
    <item1> 
       <title>t1</title> 
       <body>b1</body> 
    </item1> 
    <item2> 
       <title>t2</title> 
       <body>b2</body> 
    </item2> 
    <item3> 
       <title>3</title> 
       <body>3</body> 
   </item3> 
</items>

How can I select second's item title.

Use:

/*/*[starts-with(name(), 'item')][2]/title

This selects: all title elements that are children of the second of all children-elements of the top element, whose names are starting with the string "item".

Do note that expressions such as:

(items/*/title)[2]

or

(items//title)[2]

are not correct in general, because if in the XML document there are other elements such as (say) "chapter" that have title children, the above expressions could select an chapter/title element -- but the task here is to select the second title in the document whose parent could only be an itemXYZ element.

Leslee answered 17/9, 2011 at 16:58 Comment(4)
+1 for more general solution. However, the expressions in my answer are correct in the provided sample; they could obviously work wrong if the input document changes. This can happen to your provided expression also.Serrato
@empo: Thanks, and yes, while my solution is more general and robust than yours, there is always chance that even more radical changes could make any solution unsuitable. So, I usually care for variations that are quite possible, but not extreme.Leslee
I agree, but to say that the expressions I've used in my answer are not correct it is not correct :). You can say that those expressions are less robust and may fail if the input document changes.Serrato
@empo: This is essentially what I am saying, if you read well. I agree with your argument, so I just edited and replaced "are not correct" with "are not correct in general" :)Leslee
H
2

You can use position()

<xsl:value-of select="/items/*[position()=2]/text()"/>
Harkins answered 17/9, 2011 at 14:58 Comment(0)
A
2

You could do it with

<xsl:value-of select="items/child[position()=2]"/>
Arvy answered 17/9, 2011 at 14:59 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.