Paul Hennessey
Paul Hennessey

Reputation: 203

Find xml element using xslt

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

Upvotes: 2

Views: 4320

Answers (2)

nwellnhof
nwellnhof

Reputation: 33618

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>

Upvotes: 3

Daniel Haley
Daniel Haley

Reputation: 52848

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>

Upvotes: 2

Related Questions