正如我在评论中所说,这一点都不简单,尤其是。如果仅限于 XSLT 1.0。我的建议是分几个步骤来做到这一点。第一步是将您的输入转换为如下内容:
<elems>
<elem level="1" parent="">A</elem>
<elem level="2" parent="A">B</elem>
<elem level="3" parent="B">C</elem>
<elem level="4" parent="C" value="Value1">D</elem>
<elem level="1" parent="">A</elem>
<elem level="2" parent="A">B</elem>
<elem level="3" parent="B">C</elem>
<elem level="4" parent="C" value="Value2">E</elem>
<elem level="1" parent="">A</elem>
<elem level="2" parent="A">B</elem>
<elem level="3" parent="B">C</elem>
<elem level="4" parent="C" value="Value3">F</elem>
<elem level="1" parent="">A</elem>
<elem level="2" parent="A">C</elem>
<elem level="3" parent="C" value="Value4">F</elem>
<elem level="1" parent="">A</elem>
<elem level="2" parent="A">C</elem>
<elem level="3" parent="C" value="Value5">G</elem>
</elems>
在第二步中,您为elem
第一级的每个不同创建一个元素。
最后,您将模板递归地应用到每个元素的不同子元素——即比当前层深一层的元素,并且它们的父元素的名称与当前元素的名称匹配。
以下样式表使用 EXSLT 扩展函数来标记路径并仅选择不同的节点。如果您的 XSLT 处理器不支持这些功能,您将不得不使用命名递归模板来进行标记化,并使用 Muenchian 分组来选择不同的节点。
XSLT 1.0 (+EXSLT)
<xsl:stylesheet version="1.0"
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:exsl="http://exslt.org/common"
xmlns:set="http://exslt.org/sets"
xmlns:str="http://exslt.org/strings"
extension-element-prefixes="exsl set str">
<xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:key name="children" match="elem" use="concat(@parent, '|', @level)" />
<xsl:variable name="elems">
<xsl:for-each select="/DETAILS/DETAIL">
<xsl:variable name="value" select="VALUE" />
<xsl:for-each select="str:tokenize(PATH, '\')">
<elem level="{position()}" parent="{preceding-sibling::token[1]}">
<xsl:if test="position()=last()">
<xsl:attribute name="value">
<xsl:value-of select="$value"/>
</xsl:attribute>
</xsl:if>
<xsl:value-of select="."/>
</elem>
</xsl:for-each>
</xsl:for-each>
</xsl:variable>
<xsl:variable name="elems-set" select="exsl:node-set($elems)" />
<xsl:template match="/">
<output>
<xsl:apply-templates select="set:distinct($elems-set/elem[@level=1])"/>
</output>
</xsl:template>
<xsl:template match="elem">
<xsl:element name="{.}">
<xsl:value-of select="@value"/>
<xsl:apply-templates select="set:distinct(key('children', concat(., '|', @level + 1)))"/>
</xsl:element>
</xsl:template>
</xsl:stylesheet>
请注意,这一切都基于一个假设,即不能有同名的兄弟元素。