I.Вот полное решение XSLT 1.0 :
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:param name="pYearsBack" select="6"/>
<xsl:param name="pThisYear" select="2012"/>
<xsl:variable name="vEarliest" select=
"$pThisYear - $pYearsBack"/>
<xsl:variable name="vYears" select="/*/*/year"/>
<xsl:template match="/">
<incidents>
<xsl:call-template name="genYears"/>
</incidents>
</xsl:template>
<xsl:template name="genYears">
<xsl:param name="pTimes" select="$pYearsBack+1"/>
<xsl:param name="pStart" select="$pThisYear"/>
<xsl:if test="$pTimes > 0">
<incident>
<year>
<xsl:value-of select=
"concat($vYears[. = $pStart],
substring('missingYear',
1 div not($vYears[. = $pStart]))
)
"/>
</year>
</incident>
<xsl:call-template name="genYears">
<xsl:with-param name="pTimes" select="$pTimes -1"/>
<xsl:with-param name="pStart" select="$pStart -1"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
, когда это преобразование применяется к предоставленному XML-документу (исправлено, чтобы быть корректным):
<incidents>
<incident>
<year>2011</year>
<other-data-here/>
</incident>
<incident>
<year>2009</year>
<other-data-here/>
</incident>
<incident>
<year>2006</year>
</incident>
</incidents>
требуемый, правильный результат (инцидент за весь год, начиная с $pThisYear
назад $pYearsBack
года) производится :
<incidents>
<incident>
<year>missingYear</year>
</incident>
<incident>
<year>2011</year>
</incident>
<incident>
<year>missingYear</year>
</incident>
<incident>
<year>2009</year>
</incident>
<incident>
<year>missingYear</year>
</incident>
<incident>
<year>missingYear</year>
</incident>
<incident>
<year>2006</year>
</incident>
</incidents>
II.Решение XSLT 2.0 :
Как обычно, решение XSLT 2.0 намного проще, короче и более читабельно:
<xsl:stylesheet version="2.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:param name="pYearsBack" select="6" as="xs:integer"/>
<xsl:param name="pThisYear" select="2012" as="xs:integer"/>
<xsl:variable name="vEarliest" select=
"$pThisYear - $pYearsBack -1"/>
<xsl:variable name="vYears" select="/*/*/year/xs:integer(.)"/>
<xsl:template match="/">
<incidents>
<xsl:for-each select="1 to $pYearsBack +1">
<xsl:variable name="vthisYear" as="xs:integer"
select="$pThisYear - . +1"/>
<incident>
<year>
<xsl:sequence select=
"($vYears[. eq $vthisYear], 'missingYear')[1]"/>
</year>
</incident>
</xsl:for-each>
</incidents>
</xsl:template>
</xsl:stylesheet>
, когда это преобразование применяется к тому же XMLдокумент (выше), тот же правильный результат получается :
<incidents>
<incident>
<year>missingYear</year>
</incident>
<incident>
<year>2011</year>
</incident>
<incident>
<year>missingYear</year>
</incident>
<incident>
<year>2009</year>
</incident>
<incident>
<year>missingYear</year>
</incident>
<incident>
<year>missingYear</year>
</incident>
<incident>
<year>2006</year>
</incident>
</incidents>