この変換:
<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>
説明:
「現在の親のセット」(または「最後に見つかった親」) と現在の (まだ処理されていない) ノードのセットの 2 つのパラメーターを使用して、名前付きテンプレートを再帰的に呼び出します。
停止条件: 「現在の親のセット」または「現在のノードのセット」のいずれか、または両方が空です。ここで@name
、残りの空でないパラメータ セットを出力 (およびソート) します。
再帰的ステップ: 「現在の親」の直接の子が新しい「現在の親」になります。残りの「現在のノード」は新しい「現在のノード」になります。すべての現在の親をコピーするか、現在の親が残っていない場合はすべての現在のノードをコピーします。
更新:
コメントでは、OP は、ソリューションが小さなファイルで機能していると主張してきましたが、
「しかし、より多くの要素とより多くのレベルを含む xml 全体で試してみると、機能しません。私が持っている xml は約 8Mb であるため、ここに投稿することはできません。」
私は彼に XML ファイルを (オフラインで) 提供するように依頼し、それらを入手したとき、提供された小さいファイルと大きいファイル (44000 行、700KB) の両方でこのソリューションが問題なく動作することを確認しました。
MSXML3 を除いて、より大きなファイルでのパフォーマンスはそれほど悪くはありませんでした。
以下は、私の 8 年前の (2GB RAM、3GHz シングルコア) PC で見た、44000 行のファイルのパフォーマンス データです。
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.