Re: [xsl] Thorny select: getting surrounding years

Subject: Re: [xsl] Thorny select: getting surrounding years
From: "G. Ken Holman" <gkholman@xxxxxxxxxxxxxxxxxxxx>
Date: Thu, 21 Oct 2010 17:29:05 -0400
At 2010-10-21 10:12 -1000, Brooks Talley wrote:
I've been wresting with this, and my brain is melting. I need to get a
list of the surrounding years for an item -- zero to two years before,
the item itself, zero to two years after. There may be gaps in the
sequence, in which case I still need two items before and after (if
available).

Sample xml:
...
Desired output (or similar, the select is the hard part):

I couldn't do it in a single select assuming XSLT 1.0 ... if you are using XSLT 2.0 then you can review the below and munge the tests into predicates.


I created a second test file that tries to exercise more of your requirements than did your given test file.

I hope this helps.

. . . . . . . . . . Ken


T:\ftemp>type brooks.xml <root> <item> <id>12345</id> <year>2005</year> </item> <otherYears> <item> <id>56789</id> <year>2001</year> </item> <item> <id>67890</id> <year>2002</year> </item> <item> <id>78901</id> <year>2003</year> </item> <item> <id>12345</id> <year>2005</year> </item> <item> <id>89012</id> <year>2006</year> </item> <item> <id>90123</id> <year>2008</year> </item> </otherYears> </root> T:\ftemp>type brooks.xsl <?xml version="1.0" encoding="US-ASCII"?> <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"; version="1.0">

<xsl:output method="text"/>

<xsl:template match="/">
<xsl:for-each select="*/otherYears/item
[id=/*/item/id and year=/*/item/year]">
<xsl:variable name="before"
select="preceding-sibling::*[year >= current()/year - 2]"/>
<xsl:choose>
<xsl:when test="count($before) &lt; 2">
<xsl:apply-templates select="preceding-sibling::*[position() &lt; 3]"/>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="$before"/>
</xsl:otherwise>
</xsl:choose>
<xsl:apply-templates select="."/>
<xsl:variable name="after"
select="following-sibling::*[year &lt;= current()/year +2]"/>
<xsl:choose>
<xsl:when test="count($after) &lt; 2">
<xsl:apply-templates select="following-sibling::*[position() &lt; 3]"/>
</xsl:when>
<xsl:otherwise>
<xsl:apply-templates select="$after"/>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each>
</xsl:template>


<xsl:template match="item">
  <xsl:value-of select="year"/> = <xsl:value-of select="id"/>
  <xsl:text>
</xsl:text>
</xsl:template>

</xsl:stylesheet>
T:\ftemp>call xslt brooks.xml brooks.xsl
2002 = 67890
2003 = 78901
2005 = 12345
2006 = 89012
2008 = 90123

T:\ftemp>call xslt brooks2.xml brooks.xsl
2003 = 78901
2004 = 44441
2005 = 12345
2006 = 89012
2007 = 77771
2007 = 77772
2007 = 77773

T:\ftemp>type brooks2.xml
<root>
   <item>
      <id>12345</id>
      <year>2005</year>
   </item>
   <otherYears>
     <item>
        <id>56789</id>
        <year>2001</year>
     </item>
     <item>
        <id>67890</id>
        <year>2002</year>
     </item>
     <item>
        <id>78901</id>
        <year>2003</year>
     </item>
     <item>
        <id>44441</id>
        <year>2004</year>
     </item>
     <item>
        <id>12345</id>
        <year>2005</year>
     </item>
     <item>
        <id>89012</id>
        <year>2006</year>
     </item>
     <item>
        <id>77771</id>
        <year>2007</year>
     </item>
     <item>
        <id>77772</id>
        <year>2007</year>
     </item>
     <item>
        <id>77773</id>
        <year>2007</year>
     </item>
     <item>
        <id>90123</id>
        <year>2008</year>
     </item>
   </otherYears>
</root>
T:\ftemp>rem Done!



--
XSLT/XQuery training:   after http://XMLPrague.cz 2011-03-28/04-01
Vote for your XML training:   http://www.CraneSoftwrights.com/s/i/
Crane Softwrights Ltd.          http://www.CraneSoftwrights.com/s/
G. Ken Holman                 mailto:gkholman@xxxxxxxxxxxxxxxxxxxx
Male Cancer Awareness Nov'07  http://www.CraneSoftwrights.com/s/bc
Legal business disclaimers:  http://www.CraneSoftwrights.com/legal

Current Thread