Search code examples
loopsindexingnumberspositionxslt-1.0

Repeat position within a loop in xslt


I have two nested loops. The first loop is picking up distinct value and comparing in second loop. In second loop i am giving position() and it is coming sequential as 1,2,3 but i want it to appear as 1,1,1 during first iteration and 2,2,2 in second iteration and 3,3,3 in third iteration and so on.

XML:

<root>
    <Items>
        <Item>
          <ItemCode>12345</ItemCode>
          <ItemColor>Red</ItemColor>
          <Weight>1Kg</Weight>
        </Item>


        <Item>
          <ItemCode>19087</ItemCode>
          <ItemColor>Blue</ItemColor>
          <Weight>1Kg</Weight>
        </Item>
  
    </Items>

<Items>
       
        <Item>
          <ItemCode>12345</ItemCode>
          <ItemColor>Yellow</ItemColor>
          <Weight>1Kg</Weight>
        </Item>

        <Item>
          <ItemCode>19087</ItemCode>
          <ItemColor>Green</ItemColor>
          <Weight>1Kg</Weight>
        </Item>
    
    </Items>
</root>

Required Output:

  12345
  1.Red
  1.Yellow
  
  19087
  2.Blue
  2.Green

(Or)
  1.12345
    Red
    Yellow
  
  2.19087
    Blue
    Green

Code:

 <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

<xsl:key name="check" match="Items" use="ItemCode" />

<xsl:template match="root/Items">
     <xsl:for-each select="Item[count(. | key('check', ItemCode)[1]) = 1]">
             <xsl:value-of select="ItemCode"/>
        <xsl:for-each select="key('check', ItemCode)"> 
               
               <xsl:value-of select="position()"/>
               <xsl:value-of select="ItemColor"/>
        </xsl:for-each>
    </xsl:for-each>
</xsl:template>
</xsl:stylesheet>

I am using xslt-1.0 Your help is appreciated. Thank you!


Solution

  • The following stylesheet:

    XSLT 1.0

    <xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="text" encoding="utf-8"/>
    
    <xsl:key name="item-by-code" match="Item" use="ItemCode"/>
    
    <xsl:template match="/root">
        <xsl:for-each select="Items/Item[count(. | key('item-by-code', ItemCode)[1]) = 1]">
            <xsl:value-of select="position()"/>
            <xsl:text>.</xsl:text>
            <xsl:value-of select="ItemCode"/>
            <xsl:for-each select="key('item-by-code', ItemCode)"> 
                <xsl:text>&#10;  </xsl:text>
                <xsl:value-of select="ItemColor"/>
            </xsl:for-each>
            <xsl:text>&#10;&#10;</xsl:text>
        </xsl:for-each>
    </xsl:template>
    
    </xsl:stylesheet>
    

    when applied yo your input example, will return:

    Result

    1.12345
      Red
      Yellow
    
    2.19087
      Blue
      Green
    

    Alternatively, you could do:

    <xsl:stylesheet version="1.0"
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="text" encoding="utf-8"/>
    
    <xsl:key name="item-by-code" match="Item" use="ItemCode"/>
    
    <xsl:template match="/root">
        <xsl:for-each select="Items/Item[count(. | key('item-by-code', ItemCode)[1]) = 1]">
            <xsl:variable name="i" select="position()" />
            <xsl:value-of select="ItemCode"/>
            <xsl:text>&#10;</xsl:text>
            <xsl:for-each select="key('item-by-code', ItemCode)"> 
                <xsl:value-of select="$i"/>
                <xsl:text>.</xsl:text>
                <xsl:value-of select="ItemColor"/>
                <xsl:text>&#10;</xsl:text>
            </xsl:for-each>
            <xsl:text>&#10;</xsl:text>
        </xsl:for-each>
    </xsl:template>
    
    </xsl:stylesheet>
    

    to get:

    12345
    1.Red
    1.Yellow
    
    19087
    2.Blue
    2.Green