XSLT split based on child of child data
I have:
<?xml version="1.0" encoding="utf-8"?>
<parent>
<parentspecialinfo>blond</parentspecialinfo>
<child>
<grandchild>
<grandchildtype>special</grandchildtype>
<specialvalue>123</specialvalue>
<otherstuff>123</otherstuff>
<otherstuff2>abc</otherstuff2>
<otherstuff3>zxc</otherstuff3>
</grandchild>
<grandchild>
<grandchildtype>red</grandchildtype>
<specialvalue>345</specialvalue>
<otherstuff>123</otherstuff>
<otherstuff2>abc</otherstuff2>
<otherstuff3>zxc</otherstuff3>
</grandchild>
<grandchild>
<grandchildtype>blue</grandchildtype>
&l开发者_JAVA百科t;specialvalue>678</specialvalue>
<otherstuff>123</otherstuff>
<otherstuff2>abc</otherstuff2>
<otherstuff3>zxc</otherstuff3>
</grandchild>
<otherchildthings>tiger</otherchildthings>
</child>
<child>
<grandchild>
<grandchildtype>special</grandchildtype>
<specialvalue>123</specialvalue>
<otherstuff>123</otherstuff>
<otherstuff2>abc</otherstuff2>
<otherstuff3>zxc</otherstuff3>
</grandchild>
<otherchildthings>tiger</otherchildthings>
</child>
<child>
<grandchild>
<grandchildtype>red</grandchildtype>
<specialvalue>345</specialvalue>
<otherstuff>123</otherstuff>
<otherstuff2>abc</otherstuff2>
<otherstuff3>zxc</otherstuff3>
</grandchild>
<grandchild>
<grandchildtype>blue</grandchildtype>
<specialvalue>678</specialvalue>
<otherstuff>123</otherstuff>
<otherstuff2>abc</otherstuff2>
<otherstuff3>zxc</otherstuff3>
</grandchild>
<grandchild>
<grandchildtype>special</grandchildtype>
<specialvalue>999</specialvalue>
<otherstuff>123</otherstuff>
<otherstuff2>abc</otherstuff2>
<otherstuff3>zxc</otherstuff3>
</grandchild>
<otherchildthings>tiger</otherchildthings>
</child>
</parent>
I need to copy the entire set of child records into a new parent element retaining all parental node information for each unique set of specialvalue where grandchildtype is special. So for this example we only have 2, 123 and 999. But there could be many sets of unique values. I am having some trouble moving back up the chain to retain all the elements. I was experimenting using the xsl:key element, but have not gotten far. Is that a good solution for this problem?
So this would be the result:
<?xml version="1.0" encoding="utf-8"?>
<parent>
<parentspecialinfo>blond</parentspecialinfo>
<child>
<grandchild>
<grandchildtype>special</grandchildtype>
<specialvalue>123</specialvalue>
<otherstuff>123</otherstuff>
<otherstuff2>abc</otherstuff2>
<otherstuff3>zxc</otherstuff3>
</grandchild>
<grandchild>
<grandchildtype>red</grandchildtype>
<specialvalue>345</specialvalue>
<otherstuff>123</otherstuff>
<otherstuff2>abc</otherstuff2>
<otherstuff3>zxc</otherstuff3>
</grandchild>
<grandchild>
<grandchildtype>blue</grandchildtype>
<specialvalue>678</specialvalue>
<otherstuff>123</otherstuff>
<otherstuff2>abc</otherstuff2>
<otherstuff3>zxc</otherstuff3>
</grandchild>
<otherchildthings>tiger</otherchildthings>
</child>
<child>
<grandchild>
<grandchildtype>special</grandchildtype>
<specialvalue>123</specialvalue>
<otherstuff>123</otherstuff>
<otherstuff2>abc</otherstuff2>
<otherstuff3>zxc</otherstuff3>
</grandchild>
<otherchildthings>tiger</otherchildthings>
</child>
</parent>
<parent>
<parentspecialinfo>blond</parentspecialinfo>
<child>
<grandchild>
<grandchildtype>red</grandchildtype>
<specialvalue>345</specialvalue>
<otherstuff>123</otherstuff>
<otherstuff2>abc</otherstuff2>
<otherstuff3>zxc</otherstuff3>
</grandchild>
<grandchild>
<grandchildtype>blue</grandchildtype>
<specialvalue>678</specialvalue>
<otherstuff>123</otherstuff>
<otherstuff2>abc</otherstuff2>
<otherstuff3>zxc</otherstuff3>
</grandchild>
<grandchild>
<grandchildtype>special</grandchildtype>
<specialvalue>999</specialvalue>
<otherstuff>123</otherstuff>
<otherstuff2>abc</otherstuff2>
<otherstuff3>zxc</otherstuff3>
</grandchild>
<otherchildthings>tiger</otherchildthings>
</child>
</parent>
As I have been asked for clarification here is my psuedo code walk through from my LINQ solution. I hope it helps:
1) Create shell node set by copying <parent>
.
2) Remove all <child>
elements from shell node.
3) Query original document for all <child>
nodes.
4) For each <child>
node find the <specialvalue>
value where <grandchildtype
> value is "special"
5) Check if we have already seen the <specialvalue>
if not then add the entire <child>
to a collection. If we have already seen it then find it in the collection and add it to the collection at that location.
6) For each collection value, add the <child>
nodes to a new shell node created in step 1.
7) Add all nodes created above to the same document.
Thank you.
Update: With the new input source, this stylesheet (overwriting identity rule):
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:key name="kChildBySpecialvalue"
match="child"
use="concat(
generate-id(..),'+',
grandchild[grandchildtype='special']/specialvalue
)"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="parent">
<xsl:variable name="vCurrent" select="."/>
<xsl:for-each select="child[
count(.|key('kChildBySpecialvalue',
concat(
generate-id($vCurrent),'+',
grandchild[
grandchildtype = 'special'
]/specialvalue
)
)[1]
) = 1
]">
<xsl:variable name="vGroup"
select="key('kChildBySpecialvalue',
concat(
generate-id($vCurrent),'+',
grandchild[
grandchildtype = 'special'
]/specialvalue
)
)"/>
<xsl:for-each select="$vCurrent">
<xsl:copy>
<xsl:apply-templates
select="node()[not(self::child)]|$vGroup|@*"/>
</xsl:copy>
</xsl:for-each>
</xsl:for-each>
</xsl:template>
</xsl:stylesheet>
Output:
<parent>
<parentspecialinfo>blond</parentspecialinfo>
<child>
<grandchild>
<grandchildtype>special</grandchildtype>
<specialvalue>123</specialvalue>
<otherstuff>123</otherstuff>
<otherstuff2>abc</otherstuff2>
<otherstuff3>zxc</otherstuff3>
</grandchild>
<grandchild>
<grandchildtype>red</grandchildtype>
<specialvalue>345</specialvalue>
<otherstuff>123</otherstuff>
<otherstuff2>abc</otherstuff2>
<otherstuff3>zxc</otherstuff3>
</grandchild>
<grandchild>
<grandchildtype>blue</grandchildtype>
<specialvalue>678</specialvalue>
<otherstuff>123</otherstuff>
<otherstuff2>abc</otherstuff2>
<otherstuff3>zxc</otherstuff3>
</grandchild>
<otherchildthings>tiger</otherchildthings>
</child>
<child>
<grandchild>
<grandchildtype>special</grandchildtype>
<specialvalue>123</specialvalue>
<otherstuff>123</otherstuff>
<otherstuff2>abc</otherstuff2>
<otherstuff3>zxc</otherstuff3>
</grandchild>
<otherchildthings>tiger</otherchildthings>
</child>
</parent>
<parent>
<parentspecialinfo>blond</parentspecialinfo>
<child>
<grandchild>
<grandchildtype>red</grandchildtype>
<specialvalue>345</specialvalue>
<otherstuff>123</otherstuff>
<otherstuff2>abc</otherstuff2>
<otherstuff3>zxc</otherstuff3>
</grandchild>
<grandchild>
<grandchildtype>blue</grandchildtype>
<specialvalue>678</specialvalue>
<otherstuff>123</otherstuff>
<otherstuff2>abc</otherstuff2>
<otherstuff3>zxc</otherstuff3>
</grandchild>
<grandchild>
<grandchildtype>special</grandchildtype>
<specialvalue>999</specialvalue>
<otherstuff>123</otherstuff>
<otherstuff2>abc</otherstuff2>
<otherstuff3>zxc</otherstuff3>
</grandchild>
<otherchildthings>tiger</otherchildthings>
</child>
</parent>
Note: Gruping parent
's child
children by specialvalue
when grandchildtype
is equal to 'special'
; copying itself, others children and group for each group.
精彩评论