Reputation: 11
Is there any way in XSLT 1.0 to restrict the function key() to search within a child node and not entire input XML. My input XML is
<a>
<b>
<c>
<d name="1"/>
<d name="2"/>
<d name="3"/>
<d name="1"/>
</c>
</b>
<b>
<c>
<d name="1"/>
<d name="2"/>
</c>
</b>
</a>
XSLT that I have written is
<?xml version="1.0"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="findD" match="d" use="@name"/>
<xsl:template match="/">
<start>
<xsl:apply-templates select="a/b/c"/>
</start>
</xsl:template>
<xsl:template match="a/b/c">
<inside>
<xsl:for-each select="key('findD', '1')">
<xsl:copy-of select="."/>
</xsl:for-each>
</inside>
</xsl:template>
Which results in
<?xml version='1.0' ?>
<start>
<inside>
<d name="1"/>
<d name="1"/>
<d name="1"/>
</inside>
<inside>
<d name="1"/>
<d name="1"/>
<d name="1"/>
</inside>
</start>
What I need is something like
<?xml version='1.0' ?>
<start>
<inside>
<d name="1"/>
<d name="1"/>
</inside>
<inside>
<d name="1"/>
</inside>
</start>
This returns all the three nodes 'd' (present in xml) for every c node. While what I need is to get d nodes within corresponding c node (when key is called).
I have seen use of concat within key() where one can concat result based on node c's value. Is there any other way to say key() to look within a node only and not entire XML.
Upvotes: 1
Views: 163
Reputation: 1235
Here is an answer:
<xsl:key name="findD" match="d" use="generate-id(..)"/>
<xsl:template match="/">
<start>
<xsl:apply-templates select="a/b/c"/>
</start>
</xsl:template>
<xsl:template match="a/b/c">
<xsl:variable name="parentID" select="generate-id(.)"/>
<inside>
<xsl:for-each select="key('findD', $parentID)[@name='1']">
<xsl:copy-of select="."/>
</xsl:for-each>
</inside>
</xsl:template>
Please tell us why you want to use a key here. Just using normal push programming would be a very efficient and straight forward way to solve this problem.
<xsl:template match="/">
<start>
<xsl:apply-templates select="a/b/c"/>
</start>
</xsl:template>
<xsl:template match="c">
<inside>
<xsl:apply-templates select="d[@name='1']"/>
</inside>
</xsl:template>
<xsl:template match="d">
<xsl:copy-of select="."/>
</xsl:template>
Upvotes: 0