Reputation: 5656
I am trying to list all the nodes which contains a child node which of a certain id.
Take this example xml:
<foo>
<bar name="hello">
<baz id="1" />
</bar>
<bar name="there">
<baz id="1" />
<baz id="2" />
</bar>
<bar name="world">
<baz id="3" />
</bar>
</foo>
I've come up with the following XSLT template which contains two nested for-each
loops
<xsl:for-each select="/foo/bar/baz">
<xsl:variable name="id" select="@id" />
<xsl:value-of select="$id" />
<ul>
<xsl:for-each select="/foo/bar/baz">
<xsl:variable name="local_id" select="@id" />
<xsl:variable name="bar_name" select="../@name" />
<xsl:if test="$id = $local_id">
<li><xsl:value-of select="$bar_name" /></li>
</xsl:if>
</xsl:for-each>
</ul>
</xsl:for-each>
Which gives the following result
1
- hello
- there
1
- hello
- there
2
- there
3
- world
The problem is that the first key/values pair is duplicated.
Upvotes: 0
Views: 71
Reputation: 9627
To keep the solution as it is you can change the first for-each that it only consider the first occurrence of an id.
<xsl:for-each select="/foo/bar/baz[not (preceding::baz/@id = @id)] ">
This is by far not the best solution for this kind of "problem". To improve this have a look for " Grouping Using the Muenchian Method" (E.g.. And also it is better practice to use apply-templates instead of for-each.
Here a key based solution:
<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes"/>
<xsl:key name="kBazId" match="bar/baz" use="@id"/>
<xsl:template match="/" >
<xsl:for-each select="/foo/bar/baz[count( . | key('kBazId', @id)[1])=1]" >
<xsl:value-of select="@id" />
<ul>
<xsl:apply-templates select="key('kBazId', @id)/.." />
</ul>
</xsl:for-each>
</xsl:template>
<xsl:template match="bar">
<li>
<xsl:value-of select="@name"/>
</li>
</xsl:template>
</xsl:stylesheet>
Upvotes: 1