2

I'm using xslt to convert some xml files. My input data looks like this:

<data>
  <dataItem>
    <value>24014</value>
    <date>Feb 11, 2013</date>
  </dataItem>
  <dataItem>
    <value>0</value>
    <date>Feb 12, 2013</date>
  </dataItem>
  <dataItem>
    <value>0</value>
    <date>Feb 13, 2013</date>
  </dataItem>
  <dataItem>
    <value>24627</value>
    <date>Feb 14, 2013</date>
  </dataItem>
  <dataItem>
    <value>0</value>
    <date>Feb 15, 2013</date>
  </dataItem>
</data>

My output data needs to look like this:

<root>
  <item>
    <text>
      Feb 14, 2013
    </text>
  </item>
</root>

In other words I'm looking for the most recent date element where the value element is not 0. The dataItem elements are guarantee to be in increasing date order (starting at the top of the document).

I've tried to approach this recursively, like this:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output method="xml" indent="yes"/>

  <xsl:template name="findDate">
    <xsl:param name="list"/>
    <xsl:choose>

      <xsl:when test="value = 0">
        <xsl:call-template name="findDate">
          <xsl:with-param name="list" select="$list[position()!=1]"/>
        </xsl:call-template>
      </xsl:when>

      <xsl:otherwise>
        <root>
          <item>
            <text>
              <xsl:value-of select="label"/>
            </text>
          </item>
        </root>
      </xsl:otherwise>

    </xsl:choose>
  </xsl:template>

  <xsl:template match="/">
      <xsl:call-template name="findDate">
        <xsl:with-param name="list" select="//dataItem"/>
      </xsl:call-template>
  </xsl:template>

</xsl:stylesheet>

So far though, it's not working, and all I'm getting out is this:

   <root>
      <item>
        <text>
        </text>
      </item>
    </root>

Can anyone see where I'm going wrong?

Thanks,

Paul

0

2 Answers 2

3

The line <xsl:value-of select="label"/> looks suspicious because there aren't any label elements in your input XML.

But there's no need for a recursive template. Try the following:

<xsl:template match="/">
    <root>
        <xsl:apply-templates select="data/dataItem[value!=0][last()]"/>
    </root>
</xsl:template>

<xsl:template match="dataItem">
    <item>
        <text>
            <xsl:value-of select="date"/>
        </text>
    </item>
</xsl:template>
Sign up to request clarification or add additional context in comments.

3 Comments

No, the parentheses are not needed. Try my example and you'll see that it works.
My mistake, I was confused with a different example.
Thanks nwellnhof, this works perfectly too. I've already accepted Daniel's suggestion, but will mark this as useful.
2

If the dataItem elements are already sorted by date, you should be able to just grab the last dataItme that doesn't have a value of 0. (Look at the xsl:apply-temlates in the /* template for the XPath to do this.)

XML Input

<data>
    <dataItem>
        <value>24014</value>
        <date>Feb 11, 2013</date>
    </dataItem>
    <dataItem>
        <value>0</value>
        <date>Feb 12, 2013</date>
    </dataItem>
    <dataItem>
        <value>0</value>
        <date>Feb 13, 2013</date>
    </dataItem>
    <dataItem>
        <value>24627</value>
        <date>Feb 14, 2013</date>
    </dataItem>
    <dataItem>
        <value>0</value>
        <date>Feb 15, 2013</date>
    </dataItem>
</data>

XSLT 1.0

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output indent="yes"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="@*|node()">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="/*">
        <root>
            <xsl:apply-templates select="(dataItem[not(value=0)])[last()]"/>            
        </root>
    </xsl:template>

    <xsl:template match="dataItem">
        <item>
            <xsl:apply-templates/>
        </item>
    </xsl:template>

    <xsl:template match="date">
        <text><xsl:value-of select="."/></text>
    </xsl:template>

    <xsl:template match="value"/>

</xsl:stylesheet>

XML Output

<root>
   <item>
      <text>Feb 14, 2013</text>
   </item>
</root>

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.