值得一提的是,这里有一种在 XSLT 1.0 中执行此操作的方法。
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes" />
<xsl:strip-space elements="*" />
<xsl:key name="name" match="*[@name]" use="
concat(@name, '|', ancestor::*[1]/@name, '|', ancestor::*[2]/@name)
" />
<xsl:template match="node() | @*">
<xsl:copy>
<xsl:apply-templates select="node() | @*" />
</xsl:copy>
</xsl:template>
<xsl:template match="*[@name]">
<xsl:variable name="myKey" select="
concat(@name, '|', ancestor::*[1]/@name, '|', ancestor::*[2]/@name)
" />
<xsl:variable name="myGroup" select="key('name', $myKey)" />
<xsl:if test="generate-id() = generate-id($myGroup[1])">
<xsl:copy>
<xsl:copy-of select="@*" />
<xsl:apply-templates select="$myGroup/*" />
</xsl:copy>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
输出
<roots>
<root name="name1">
<layer1 name="name2">
<layer2 attribute="sowhat"/>
<layer2 attribute="justit"/>
<layer2 attribute="yeaha"/>
</layer1>
</root>
<root name="name2123">
<layer1 name="name2">
<layer2 attribute="itis"/>
</layer1>
</root>
</roots>
XSLT 的关键特性是能够用相对较少的代码行来表达复杂的转换。上面的转换是 29 行代码,你可以进一步压缩它。
我认为 XSLT 速成课程超出了这个答案的范围。除此之外,互联网上还有无数的 XSLT 速成课程。
所以我要做的是对这里发生的事情进行一个总体概述。
首先,我为您的输入定义了两类元素——可合并的和不可合并的。我已经定义了所有具有@name
可合并属性的元素。
- 所有正常节点(没有 a 的节点
@name
)都按原样复制。第一个<xsl:template>
这样做(它是身份模板)。
- 我将元素的“可合并组”定义为
@name
沿其祖先共享一组公共属性值的元素。
- 为此,我
@name
为拥有它们的所有元素创建了所有相关属性的串联。
- 目前,这种转换可以处理深度为 3 级的组 (
concat(@name, '|', ancestor::*[1]/@name, '|', ancestor::*[2]/@name)
)。
- 如有必要,以相同的方式添加更多级别。
- 父级的组名(键
sowhat
) is name2|name1||
,这适用<layer2>
于该逻辑组中的另一个。
- 现在,每当 XSLT 引擎遇到带有 a 的元素时
@name
,它
- 计算该元素的键(
$myKey
)。
- 获取具有相同键 (
$myGroup
) 的元素组。
- 找出当前元素是否是组中的第一个元素,如果是,则将其复制到输出
- 这有效地通过它们的键对元素进行分组(这种技术称为Muenchian 分组)。
- 然后它采取递归步骤:它开始处理该组的孩子(
$myGroup/*
)。
- 实际上,这使我们回到了 0 方,算法从头开始。
我的代码中有一些假设/限制可能不一定与您的输入一致。
- 这些元素应该由它们
@name
而不是由其他一些属性合并。
- 具有相同
@name
祖先的元素没有特殊属性,因此丢弃某个组中除第一个元素之外的所有元素不会导致数据丢失。
- 嵌套深度有限。
- 可合并元素永远不是不可合并元素的后代(没有
<layer>
a @name
inside a<layer>
没有 a @name
)
- 可能其他人现在让我忘记了。
阅读建议
- 模板匹配和 XSLT 处理器的一般工作机制
- XSL 默认规则
- XPath
- XSL 键和 Muenchian 分组
- 身份模板
- 当前节点的概念贯穿整个处理流程