如何使用XSLT合并XML元素并重构同名同类型的元素/属性?
基于XSLT合并同ATTRIBUTEX值的ELEMENT元素
需求回顾
输入XML示例:
<FILE> <ELEMENT> <ATTRIBUTEX>1</ATTRIBUTEX> <ATTRIBUTEY>A</ATTRIBUTEY> </ELEMENT> <ELEMENT> <ATTRIBUTEX>1</ATTRIBUTEX> <ATTRIBUTEY>B</ATTRIBUTEY> </ELEMENT> </FILE>
期望输出:
<FILE> <ELEMENT> <ATTRIBUTEX>1</ATTRIBUTEX> <NEWELEMENT> <ATTRIBUTEY>A</ATTRIBUTEY> </NEWELEMENT> <NEWELEMENT> <ATTRIBUTEY>B</ATTRIBUTEY> </NEWELEMENT> </ELEMENT> </FILE>
XSLT 1.0 解决方案(Muenchian分组)
XSLT 1.0中可以用Muenchian分组直接完成分组与结构重构,无需提前合并元素:
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <!-- 定义分组键:按ATTRIBUTEX的文本值分组 --> <xsl:key name="elementByX" match="ELEMENT" use="ATTRIBUTEX/text()" /> <xsl:template match="FILE"> <FILE> <!-- 遍历每个唯一分组的第一个ELEMENT(代表该组) --> <xsl:for-each select="ELEMENT[count(. | key('elementByX', ATTRIBUTEX/text())[1]) = 1]"> <ELEMENT> <!-- 复制当前组的ATTRIBUTEX --> <xsl:copy-of select="ATTRIBUTEX" /> <!-- 遍历当前组内的所有ELEMENT,生成对应的NEWELEMENT --> <xsl:for-each select="key('elementByX', ATTRIBUTEX/text())"> <NEWELEMENT> <xsl:copy-of select="ATTRIBUTEY" /> </NEWELEMENT> </xsl:for-each> </ELEMENT> </xsl:for-each> </FILE> </xsl:template> </xsl:stylesheet>
代码说明
<xsl:key>:定义分组规则,将所有ELEMENT按ATTRIBUTEX的文本值分组。- 外层
xsl:for-each:筛选出每个分组的第一个ELEMENT,确保每个ATTRIBUTEX值只生成一个父ELEMENT。 - 内层
xsl:for-each:遍历当前分组下的所有ELEMENT,为每个ATTRIBUTEY生成独立的NEWELEMENT。
XSLT 2.0+ 简化解决方案
如果使用XSLT 2.0或更高版本,可直接用for-each-group语法,代码更简洁:
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:template match="FILE"> <FILE> <!-- 按ATTRIBUTEX的值分组 --> <xsl:for-each-group select="ELEMENT" group-by="ATTRIBUTEX"> <ELEMENT> <xsl:copy-of select="current-group()[1]/ATTRIBUTEX" /> <!-- 遍历分组内的每个元素,生成NEWELEMENT --> <xsl:for-each select="current-group()"> <NEWELEMENT> <xsl:copy-of select="ATTRIBUTEY" /> </NEWELEMENT> </xsl:for-each> </ELEMENT> </xsl:for-each-group> </FILE> </xsl:template> </xsl:stylesheet>
原有方案错误原因
你之前的代码存在两个核心问题:
- 硬编码NEWELEMENT数量:手动写了两个
NEWELEMENT,无法适配任意数量的ATTRIBUTEY。 - 未遍历单个ATTRIBUTEY:
xsl:copy-of select="ATTRIBUTEY"会选中当前ELEMENT下所有ATTRIBUTEY元素,导致每个NEWELEMENT都包含所有值。
通过XSLT分组可以直接从原始XML完成合并与结构重构,无需提前合并元素,避免了同名元素带来的处理问题。
内容的提问来源于stack exchange,提问作者Benjamin Hammond
相关产品推荐
相关产品推荐

