Search code examples
variablesxpathxslt-2.0saxonxslt-3.0

Reference the current node in a document tree, which is stored in a variable


I have a stylesheet in which I loop through a Day-Element. For each day, I need to get a value from another XML-document, which i have inside a parameter, referenced with $ArtStat.

If I use the filter as a fixed value of 2022-10-11, it works fine

<xsl:for-each select="Day">
    <QtyOut><xsl:value-of select="$ArtStat/ECRArtStat/Days/Day[Date='2022-10-11']/QtyOut" /></QtyOut>
</xsl:for-each>

But I need to use the filter as a dynamic value (the content of the current node), and that doesnt work (the result in this case is that this select gives back an empty String ""

<xsl:for-each select="Day">
    <QtyOut><xsl:value-of select="$ArtStat/ECRArtStat/Days/Day[Date=current()]/QtyOut" /></QtyOut>
</xsl:for-each>

I tried it with current() or 'current()', with ., with self:node(), anything didnt work at all I guess there is a simple solution with it, but I can't find it. I could use XSLT 2.0 or 3.0 with Saxon 9

The explanation above is a simplification of my issue. Cause actually what I need is: For each day on my XML document, I need to check the QtyOut-value inside another document and I need to sum them to one value. So something like this:

sum($ArtStat/ECRArtStat/Days/Day[Date=<Nodeset of the days>]/QtyOut)

but this I couldn't solve directly with XSL, so I try to set a variable first, and after sum the content, like this:

<xsl:variable name="QtyOutList">
   <xsl:for-each select="Day">
       <QtyOut><xsl:value-of select="$ArtStat/ECRArtStat/Days/Day[Date=current()]/QtyOut" /></QtyOut>
   </xsl:for-each>
</xsl:variable>
<xsl:value-of select="sum($QtyOutList/QtyOut)" />

This does work if I use a fixed value for the date, but not with current(),....

Source XML (the source doc define for which days we need to get the values):

<Columns>
  <Column type="pastWeek">
    <WeekNo>40</WeekNo>
    <Year>2022</Year>
    <StartDay>2022-10-03</StartDay>
  </Column>
  <Column type="currentWeek">
    <WeekNo>41</WeekNo>
    <Year>2022</Year>
    <StartDay>2022-10-10</StartDay>
    <Day>2022-10-10</Day>
    <Day>2022-10-11</Day>
    <Day>2022-10-12</Day>
    <Day>2022-10-13</Day>
    <Day>2022-10-14</Day>
    <Day>2022-10-15</Day>
  </Column>
</Columns>

Referenced XML as a variable (where I need to get the QtyOut value from):

<ECRArtStat>
  <Days>
    <Day>
      <Date>2022-10-13</Date>
      <QtyIn>0</QtyIn>
      <QtyOut>0</QtyOut>
    </Day>
    <Day>
      <Date>2022-10-12</Date>
      <QtyIn>0</QtyIn>
      <QtyOut>0</QtyOut>
    </Day>
    <Day>
      <Date>2022-10-11</Date>
      <QtyIn>0</QtyIn>
      <QtyOut>5</QtyOut>
     </Day>
     <Day>
       <Date>2022-10-10</Date>
       <QtyIn>0</QtyIn>
       <QtyOut>4</QtyOut>
     </Day>

Solution

  • If I do e.g.

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        exclude-result-prefixes="#all"
        expand-text="yes"
        version="3.0">
      
      <xsl:mode on-no-match="shallow-copy"/>
      
      <xsl:template match="Column[Day]">
        <xsl:comment>Sum {sum($ArtStat/ECRArtStat/Days/Day[Date = current()/Day]/QtyOut)}</xsl:comment>
        <xsl:next-match/>
      </xsl:template>
    
      <xsl:param name="ArtStat">
    <ECRArtStat>
      <Days>
        <Day>
          <Date>2022-10-13</Date>
          <QtyIn>0</QtyIn>
          <QtyOut>0</QtyOut>
        </Day>
        <Day>
          <Date>2022-10-12</Date>
          <QtyIn>0</QtyIn>
          <QtyOut>0</QtyOut>
        </Day>
        <Day>
          <Date>2022-10-11</Date>
          <QtyIn>0</QtyIn>
          <QtyOut>5</QtyOut>
         </Day>
         <Day>
           <Date>2022-10-10</Date>
           <QtyIn>0</QtyIn>
           <QtyOut>4</QtyOut>
         </Day>
      </Days>
    </ECRArtStat>
      </xsl:param>
      
    </xsl:stylesheet>
    

    against an input of e.g.

    <Columns>
      <Column type="pastWeek">
        <WeekNo>40</WeekNo>
        <Year>2022</Year>
        <StartDay>2022-10-03</StartDay>
      </Column>
      <Column type="currentWeek">
        <WeekNo>41</WeekNo>
        <Year>2022</Year>
        <StartDay>2022-10-10</StartDay>
        <Day>2022-10-10</Day>
        <Day>2022-10-11</Day>
        <Day>2022-10-12</Day>
        <Day>2022-10-13</Day>
        <Day>2022-10-14</Day>
        <Day>2022-10-15</Day>
      </Column>
    </Columns>
    

    the result is e.g.

    <?xml version="1.0" encoding="UTF-8"?><Columns>
      <Column type="pastWeek">
        <WeekNo>40</WeekNo>
        <Year>2022</Year>
        <StartDay>2022-10-03</StartDay>
      </Column>
      <!--Sum 9--><Column type="currentWeek">
        <WeekNo>41</WeekNo>
        <Year>2022</Year>
        <StartDay>2022-10-10</StartDay>
        <Day>2022-10-10</Day>
        <Day>2022-10-11</Day>
        <Day>2022-10-12</Day>
        <Day>2022-10-13</Day>
        <Day>2022-10-14</Day>
        <Day>2022-10-15</Day>
      </Column>
    </Columns>
    

    meaning a sum is computed based on the reference values.

    As you pretend to ask questions about XSLT 3 but don't understand the use of text value templates or xsl:next-match, here is an example using xsl:value-of:

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        xmlns:xs="http://www.w3.org/2001/XMLSchema"
        exclude-result-prefixes="#all"
        version="3.0">
      
      <xsl:mode on-no-match="shallow-copy"/>
      
      <xsl:template match="Column[Day]">
        <xsl:copy>
          <xsl:apply-templates select="@* | node()"/>
          <Sum>
            <xsl:value-of select="sum($ArtStat/ECRArtStat/Days/Day[Date = current()/Day]/QtyOut)"/>
          </Sum>
        </xsl:copy>
      </xsl:template>
    
      <xsl:param name="ArtStat">
    <ECRArtStat>
      <Days>
        <Day>
          <Date>2022-10-13</Date>
          <QtyIn>0</QtyIn>
          <QtyOut>0</QtyOut>
        </Day>
        <Day>
          <Date>2022-10-12</Date>
          <QtyIn>0</QtyIn>
          <QtyOut>0</QtyOut>
        </Day>
        <Day>
          <Date>2022-10-11</Date>
          <QtyIn>0</QtyIn>
          <QtyOut>5</QtyOut>
         </Day>
         <Day>
           <Date>2022-10-10</Date>
           <QtyIn>0</QtyIn>
           <QtyOut>4</QtyOut>
         </Day>
      </Days>
    </ECRArtStat>
      </xsl:param>
      
    </xsl:stylesheet>
    

    Output is e.g.

    <Columns>
      <Column type="pastWeek">
        <WeekNo>40</WeekNo>
        <Year>2022</Year>
        <StartDay>2022-10-03</StartDay>
      </Column>
      <Column type="currentWeek">
        <WeekNo>41</WeekNo>
        <Year>2022</Year>
        <StartDay>2022-10-10</StartDay>
        <Day>2022-10-10</Day>
        <Day>2022-10-11</Day>
        <Day>2022-10-12</Day>
        <Day>2022-10-13</Day>
        <Day>2022-10-14</Day>
        <Day>2022-10-15</Day>
      <Sum>9</Sum></Column>
    </Columns>