Reputation: 1391
I have the following input xml:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<results>
<case>
<KEY>c1</KEY>
<issue>
<KEY>i1</KEY>
<id>Apple</id>
</issue>
<issue>
<KEY>i1</KEY>
<id>Orange</id>
</issue>
<issue>
<KEY>i2</KEY>
<id>Mango</id>
</issue>
</case>
<case>
<KEY>c1</KEY>
<issue>
<KEY>i5</KEY>
<id>Apricot</id>
</issue>
<issue>
<KEY>i5</KEY>
<id>Blueberry</id>
</issue>
<issue>
<KEY>i6</KEY>
<id>blackberry</id>
</issue>
</case>
<case>
<KEY>c2</KEY>
<issue>
<KEY>i3</KEY>
<id>Banana</id>
</issue>
<issue>
<KEY>i3</KEY>
<id>Cherry</id>
</issue>
<issue>
<KEY>i4</KEY>
<id>Grapes</id>
</issue>
</case>
</results>
</root>
Now I want to group by <KEY>
of <case>
first and then by<KEY>
of <issue>
. The idea is to group all the <issue>
's by their issue key and case key. Finally I want to move all the <id>
's whose issue keys are same under <sourceInstance>
node within the <issue>
.
My output xml should be as below:
<?xml version="1.0" encoding="UTF-8"?>
<root>
<results>
<case>
<KEY>c1</KEY>
<issue>
<KEY>i1</KEY>
<sources>
<sourceInstance>
<id>Apple</id>
</sourceInstance>
<sourceInstance>
<id>Orange</id>
</sourceInstance>
</sources>
</issue>
<issue>
<KEY>i2</KEY>
<sources>
<sourceInstance>
<id>Mango</id>
</sourceInstance>
</sources>
</issue>
<issue>
<KEY>i5</KEY>
<sources>
<sourceInstance>
<id>Apricot</id>
</sourceInstance>
<sourceInstance>
<id>Blueberry</id>
</sourceInstance>
</sources>
</issue>
<issue>
<KEY>i6</KEY>
<sources>
<sourceInstance>
<id>Apple</id>
</sourceInstance>
<sourceInstance>
<id>Orange</id>
</sourceInstance>
</sources>
</issue>
</case>
<case>
<KEY>c2</KEY>
<issue>
<KEY>i3</KEY>
<sources>
<sourceInstance>
<id>Banana</id>
</sourceInstance>
<sourceInstance>
<id>Cherry</id>
</sourceInstance>
</sources>
</issue>
<issue>
<KEY>i4</KEY>
<sources>
<sourceInstance>
<id>Grapes</id>
</sourceInstance>
</sources>
</issue>
</case>
</results>
</root>
I have tried by using the following XSLT, but couldn't get the desired xml output.
<?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="case" match="case" use="string(KEY)" />
<xsl:key name="issue" match="case" use="concat(KEY, '|', KEY)" />
<xsl:template match="results">
<xsl:copy>
<xsl:apply-templates select="case[generate-id() = generate-id(key('case', string(KEY))[1])]" mode="case" />
</xsl:copy>
</xsl:template>
<xsl:template match="case" mode="case">
<xsl:choose>
<xsl:when test="KEY">
<case>
<xsl:copy-of select="KEY" />
<xsl:apply-templates select="key('case', KEY)[generate-id() = generate-id(key('issue', concat(KEY, '|', KEY))[1])]" mode="issue" />
</case>
</xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template match="case " mode="issue">
<xsl:choose>
<xsl:when test="KEY">
<issue>
<xsl:copy-of select="KEY" />
<sources>
<xsl:apply-templates select="key('issue', id)" />
</sources>
</issue>
</xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="case">
<sourceInstance>
<id>
<xsl:value-of select="id" />
</id>
</sourceInstance>
</xsl:template>
</xsl:stylesheet>
It appears that I am unable to frame the correct combination of a key using the <KEY>
of <case>
and <issue>
as the node with the same name (i.e.<KEY>
)exists at both the places.
Can somebody tell me what I am missing in my XSLT?
Upvotes: 0
Views: 200
Reputation: 70598
The main problem is the definition of your key of issue
<xsl:key name="issue" match="case" use="concat(KEY, '|', KEY)" />
You need to be matching issue
elements here, and using a concatenation of the KEY for issue
and the parent case
element
<xsl:key name="issue" match="issue" use="concat(KEY, '|', ../KEY)" />
Then, to get the grouped issue
elements for a given case
KEY, you would do this...
<xsl:apply-templates select="key('case', KEY)/issue[generate-id() = generate-id(key('issue', concat(KEY, '|', ../KEY))[1])]" mode="issue" />
Try this XSLT
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml" indent="yes" />
<xsl:key name="case" match="case" use="string(KEY)" />
<xsl:key name="issue" match="issue" use="concat(KEY, '|', ../KEY)" />
<xsl:template match="results">
<xsl:copy>
<xsl:apply-templates select="case[generate-id() = generate-id(key('case', string(KEY))[1])]" mode="case" />
</xsl:copy>
</xsl:template>
<xsl:template match="case" mode="case">
<xsl:choose>
<xsl:when test="KEY">
<case>
<xsl:copy-of select="KEY" />
<xsl:apply-templates select="key('case', KEY)/issue[generate-id() = generate-id(key('issue', concat(KEY, '|', ../KEY))[1])]" mode="issue" />
</case>
</xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template match="issue" mode="issue">
<xsl:choose>
<xsl:when test="KEY">
<issue>
<xsl:copy-of select="KEY" />
<sources>
<xsl:apply-templates select="key('issue', concat(KEY, '|', ../KEY))" />
</sources>
</issue>
</xsl:when>
</xsl:choose>
</xsl:template>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()" />
</xsl:copy>
</xsl:template>
<xsl:template match="issue">
<sourceInstance>
<id>
<xsl:value-of select="id" />
</id>
</sourceInstance>
</xsl:template>
</xsl:stylesheet>
Upvotes: 2