Reputation: 91
I have the following xml:
<?xml version="1.0" encoding="UTF-8"?>
<notes>
<note>
<to>Aaa</to>
<from>1985</from>
</note>
<note>
<to>Bbb</to>
<from>2009</from>
</note>
<note>
<to>Ccc</to>
<from>2010</from>
</note>
<note>
<to>Aaaaaa</to>
<from>2008</from>
</note>
</notes>
and the xsl:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="initial" match="note" use="substring(to,1,1)" />
<xsl:template match="/">
<html>
<body>
<xsl:for-each select="//note[generate-id(.)= generate-id(key('initial', substring(to,1,1))[1])]">
<xsl:for-each select="key('initial', substring(to,1,1))">
<xsl:if test="from >= 2000">
<xsl:if test="position() = 1">
<h1>Heading-<xsl:value-of select="substring(to,1,1)" /></h1>
</xsl:if>
<p><xsl:value-of select="to"/></p>
<p><xsl:value-of select="from"/></p>
</xsl:if>
</xsl:for-each>
</xsl:for-each>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
this produces:
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
</head>
<body>
<p>Aaaaaa</p>
<p>2008</p>
<h1>Heading-B</h1>
<p>Bbb</p>
<p>2009</p>
<h1>Heading-C</h1>
<p>Ccc</p>
<p>2010</p>
</body>
</html>
desired output:
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
</head>
<body>
<h1>Heading-A</h1>
<p>Aaaaaa</p>
<p>2008</p>
<h1>Heading-B</h1>
<p>Bbb</p>
<p>2009</p>
<h1>Heading-C</h1>
<p>Ccc</p>
<p>2010</p>
</body>
</html>
You can see that the heading is missing for the first part of the output i.e there is no 'Heading-A' after the open body tag, I understand it is because my 'if' condition on the date in the xsl stops position() = 1 from happening. Not sure how to get the heading working do I need some type of grouping or filtering by date before the loop?
I also do not want a heading if all the dates for a particular letter are before the given 2000 i.e No header without records.
(Please note this is a cut down example of my problem).
Upvotes: 0
Views: 205
Reputation: 117073
This question would have been a lot easier to answer if you had provided a more complete test input, for example:
<notes>
<note>
<to>Aa</to>
<from>1985</from>
</note>
<note>
<to>Bb</to>
<from>2009</from>
</note>
<note>
<to>Cc</to>
<from>2010</from>
</note>
<note>
<to>Aaa</to>
<from>2008</from>
</note>
<note>
<to>Dd</to>
<from>1985</from>
</note>
<note>
<to>Bbb</to>
<from>2004</from>
</note>
<note>
<to>Ddd</to>
<from>1986</from>
</note>
<note>
<to>Aaaa</to>
<from>2005</from>
</note>
</notes>
Now, if you want to eliminate headings that do not contain any notes older than 2000, you can do so right at the beginning, in the key definition. The following stylesheet:
XSLT 1.0
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:key name="note-by-initial" match="note[from > 2000]" use="substring(to,1,1)" />
<xsl:template match="/">
<html>
<body>
<xsl:for-each select="notes/note[generate-id() = generate-id(key('note-by-initial', substring(to,1,1))[1])]">
<xsl:sort select="substring(to,1,1)" data-type="text" order="ascending"/>
<h1>Heading-<xsl:value-of select="substring(to,1,1)" /></h1>
<xsl:for-each select="key('note-by-initial', substring(to,1,1))">
<xsl:sort select="from" data-type="number" order="ascending"/>
<p>
<xsl:value-of select="to" /><br/>
<xsl:value-of select="from" />
</p>
</xsl:for-each>
</xsl:for-each>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
when applied to the above test input, will produce:
<?xml version="1.0" encoding="UTF-8"?>
<html>
<body>
<h1>Heading-A</h1>
<p>Aaaa<br/>2005</p>
<p>Aaa<br/>2008</p>
<h1>Heading-B</h1>
<p>Bbb<br/>2004</p>
<p>Bb<br/>2009</p>
<h1>Heading-C</h1>
<p>Cc<br/>2010</p>
</body>
</html>
rendered as:
Upvotes: 1
Reputation: 7173
disregard the test for position()
and add the if
test as predicate directly in the second for-each
:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:strip-space elements="*"/>
<xsl:key name="initial" match="note" use="substring(to,1,1)" />
<xsl:template match="/">
<html>
<body>
<xsl:for-each select="//note[generate-id(.)= generate-id(key('initial', substring(to,1,1))[1])]">
<xsl:for-each select="key('initial', substring(to,1,1))[from >= 2000]">
<h1>Heading-<xsl:value-of select="substring(to,1,1)" /></h1>
<p><xsl:value-of select="to"/></p>
<p><xsl:value-of select="from"/></p>
</xsl:for-each>
</xsl:for-each>
</body>
</html>
</xsl:template>
</xsl:stylesheet>
Upvotes: 0