none
XSL Counter

    Question

  • Hi,

    I have a scenario where I have a XML like -

    <AllEmp>
    <EMPTable>
    <Table>
    <EID>1</EID>
    <EmpID>1</EmpID>
    <EmpName>Name1</EmpName>
    <EmpDesig>Desig1<EmpDesig>
    </Table>

    <Table>
    <EID>2</EID>
    <EmpID>2</EmpID>
    <EmpName>Name2</EmpName>
    <EmpDesig>Desig2<EmpDesig>
    </Table>

    <Table>
    <EID>3</EID>
    <EmpID>3</EmpID>
    <EmpName>Name3</EmpName>
    <EmpDesig>Desig3<EmpDesig>
    </Table>

    </EMPTable>

    <EMPDetails>
    <Table>
    <EID>1</EID>
    <Dept>Dept1<Dept>
    </Table>
    <Table>
    <EID>2</EID>
    <Dept>Dept2<Dept>
    </Table>
    <Table>
    <EID>3</EID>
    <Dept>Dept3<Dept>
    </Table>
    </EMPDetails>
    <AllEmp>

    I loop through this and generate a different set of XML considering the unique EID that is there, this process is working fine.

    I get this like-

    <xsl:for-each select="AllEmp/EMPTable/Table">
    <xsl:variable name="EMPKeyId">
        <xsl:value-of select="EID"/>
    </xsl:variable>

     <xsl:variable name="EmpDept">
            <xsl:value-of select="//AllEmp/EMPTable/Table[EID = $EMPKeyId]Dept"/>
          </xsl:variable>
    </xsl:for-each>

    within the for-each loop I have a If condition to process only if the EMPKeyId is not null, this is working fine as well.

    All I want is the count whenever it enters the if condition, I tried this with position(), but say when the EMPKeyId is null and I will not be entering the If condition I get a wrong Position number, is there a way to achieve this? Could you please advise. Thanks.


    Rpaul

    Tuesday, February 05, 2013 12:24 PM

Answers

  • Well I asked you to provide an XML input sample and the corresponding output sample you want to create with XSLT. So far you have posted an input sample and some XSLT code that does not do what you want, together with a procedural description (loop, counter) of what you want to implement.

    The input sample is not even well-formed XML and the XSLT code contains references to parameters or variables that are not declared.

    So with that it is very difficult to tell what you want.

    Assuming we correct the input sample to the well-formed markup

    <AllEmp>
    <EMPTable>
    <Table>
    <EID>1</EID>
    <EmpID>1</EmpID>
    <EmpName>Name1</EmpName>
    <EmpDesig>Desig1</EmpDesig>
    </Table>
    
    <Table>
    <EID>2</EID>
    <EmpID>2</EmpID>
    <EmpName>Name2</EmpName>
    <EmpDesig>Desig2</EmpDesig>
    </Table>
    
    <Table>
    <EID>3</EID>
    <EmpID>3</EmpID>
    <EmpName>Name3</EmpName>
    <EmpDesig>Desig3</EmpDesig>
    </Table>
    
    </EMPTable>
    
    <EMPDetails>
    <Table>
    <EID>1</EID>
    <Dept>Dept1</Dept>
    </Table>
    <Table>
    <EID>2</EID>
    <Dept>Dept2</Dept>
    </Table>
    <Table>
    <EID>3</EID>
    <Dept>Dept3</Dept>
    </Table>
    </EMPDetails>
    </AllEmp>

    and we use code like the following where the condition is simply put in a predicate instead of into an xsl:if the position should do what you seem to want to achieve:

    <xsl:stylesheet
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      version="1.0">
    
    <xsl:output indent="yes"/>
    
    <xsl:param name="EMPKName" select="'1,3'"/>
    <xsl:variable name="id-list" 
      select="concat(',', $EMPKName, ',')"/>
    
    <xsl:key name="dept"
             match="EMPDetails/Table"
             use="EID"/>
    
    <xsl:template match="/">
      <root>
        <xsl:apply-templates select="AllEmp/EMPTable/Table
          [EID != '' and contains($id-list, concat(',', EID, ','))]"/>
      </root>
    </xsl:template>
    
    <xsl:template match="Table">
      <xsl:copy>
         <GetPos><xsl:value-of select="position()"/></GetPos>
         <xsl:copy-of select="key('dept', EID)/Dept"/>
      </xsl:copy>
    </xsl:template>
    
    </xsl:stylesheet>

    The result of running that stylesheet against the input sample is

    <root>
      <Table>
        <GetPos>1</GetPos>
        <Dept>Dept1</Dept>
      </Table>
      <Table>
        <GetPos>2</GetPos>
        <Dept>Dept3</Dept>
      </Table>
    </root>


    MVP Data Platform Development My blog

    • Marked as answer by RPaul18 Wednesday, February 13, 2013 5:31 AM
    Tuesday, February 12, 2013 11:06 AM
  • It sounds as if you want to process and output nodes twice, the right approach with XSLT to do that is to introduce a mode for templates:

    <xsl:stylesheet
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      version="1.0">
    
    <xsl:output indent="yes"/>
    
    <xsl:param name="EMPKName" select="'1,3'"/>
    <xsl:variable name="id-list" 
      select="concat(',', $EMPKName, ',')"/>
    
    <xsl:key name="dept"
             match="EMPDetails/Table"
             use="EID"/>
    
    <xsl:template match="/">
      <root>
        <xsl:apply-templates select="AllEmp/EMPTable/Table
          [EID != '' and contains($id-list, concat(',', EID, ','))]"/>
        <xsl:apply-templates select="AllEmp/EMPTable/Table
          [EID != '' and contains($id-list, concat(',', EID, ','))]"
          mode="name-mode"/>
      </root>
    </xsl:template>
    
    <xsl:template match="Table">
      <xsl:copy>
         <GetPos><xsl:value-of select="position()"/></GetPos>
         <xsl:copy-of select="key('dept', EID)/Dept"/>
      </xsl:copy>
    </xsl:template>
    
    <xsl:template match="Table" mode="name-mode">
      <xsl:copy>
         <GetPos><xsl:value-of select="position()"/></GetPos>
         <xsl:copy-of select="EmpName"/>
      </xsl:copy>
    </xsl:template>
    
    </xsl:stylesheet>

    Note however that that way I get the output

    <root>
      <Table>
        <GetPos>1</GetPos>
        <Dept>Dept1</Dept>
      </Table>
      <Table>
        <GetPos>2</GetPos>
        <Dept>Dept3</Dept>
      </Table>
      <Table>
        <GetPos>1</GetPos>
        <EmpName>Name1</EmpName>
      </Table>
      <Table>
        <GetPos>2</GetPos>
        <EmpName>Name3</EmpName>
      </Table>
    </root>
    

    if you really want

      <Table>
        <GetPos>2</GetPos>
        <EmpName>Name2</EmpName>
      </Table>

    as in your sample then you first need to explain which data you want to process and output as in that case I am not sure how the second part of the output relates to the first one and the input parameter.


    MVP (XML, Data Platform Development) 2005/04 - 2013/03 My blog

    • Marked as answer by RPaul18 Thursday, April 04, 2013 9:32 AM
    Wednesday, April 03, 2013 12:43 PM

All replies

  • Consider to post the result you want to create for the XML input sample you have already posted, then we can help with an XSLT approach to produce that result.

    Currently you are describing your problem in procedural terms like loop and condition while XSLT is declarative, so it is hard to understand what you want to achieve.


    MVP Data Platform Development My blog

    Tuesday, February 05, 2013 1:36 PM
  • Hi Martin

    Thanks for replying, I have created the scenario I am looking for in the below code:

    <xsl:variable name="id-list" select="concat(',', $EMPKName, ',')"/>

    <xsl:for-each select="AllEmp/EMPTable/Table">
    <xsl:variable name="EMPKeyId">
        <xsl:value-of select="EID"/>
    </xsl:variable>

    <xsl:if test="($EMPKeyId != '') and (contains($id-list, concat(',', $PartnerKeyId, ',')))"/>
    <GetPos><xsl:value-of select="position()"/></GetPos>
     <xsl:variable name="EmpDept">
            <xsl:value-of select="//AllEmp/EMPTable/Table[EID = $EMPKeyId]Dept"/>
          </xsl:variable>
    </xsl:if>
    </xsl:for-each>

     Say for example in the XML I had attached, id-list will contain all the EID I want to process, now I pass only 1 & 3 EID to the id-list, when I process this then I should get the position for GetPos as 1 & 2, I expect only the values from the 2 tables to be present in the output, whereas with the code  I get 1 & 3 as GetPos. Sorry I could not give the exact code and I have replicated the scenario in the code mentioned here. Thanks.


    Rpaul

    Wednesday, February 06, 2013 10:15 AM
  • Hi Martin,

    Could you please let me know if there are any other details required? Thanks.


    Rpaul

    Thursday, February 07, 2013 1:48 PM
  • Hi Martin,

    I am waiting for your suggestions on this, could you please let me know your thoughts on this. Thanks.


    Rpaul

    Tuesday, February 12, 2013 5:40 AM
  • Well I asked you to provide an XML input sample and the corresponding output sample you want to create with XSLT. So far you have posted an input sample and some XSLT code that does not do what you want, together with a procedural description (loop, counter) of what you want to implement.

    The input sample is not even well-formed XML and the XSLT code contains references to parameters or variables that are not declared.

    So with that it is very difficult to tell what you want.

    Assuming we correct the input sample to the well-formed markup

    <AllEmp>
    <EMPTable>
    <Table>
    <EID>1</EID>
    <EmpID>1</EmpID>
    <EmpName>Name1</EmpName>
    <EmpDesig>Desig1</EmpDesig>
    </Table>
    
    <Table>
    <EID>2</EID>
    <EmpID>2</EmpID>
    <EmpName>Name2</EmpName>
    <EmpDesig>Desig2</EmpDesig>
    </Table>
    
    <Table>
    <EID>3</EID>
    <EmpID>3</EmpID>
    <EmpName>Name3</EmpName>
    <EmpDesig>Desig3</EmpDesig>
    </Table>
    
    </EMPTable>
    
    <EMPDetails>
    <Table>
    <EID>1</EID>
    <Dept>Dept1</Dept>
    </Table>
    <Table>
    <EID>2</EID>
    <Dept>Dept2</Dept>
    </Table>
    <Table>
    <EID>3</EID>
    <Dept>Dept3</Dept>
    </Table>
    </EMPDetails>
    </AllEmp>

    and we use code like the following where the condition is simply put in a predicate instead of into an xsl:if the position should do what you seem to want to achieve:

    <xsl:stylesheet
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      version="1.0">
    
    <xsl:output indent="yes"/>
    
    <xsl:param name="EMPKName" select="'1,3'"/>
    <xsl:variable name="id-list" 
      select="concat(',', $EMPKName, ',')"/>
    
    <xsl:key name="dept"
             match="EMPDetails/Table"
             use="EID"/>
    
    <xsl:template match="/">
      <root>
        <xsl:apply-templates select="AllEmp/EMPTable/Table
          [EID != '' and contains($id-list, concat(',', EID, ','))]"/>
      </root>
    </xsl:template>
    
    <xsl:template match="Table">
      <xsl:copy>
         <GetPos><xsl:value-of select="position()"/></GetPos>
         <xsl:copy-of select="key('dept', EID)/Dept"/>
      </xsl:copy>
    </xsl:template>
    
    </xsl:stylesheet>

    The result of running that stylesheet against the input sample is

    <root>
      <Table>
        <GetPos>1</GetPos>
        <Dept>Dept1</Dept>
      </Table>
      <Table>
        <GetPos>2</GetPos>
        <Dept>Dept3</Dept>
      </Table>
    </root>


    MVP Data Platform Development My blog

    • Marked as answer by RPaul18 Wednesday, February 13, 2013 5:31 AM
    Tuesday, February 12, 2013 11:06 AM
  • Hi Martin,

    Thanks for replying and sorry that I could not post the exact code as it was too long and too complex to explain; I understood the approach you have taken, I will try out the same with the approach I had taken and will let you know if I come across any issues. Thanks for all the help.


    Rpaul

    Wednesday, February 13, 2013 5:31 AM
  • Hi Martin,

    The above suggestion of yours worked in most of the cases; but now I have a scenario where I need to group the output, conisdering the sample XML and the XSL above, I need to get the output like - I have added a comment to distinguish the second part output; basically when I apply the XSL you have mentioned I get the first part correctly, but after I loop through all the Tables and generate the first set of output, I need to loop the same XML and get the second set of elements; like what I have shown below; not sure what I can modify in the XSL to get this, please help.

    <root>
      <Table>
        <GetPos>1</GetPos>
        <Dept>Dept1</Dept>
      </Table>
      <Table>
        <GetPos>2</GetPos>
        <Dept>Dept3</Dept>
      </Table>
    <!-- Part 2 -->
    <Table>
        <GetPos>1</GetPos>
        <EmpName>Name1</EmpName>
      </Table>
      <Table>
        <GetPos>2</GetPos>
        <EmpName>Name2</EmpName>
      </Table>
    </root>


    Rpaul

    Tuesday, April 02, 2013 9:33 AM
  • It sounds as if you want to process and output nodes twice, the right approach with XSLT to do that is to introduce a mode for templates:

    <xsl:stylesheet
      xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
      version="1.0">
    
    <xsl:output indent="yes"/>
    
    <xsl:param name="EMPKName" select="'1,3'"/>
    <xsl:variable name="id-list" 
      select="concat(',', $EMPKName, ',')"/>
    
    <xsl:key name="dept"
             match="EMPDetails/Table"
             use="EID"/>
    
    <xsl:template match="/">
      <root>
        <xsl:apply-templates select="AllEmp/EMPTable/Table
          [EID != '' and contains($id-list, concat(',', EID, ','))]"/>
        <xsl:apply-templates select="AllEmp/EMPTable/Table
          [EID != '' and contains($id-list, concat(',', EID, ','))]"
          mode="name-mode"/>
      </root>
    </xsl:template>
    
    <xsl:template match="Table">
      <xsl:copy>
         <GetPos><xsl:value-of select="position()"/></GetPos>
         <xsl:copy-of select="key('dept', EID)/Dept"/>
      </xsl:copy>
    </xsl:template>
    
    <xsl:template match="Table" mode="name-mode">
      <xsl:copy>
         <GetPos><xsl:value-of select="position()"/></GetPos>
         <xsl:copy-of select="EmpName"/>
      </xsl:copy>
    </xsl:template>
    
    </xsl:stylesheet>

    Note however that that way I get the output

    <root>
      <Table>
        <GetPos>1</GetPos>
        <Dept>Dept1</Dept>
      </Table>
      <Table>
        <GetPos>2</GetPos>
        <Dept>Dept3</Dept>
      </Table>
      <Table>
        <GetPos>1</GetPos>
        <EmpName>Name1</EmpName>
      </Table>
      <Table>
        <GetPos>2</GetPos>
        <EmpName>Name3</EmpName>
      </Table>
    </root>
    

    if you really want

      <Table>
        <GetPos>2</GetPos>
        <EmpName>Name2</EmpName>
      </Table>

    as in your sample then you first need to explain which data you want to process and output as in that case I am not sure how the second part of the output relates to the first one and the input parameter.


    MVP (XML, Data Platform Development) 2005/04 - 2013/03 My blog

    • Marked as answer by RPaul18 Thursday, April 04, 2013 9:32 AM
    Wednesday, April 03, 2013 12:43 PM
  • Hi Martin,

    Thanks very much for the reply, this was what I was looking for. Thanks again.


    Rpaul

    Thursday, April 04, 2013 9:31 AM