这种转变:
<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="kElemById" match="Category"
use="@id"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match="/*">
<xsl:copy>
<xsl:copy-of select="@*"/>
<xsl:call-template name="sortHier">
<xsl:with-param name="pNodes" select=
"*[ParentCategory]"/>
<xsl:with-param name="pParents" select=
"*[not(ParentCategory)]"/>
</xsl:call-template>
</xsl:copy>
</xsl:template>
<xsl:template name="sortHier">
<xsl:param name="pNodes"/>
<xsl:param name="pParents"/>
<xsl:apply-templates select=
"$pParents|$pNodes[not($pParents)]">
<xsl:sort select="@name"/>
</xsl:apply-templates>
<xsl:if test="$pNodes and $pParents">
<xsl:variable name="vNewParents"
select="key('kElemById', $pNodes/ParentCategory)
[not(@id=$pParents/@id)]
"/>
<xsl:variable name="vNewChildren"
select="$pNodes[not(@id=$vNewParents/@id)]"/>
<xsl:call-template name="sortHier">
<xsl:with-param name="pNodes"
select="$vNewChildren"/>
<xsl:with-param name="pParents"
select="$vNewParents"/>
</xsl:call-template>
</xsl:if>
</xsl:template>
</xsl:stylesheet>
应用于此 XML 文档时(基于提供的文档,但已打乱/未排序):
<Catalog name="AccessoriesCatalog">
<Category Definition="AccessoriesCategory"
name="16144" id="16144">
<ParentCategory>16131</ParentCategory>
</Category>
<Category Definition="AccessoriesCategory"
name="16116" id="16116">
<ParentCategory>16115</ParentCategory>
</Category>
<Category Definition="AccessoriesCategory"
name="16126" id="16126">
<ParentCategory>16115</ParentCategory>
</Category>
<Category Definition="AccessoriesCategory"
name="16131" id="16131">
<ParentCategory>1532</ParentCategory>
</Category>
<Category Definition="AccessoriesCategory"
name="16132" id="16132">
<ParentCategory>16131</ParentCategory>
</Category>
<Category Definition="AccessoriesCategory"
name="16136" id="16136">
<ParentCategory>16131</ParentCategory>
</Category>
<Category Definition="AccessoriesCategory"
name="16139" id="16139">
<ParentCategory>16131</ParentCategory>
</Category>
<Category Definition="AccessoriesCategory"
name="16115" id="16115">
<ParentCategory>1532</ParentCategory>
</Category>
<Category Definition="AccessoriesCategory"
name="1532" id="1532"></Category>
<Category Definition="AccessoriesCategory"
name="16195" id="16195">
<ParentCategory>16131</ParentCategory>
</Category>
</Catalog>
产生想要的正确结果:
<Catalog name="AccessoriesCatalog">
<Category Definition="AccessoriesCategory" name="1532" id="1532"/>
<Category Definition="AccessoriesCategory" name="16115" id="16115">
<ParentCategory>1532</ParentCategory>
</Category>
<Category Definition="AccessoriesCategory" name="16131" id="16131">
<ParentCategory>1532</ParentCategory>
</Category>
<Category Definition="AccessoriesCategory" name="16116" id="16116">
<ParentCategory>16115</ParentCategory>
</Category>
<Category Definition="AccessoriesCategory" name="16126" id="16126">
<ParentCategory>16115</ParentCategory>
</Category>
<Category Definition="AccessoriesCategory" name="16132" id="16132">
<ParentCategory>16131</ParentCategory>
</Category>
<Category Definition="AccessoriesCategory" name="16136" id="16136">
<ParentCategory>16131</ParentCategory>
</Category>
<Category Definition="AccessoriesCategory" name="16139" id="16139">
<ParentCategory>16131</ParentCategory>
</Category>
<Category Definition="AccessoriesCategory" name="16144" id="16144">
<ParentCategory>16131</ParentCategory>
</Category>
<Category Definition="AccessoriesCategory" name="16195" id="16195">
<ParentCategory>16131</ParentCategory>
</Category>
</Catalog>
说明:
递归调用命名模板,带有两个参数:“当前父节点集”(或“最后找到的父节点”)和当前(仍未处理)节点集。
停止条件:“当前父节点集”或“当前节点集”或两者都为空。在这里,我们输出(并排序@name
)剩余的非空参数集。
递归步骤:“当前父母”的直系子女成为新的“当前父母”。其余的“当前节点”成为新的“当前节点”。如果没有当前父节点,则复制所有当前父节点或所有当前节点。
更新:
在评论中,OP一直声称该解决方案正在处理小文件,
“但是当我尝试使用更多元素和更多级别的整个 xml 时,它不起作用。我拥有的 xml 大约是 8Mb,所以我不能在这里发布它。”
我让他(离线)提供 XML 文件,当我得到它们时,我已经确认这个解决方案在我提供的小型和大型(44000 行,700KB)文件上都没有问题。
除了 MSXML3 之外,更大文件的性能并不算太差。
这是 44000 行文件的性能数据,在我的 8 岁(2GB RAM,3GHz 单核)PC 上看到:
MSXML3: 91 sec.
MSXML6: 6 sec.
AltovaXML (XMLSpy): 6 sec.
Saxon 6.5.4: 2 sec.
Saxon 9.1.05: 1.6 sec.
XslCompiledTransform 1.3 sec.
XQSharp: 0.8 sec.