问题
This is how my XML looks like
<?xml version="1.0"?>
<Nodes>
<NodeA NodeAattr="123">
<NodeB NodeBattr="456"></NodeB>
<NodeC>
<NodeD NodeDAttr="ValueD">
<NodeE Name="ValueABC"> "555" </NodeE >
<NodeE Name="ValueABC"> "666" </NodeE>
</NodeD>
</NodeC>
</NodeA>
</Nodes>
If the values of the Name attribute of NodeE are same, concatenate the values of NodeE. And my final output xml has to look like
<NodeA NodeAattr="123">
<NodeB NodeBattr="456"></NodeB>
<NodeC>
<NodeD="ValueD">
<NodeE Name="ValueABC"> "555" , "666" </NodeE >
</NodeD>
</NodeC>
</NodeA>
Please provide me with the xsl.. I am using XSLT1.0
回答1:
This should do it:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>
<xsl:strip-space elements="*" />
<xsl:template match="@* | node()">
<xsl:copy>
<xsl:apply-templates select="@* | node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="NodeE">
<xsl:copy>
<xsl:apply-templates select="@* | text()" />
<xsl:call-template name="NextSibling" />
</xsl:copy>
</xsl:template>
<xsl:template match="NodeE[@Name = preceding-sibling::*[1][self::NodeE]/@Name]" />
<xsl:template match="NodeE" mode="includeSib">
<xsl:value-of select="concat(',', .)"/>
<xsl:call-template name="NextSibling" />
</xsl:template>
<xsl:template name="NextSibling">
<xsl:apply-templates
select="following-sibling::*[1]
[self::NodeE and @Name = current()/@Name]"
mode="includeSib" />
</xsl:template>
</xsl:stylesheet>
When run on this input (with a few additional values to demonstrate its functionality):
<Nodes>
<NodeA NodeAattr="123">
<NodeB NodeBattr="456"></NodeB>
<NodeC>
<NodeD NodeDAttr="ValueD">
<NodeE Name="ValueABC"> "555" </NodeE >
<NodeE Name="ValueABC"> "666" </NodeE>
<NodeE Name="ValueDEF"> "555" </NodeE >
<NodeE Name="ValueDEF"> "565" </NodeE >
<NodeE Name="ValueDEF"> "575" </NodeE >
<NodeE Name="ValueABC"> "595" </NodeE >
</NodeD>
</NodeC>
</NodeA>
</Nodes>
The result is:
<Nodes>
<NodeA NodeAattr="123">
<NodeB NodeBattr="456" />
<NodeC>
<NodeD NodeDAttr="ValueD">
<NodeE Name="ValueABC"> "555" , "666" </NodeE>
<NodeE Name="ValueDEF"> "555" , "565" , "575" </NodeE>
<NodeE Name="ValueABC"> "595" </NodeE>
</NodeD>
</NodeC>
</NodeA>
</Nodes>
回答2:
Here's a solution based on my answer to question #825783:
Stylesheet
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" version="1.0" encoding="utf-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="kNode" match="NodeE" use="@Name"/>
<!--
Identity transform: copy elements and attributes from input file as is
-->
<xsl:template match="node() | @*">
<xsl:copy>
<xsl:apply-templates select="node() | @*"/>
</xsl:copy>
</xsl:template>
<!--
Use Muenchian grouping to apply unique NodeE elements.
See http://www.jenitennison.com/xslt/grouping/muenchian.html
-->
<xsl:template match="NodeE[generate-id() =
generate-id(key('kNode', @Name)[1])]">
<xsl:copy>
<xsl:apply-templates select="@*"/>
<!--
Apply <NodeE> elements with the same @Name attribute value as the current
element with the "concat" mode enabled
-->
<xsl:apply-templates select="key('kNode', @Name)" mode="concat"/>
</xsl:copy>
</xsl:template>
<xsl:template match="NodeE" mode="concat">
<xsl:value-of select="."/>
<!-- Add comma except if this is the last node -->
<xsl:if test="position() != last()">
<xsl:text>, </xsl:text>
</xsl:if>
</xsl:template>
<!-- Drop other <NodeE> elements -->
<xsl:template match="NodeE"/>
</xsl:stylesheet>
Input
Using the input provided by JLRishe:
<Nodes>
<NodeA NodeAattr="123">
<NodeB NodeBattr="456"></NodeB>
<NodeC>
<NodeD NodeDAttr="ValueD">
<NodeE Name="ValueABC"> "555" </NodeE>
<NodeE Name="ValueABC"> "666" </NodeE>
<NodeE Name="ValueDEF"> "555" </NodeE>
<NodeE Name="ValueDEF"> "565" </NodeE>
<NodeE Name="ValueDEF"> "575" </NodeE>
<NodeE Name="ValueABC"> "595" </NodeE>
</NodeD>
</NodeC>
</NodeA>
</Nodes>
Output
This is different from JLRishe's output because I understood the requirement differently:
<?xml version="1.0" encoding="utf-8"?>
<Nodes>
<NodeA NodeAattr="123">
<NodeB NodeBattr="456"/>
<NodeC>
<NodeD NodeDAttr="ValueD">
<NodeE Name="ValueABC"> "555" , "666" , "595" </NodeE>
<NodeE Name="ValueDEF"> "555" , "565" , "575" </NodeE>
</NodeD>
</NodeC>
</NodeA>
</Nodes>
来源:https://stackoverflow.com/questions/16020026/xsl-combining-values-of-siblings-if-values-of-an-attribute-is-same