Link to home
Start Free TrialLog in
Avatar of Natavia Finnie
Natavia FinnieFlag for United States of America

asked on

How do I loop through an XML data and get the node with the latest year and related data using xslt

This is part of the xml data:

I would like to get the latest of the EIVYEAR to get the EIVTOTAL for that year in my .xslt file

-<EIVANNUALCOMP>

<EIVYEAR>2017</EIVYEAR>

<EIVBASE>56487.37</EIVBASE>

<EIVOVERTIME>0</EIVOVERTIME>

<EIVCOMMISSION>0</EIVCOMMISSION>

<EIVBONUS>13131.48</EIVBONUS>

<EIVOTHER>18403.7</EIVOTHER>

<EIVTOTAL>88022.55</EIVTOTAL>

</EIVANNUALCOMP>


-<EIVANNUALCOMP>

<EIVYEAR>2016</EIVYEAR>

<EIVBASE>24400.04</EIVBASE>

<EIVOVERTIME>1805.71</EIVOVERTIME>

<EIVCOMMISSION>510.46</EIVCOMMISSION>

<EIVBONUS>2400.16</EIVBONUS>

<EIVOTHER>20.1</EIVOTHER>

<EIVTOTAL>23171.95</EIVTOTAL>

</EIVANNUALCOMP>

Open in new window

Avatar of Gertone (Geert Bormans)
Gertone (Geert Bormans)
Flag of Belgium image

xsl:sort by EIVYEAR, sort type number, descending
take the first record
set the year in a variable
and sum the nodes from that year

how much XSLT do you already have, which processor, what version?

Do you have a full wellformed XML example (just want to rule out default namespaces uphill)
because... this clumsy approach is only necessary in XSLT1... in XSLT2 you can use max()  
XSLT 2.0

    <xsl:template match="/">
        <xsl:variable name="most-recent-year" select="max(//EIVANNUALCOMP/EIVYEAR)"/>
        <xsl:value-of select="sum(//EIVANNUALCOMP[EIVYEAR = $most-recent-year]/EIVTOTAL)"/>
    </xsl:template>


Open in new window


Or just this if there is only one occurrence of EIVANNUALCOMP per year
    <xsl:template match="/">
        <xsl:variable name="most-recent-year" select="max(//EIVANNUALCOMP/EIVYEAR)"/>
        <xsl:value-of select="//EIVANNUALCOMP[EIVYEAR = $most-recent-year]/EIVTOTAL"/>
    </xsl:template>


Open in new window

ASKER CERTIFIED SOLUTION
Avatar of Gertone (Geert Bormans)
Gertone (Geert Bormans)
Flag of Belgium image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of Natavia Finnie

ASKER

@Gertone

using this version:

<xsl:template match="/">
        <xsl:for-each select="//EIVANNUALCOMP">
            <xsl:sort select="EIVYEAR" order="descending" data-type="number"/>
            <xsl:if test="position() = 1">
                <xsl:value-of select="EIVTOTAL"/>
            </xsl:if>
        </xsl:for-each>
    </xsl:template>

Open in new window


how would I use it in here:

<xsl:call-template name="rowString">
        <xsl:with-param name="label" select="'Salary: '" />
        <xsl:with-param name="val" select="EIVTOTAL"  />
      </xsl:call-template>
@Gertone this one gives me an error saying

'max()' is an unknown XSLT function

 <xsl:template match="/">
        <xsl:variable name="most-recent-year" select="max(//EIVANNUALCOMP/EIVYEAR)"/>
        <xsl:value-of select="//EIVANNUALCOMP[EIVYEAR = $most-recent-year]/EIVTOTAL"/>
    </xsl:template>

Open in new window

Please, read all my comments in detail
Max() is a xslt 2.0 function not supported in xslt 1.0
It seems you are using sn xslt 1.0 processor (my first question, left unanswered)
So you need to go for my xslt 1.0 solution with the sort and the for each
You can put the for each inside the with param “val” (and remove the select attribute then)
@Gertone

Is it possible to get the data and store it in a variable to be used later in the file?
I have included some of the .xml to better understand

-<OFX>


-<SIGNONMSGSRSV1>


-<SONRS>


-<STATUS>

<CODE>0</CODE>

<SEVERITY>INFO</SEVERITY>

</STATUS>

<DTSERVER>20201022165253</DTSERVER>

<LANGUAGE>ENG</LANGUAGE>

</SONRS>

</SIGNONMSGSRSV1>


-<EIVEMPLOYEEMSGSRSV1>


-<EIVIMMIGRATIONVERIFICATIONTRNRS>

<TRNUID>NA</TRNUID>

-<EIVIMMIGRATIONVERIFICATIONRS>

-<EIVANNUALCOMP>

<EIVYEAR>2017</EIVYEAR>

<EIVBASE>56487.37</EIVBASE>

<EIVOVERTIME>0</EIVOVERTIME>

<EIVCOMMISSION>0</EIVCOMMISSION>

<EIVBONUS>13131.48</EIVBONUS>

<EIVOTHER>18403.7</EIVOTHER>

<EIVTOTAL>88022.55</EIVTOTAL>

</EIVANNUALCOMP>

-<EIVANNUALCOMP>

<EIVYEAR>2016</EIVYEAR>

<EIVBASE>24400.04</EIVBASE>

<EIVOVERTIME>1805.71</EIVOVERTIME>

<EIVCOMMISSION>510.46</EIVCOMMISSION>

<EIVBONUS>2400.16</EIVBONUS>

<EIVOTHER>20.1</EIVOTHER>

<EIVTOTAL>23171.95</EIVTOTAL>

</EIVANNUALCOMP>

-<EIVANNUALCOMP>

<EIVYEAR>2015</EIVYEAR>

<EIVBASE>25415.41</EIVBASE>

<EIVOVERTIME>1705.38</EIVOVERTIME>

<EIVCOMMISSION>610.87</EIVCOMMISSION>

<EIVBONUS>2500.59</EIVBONUS>

<EIVOTHER>20.62</EIVOTHER>

<EIVTOTAL>23171.67</EIVTOTAL>

</EIVANNUALCOMP>

-<EIVANNUALCOMP>

<EIVYEAR>2014</EIVYEAR>

<EIVBASE>24400.04</EIVBASE>

<EIVOVERTIME>1805.71</EIVOVERTIME>

<EIVCOMMISSION>510.46</EIVCOMMISSION>

<EIVBONUS>2400.16</EIVBONUS>

<EIVOTHER>20.1</EIVOTHER>

<EIVTOTAL>23171.95</EIVTOTAL>

<EIVYEAR>2010</EIVYEAR>

<EIVBASE>29502</EIVBASE>

<EIVOVERTIME>4300</EIVOVERTIME>

<EIVCOMMISSION>2330</EIVCOMMISSION>

<EIVBONUS>830</EIVBONUS>

<EIVOTHER>163</EIVOTHER>

<EIVTOTAL>37123</EIVTOTAL>

</EIVANNUALCOMP>

<COMPLETENESS>IMMIGRATION</COMPLETENESS>

<SRVRTID>100245494397</SRVRTID>

</EIVIMMIGRATION_V100>

</EIVIMMIGRATIONVERIFICATIONRS>

</EIVIMMIGRATIONVERIFICATIONTRNRS>

</EIVEMPLOYEEMSGSRSV1>

</OFX>

Open in new window


first, if you send XML as an example, make sure you send the source XML, not the tree view from the browser)
(I am not going to bother pulling out all the collapsing dashes)

second, yes you can
  • on line two of my first code sample there is an example to create a variable (you can construct inside the xsl:variable instead of having a select attribute like this
    <xsl:variable name="most-recent-year">
       <xsl:for-each select="//EIVANNUALCOMP">
          ...
    </xsl:variable>

    Open in new window

  • further down I had the exact for each you could use
  • Can you connect the dots yourself?
@Gertone I apologize about the copy/paste. I'm dealing with coronavirus but still trying to work. I will try this!

Much appreciated!!!