问题
As an addition to my orginal post Group/merge childs of same nodes in xml/xslt I ran into the problem of having that structure repeated multiple times for different nodes (wihtin nodes higher in the hierarchy) e.g.,
<Collection>
<Questionnaire Name="Preferences" VersionID="3QW">
<Subject ID="2355">
<EventData Name="First Part">
<FormData Name="Past">
<GroupData ID="xxx" Key="4" Temp="yyy">
<ItemData ID="zzz" Value="3"/>
</GroupData>
<GroupData ID="xxx" Key="4" Temp="yyy">
<ItemData ID="qqq" Value="4"/>
</GroupData>
...
</FormData>
<FormData Name="Present">
<GroupData ID="yyy" Key="9" Temp="yyy">
<ItemData ID="www" Value="32"/>
</GroupData>
...
</FormData>
</EventData>
<EventData Name="SecondPart">
...
</EventData>
</Subject>
<Subject ID="9812">
...
</Subject>
</Questionnaire>
</Collection>
After trying variations on the suggestions I reveived and some other things I am stuck. I think it has something to do with multiple levels (and GroupData being spread over upper/grandparent nodes in which it will be a child) and then it possiblly does not have unique IDs anymore. So how can I get the childs of each GroupData node into one GroupData node (matched on ID and sometimes Key, since the latter is not always present)? Note: The same GroupData nodes (with corresponding attributes) must be merged into one GroupData node in each FormData node.
回答1:
Here are two XSLT 1.0 solutions.
One solution is to take Dimite's solution from your first question, and just expand the key to include FormData...
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kGDByIdKey" match="FormData/GroupData"
use="concat(@ID, '+', @Key, '+', generate-id(..))"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match=
"FormData/GroupData
[generate-id()
=
generate-id(key('kGDByIdKey', concat(@ID, '+', @Key, '+', generate-id(..)))[1])
]">
<xsl:copy>
<xsl:apply-templates select=
"@*|key('kGDByIdKey', concat(@ID, '+', @Key, '+', generate-id(..)))/node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="GroupData"/>
</xsl:stylesheet>
Another solution moves the grouping test from the template match condition to the the invoking xsl:apply-templates in the parent FormData ...
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kGDByIdKey" match="FormData/GroupData" use="concat(@ID, '+', @Key)" />
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="FormData">
<xsl:copy>
<xsl:apply-templates select="
@* |
node()[not(self::GroupData)] |
GroupData[generate-id() =
generate-id(key('kGDByIdKey', concat(@ID, '+', @Key))[1])]"/>
</xsl:copy>
</xsl:template>
<xsl:template match="FormData/GroupData">
<xsl:copy>
<xsl:apply-templates select="@*|
key('kGDByIdKey', concat(@ID, '+', @Key))/node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="GroupData"/>
</xsl:stylesheet>
Both stylesheets assume that GroupData's parent is only ever FormData. Any GroupData which does not have a FormData parent is removed.
来源:https://stackoverflow.com/questions/11970395/group-merge-childs-of-same-nodes-in-xml-xslt-when-repeating-upper-nodes