Reputation: 4382
I have an XML containing blog posts. Each post contains a date
node.
I want to extract the list of years in which posts have been made and print them out in a fancy format. The, for each year I want to print out the list of active months in a very similar fashion.
The outer part is working fine for me. Since I couldn't find a way to achieve this using raw XSLT-1.0, I implemented it using EXSLT. I iterate over the posts, extract the year, put it in a new year
node and store this as a temporary XML tree in a variable. Then I use EXSLT to create a nodeset from this variable, iterate over it and remove duplicates.
However, as soon as I call an inner template for each year, even if I copy and paste the variable construction code from the first template and dump it, it does not generate any output. It just refuses to iterate over the same nodeset again.
I'm hitting a wall here and I definitely can't wrap my head around what exactly is happening.
This is as much as I've managed to simplify the stylesheet::
<xsl:param name="myparam" select="''" />
<xsl:template match="/">
<ul>
<xsl:call-template name="outer" />
</ul>
</xsl:template>
<xsl:template name="outer">
<xsl:variable name="years_tree">
<xsl:for-each select="//post">
<xsl:sort select="date" />
<xsl:element name="year"><xsl:value-of select="substring(date, 1, 4)" /></xsl:element>
</xsl:for-each>
</xsl:variable>
<xsl:comment>
<xsl:copy-of select="$years_tree" />
</xsl:comment>
<xsl:for-each select="exsl:node-set($years_tree)/year[not(.=following::year)]">
<li>
<xsl:value-of select="." />
<xsl:if test="starts-with($myparam, string(.))">
<ul>
<xsl:call-template name="inner" />
</ul>
</xsl:if>
</li>
</xsl:for-each>
</xsl:template>
<xsl:template name="inner">
<xsl:variable name="years_tree">
<xsl:for-each select="//post">
<xsl:sort select="date" />
<xsl:element name="year"><xsl:value-of select="substring(date, 1, 4)" /></xsl:element>
</xsl:for-each>
</xsl:variable>
<xsl:copy-of select="$years_tree" />
</xsl:template>
</xsl:stylesheet>
This is my sample input::
<?xml version="1.0" encoding="UTF-8"?>
<blog>
<post>
<date>2011-10-22T22:50:26</date>
</post>
<post>
<date>2011-10-02T17:25:14</date>
</post>
<post>
<date>2011-10-14T11:58:58</date>
</post>
<post>
<date>2011-11-21T11:58:58</date>
</post>
<post>
<date>2010-10-14T11:58:58</date>
</post>
<post>
<date>2011-09-14T11:58:58</date>
</post>
</blog>
and this is the output I'm getting::
<?xml version="1.0"?>
<ul>
<debug>
<year>2010</year>
<year>2011</year>
<year>2011</year>
<year>2011</year>
<year>2011</year>
<year>2011</year>
</debug>
<li>2010<ul><debug/></ul></li>
<li>2011<ul><debug/></ul></li>
</ul>
Upvotes: 0
Views: 639
Reputation: 167696
Well the path /
selects the document node of the current context node and in your case you are working with two documents, the primary input document and the temporary document you create. When you call the other template the context node is a year
element in the temporary document, thus your attempt with //post
tries to find post
elements in the temporary document and you don't have any in that document. So you need to make sure you store a global <xsl:variable name="main-doc" select="/"/>
and then when you are looking for post
elements in the primary input document you can use $main-doc//post
.
Upvotes: 1