Reputation: 15
let's say I have following xml file:
<root>
<header>
<headernodes1/>
<headernodes2/>
</header>
<items>
<itemno>1</itemno>
<itemtext>first item</itemtext>
<loop>
<range>
<rangefrom>4711</rangefrom>
<rangeto>4713</rangeto>
</range>
<content>content in the first loop</content>
</loop>
<loop>
<range>
<rangefrom>4715</rangefrom>
<rangeto>4718</rangeto>
</range>
<content>content in the second loop</content>
</loop>
</items>
<footernodes/>
</root>
The header, footer and nodes in <item>
before <loop>
should just be copied.
If <rangeto>
not appears, then just copy the <loop>
segment. Otherwise if it does appear, then replicate the <loop>
segment like following example:
<loop>
<range>
<rangefrom>4711</rangefrom>
</range>
<content>content in the first loop</content>
</loop>
<loop>
<range>
<rangefrom>4712</rangefrom>
</range>
<content>content in the first loop</content>
</loop>
<loop>
<range>
<rangefrom>4713</rangefrom>
</range>
<content>content in the first loop</content>
</loop>
<loop>
<range>
<rangefrom>4715</rangefrom>
</range>
<content>content in the second loop</content>
</loop>
<loop>
<range>
<rangefrom>4716</rangefrom>
</range>
<content>content in the second loop</content>
</loop>
<loop>
<range>
<rangefrom>4717</rangefrom>
</range>
<content>content in the second loop</content>
</loop>
<loop>
<range>
<rangefrom>4718</rangefrom>
</range>
<content>content in the second loop</content>
</loop>
Is there a solution in XSLT 1.0?
Thank you very much for your help & advice.
Greetings from Germany, L
Upvotes: 0
Views: 572
Reputation: 338248
XSLT has no loops, since it does not have writable variables (i.e. there can't be a loop counter).
But it has something else: recursion!
<!-- process <loop> without <rangeto> directly as single item -->
<xsl:template match="loop[range/rangefrom and not(range/rangeto)]">
<xsl:apply-templates select="." mode="single" />
</xsl:template>
<!-- process <loop> with <rangefrom>/<rangeto> as a succession of single items -->
<xsl:template match="loop[range/rangefrom <= range/rangeto]">
<xsl:param name="i" select="range/rangefrom" />
<xsl:apply-templates select="." mode="single">
<xsl:with-param name="i" select="$i" />
</xsl:apply-templates>
<xsl:if test="$i < range/rangeto">
<!-- recursive step: same node, incremented index -->
<xsl:apply-templates select=".">
<xsl:with-param name="i" select="$i + 1" />
</xsl:apply-templates>
</xsl:if>
</xsl:template>
<!-- single item: outputs its index as <rangefrom> -->
<xsl:template match="loop" mode="single">
<xsl:param name="i" select="range/rangefrom" />
<xsl:copy>
<range>
<rangefrom><xsl:value-of select="$i" /></rangefrom>
</range>
<xsl:copy-of select="content" />
</xsl:copy>
</xsl:template>
Modern XSLT engines recognize this as tail recursion and optimize it into iteration so you will not see a "recursion too deep" error for long loops.
Upvotes: 1
Reputation: 640
try out the following
<xsl:template match="/root">
<good>
<header>
<xsl:apply-templates select="header"/>
</header>
<footernodes>
<xsl:apply-templates select="footernodes"/>
</footernodes>
<xsl:for-each select="items/loop">
<xsl:if test="range/rangeto!=''">
<xsl:call-template name="range">
<xsl:with-param name="rangedata" select="range"/>
<xsl:with-param name="contentdata" select="content"/>
<xsl:with-param name="vardata" select="range/rangefrom"/>
</xsl:call-template>
</xsl:if>
</xsl:for-each>
</good>
</xsl:template>
<xsl:template match="header">
<xsl:copy-of select="."/>
</xsl:template>
<xsl:template match="footernodes">
<xsl:copy-of select="."/>
</xsl:template>
<xsl:template name="range">
<xsl:param name="rangedata"/>
<xsl:param name="contentdata"/>
<xsl:param name="vardata"/>
<xsl:if test="$vardata <=$rangedata/rangeto">
<loop>
<range>
<rangefrom>
<xsl:value-of select="$vardata"/>
</rangefrom>
<content>
<xsl:value-of select="$contentdata"/>
</content>
</range>
</loop>
<xsl:call-template name="range">
<xsl:with-param name="rangedata" select="$rangedata"/>
<xsl:with-param name="contentdata" select="$contentdata"/>
<xsl:with-param name="vardata" select="$vardata+1"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
You could use recursion to achieve what you desire
Upvotes: 0