Search code examples
xsltxpathpositionexsltnode-set

Sorted exsl:node-set. Return node by it position


I have a set of nodes

<menuList>
  <mode name="aasdf"/>
  <mode name="vfssdd"/>
  <mode name="aswer"/>
  <mode name="ddffe"/>
  <mode name="ffrthjhj"/>
  <mode name="dfdf"/>
  <mode name="vbdg"/>
  <mode name="wewer"/>
  <mode name="mkiiu"/>
  <mode name="yhtyh"/>
  and so on...
</menuList>

I have it sorted now this way

 <xsl:variable name="rtf">
    <xsl:for-each select="//menuList/mode">
       <xsl:sort data-type="text" order="ascending" select="@name"/>
          <xsl:value-of select="@name"/>
    </xsl:for-each>
 </xsl:variable>

Now I need to get an arbitrary element in the sorted array to the number of its position. I'm using the code:

<xsl:value-of select="exsl:node-set($rtf)[position() = 3]"/>

and I get a response error. How should I be doing it?


Solution

  • There are at least two errors in the provided code:

    1. <xsl:value-of select="@name"/>

    When more than one adjacent text node exist, they are combined into one. The result is that the RTF has just one (long) single text node, and there isn't a 3rd node.

    2.<xsl:value-of select="exsl:node-set($rtf)[position() = 3]"/>

    This asks for the third node contained in exsl:node-set($rtf), however exsl:node-set($rtf) is the document node of the temporary tree produced by the exsl:node-set() extension function -- this is only one node. Therefore the above XPath expression doesn't select anything at all.

    One correct solution is the following:

    <xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
     xmlns:msxsl="urn:schemas-microsoft-com:xslt"
     >
    
     <xsl:template match="/">
        <xsl:variable name="rtf">
            <xsl:for-each select="//menuList/mode">
               <xsl:sort data-type="text" order="ascending" select="@name"/>
                  <xsl:copy-of select="."/>
            </xsl:for-each>
         </xsl:variable>
        <xsl:value-of select="msxsl:node-set($rtf)/*[position()=3]/@name"/>
     </xsl:template>
    </xsl:stylesheet>