Reputation: 17
I am trying to create a XSLT to transform the following XML structure
<?xml version="1.0"?>
<rows>
<row>
<e1>A1</e1>
<l2>B1-01</l2>
<q2>C1-1-1</q2>
<n2>D111</n2>
</row>
<row>
<e1>A1</e1>
<l2>B1-01</l2>
<q2>C1-1-2</q2>
<n2>D112</n2>
</row>
<row>
<e1>A1</e1>
<l2>B1-02</l2>
<q2>C1-2-1</q2>
<n2>D121</n2>
</row>
<row>
<e1>A1</e1>
<l2>B1-02</l2>
<q2>C1-2-2</q2>
<n2>D122</n2>
</row>
<row>
<e1>A2</e1>
<l2>B2-01</l2>
<q2>C2-1-1</q2>
<n2>D211</n2>
</row>
<row>
<e1>A2</e1>
<l2>B2-01</l2>
<q2>C2-1-2</q2>
<n2>D212</n2>
</row>
<row>
<e1>A2</e1>
<l2>B2-02</l2>
<q2>C2-2-1</q2>
<n2>D221</n2>
</row>
<row>
<e1>A2</e1>
<l2>B2-02</l2>
<q2>C2-2-2</q2>
<n2>D222</n2>
</row>
</rows>
into this
<?xml version="1.0"?>
<e1s xmlns:msxsl="urn:schemas-microsoft-com:xslt">
<e1>A1</e1>
<l2s>
<l2>B1-01</l2>
<q2s>
<q2>D111</q2>
<q2>D112</q2>
</q2s>
<l2>B1-02</l2>
<q2s>
<q2>D121</q2>
<q2>D122</q2>
</q2s>
</l2s>
<e1>A2</e1>
<l2s>
<l2>B2-01</l2>
<q2s>
<q2>D211</q2>
<q2>D212</q2>
</q2s>
<l2>B2-02</l2>
<q2s>
<q2>D221</q2>
<q2>D222</q2>
</q2s>
</l2s>
</e1s>
I have tried the following XSLT
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt">
<xsl:output method="xml" version="1.0" indent="yes" omit-xml-declaration="no"/>
<xsl:key name="ke1" match="row" use="e1" />
<xsl:key name="kl2" match="row" use="concat(e1,'#',l2)" />
<xsl:template match="rows">
<e1s>
<xsl:for-each select="row[generate-id() = generate-id(key('ke1', e1)[1])]">
<e1>
<xsl:value-of select="e1"/>
</e1>
<l2s>
<xsl:for-each select="../row[generate-id() = generate-id(key('kl2', concat(e1,'#',l2))[1])]">
<l2>
<xsl:value-of select="l2"/>
</l2>
<q2s>
<xsl:for-each select="key('kl2', concat(e1,'#',l2))">
<q2>
<xsl:value-of select="n2" />
</q2>
</xsl:for-each>
</q2s>
</xsl:for-each>
</l2s>
</xsl:for-each>
</e1s>
</xsl:template>
</xsl:stylesheet>
But the output is not good because it contains "B2"-stuff in the A1 element and vice versa. It seems I don't get the keys right, although I tried for two days now. Can someone please help me with this?
Upvotes: 1
Views: 1100
Reputation: 122364
Your key definitions are fine, the problem is in your second level of for-each
:
<xsl:for-each select="../row[generate-id() = generate-id(key('kl2', concat(e1,'#',l2))[1])]">
Every time around the outer for-each
, this select will process all the e1#l2
groups for all values of e1
. You need to filter here so that you're only selecting out of the rows that match the current e1
, rather than selecting out of all of them:
<xsl:for-each select="key('ke1', e1)[generate-id() = generate-id(key('kl2', concat(e1,'#',l2))[1])]">
With this change I get the correct result.
Upvotes: 1