これは、代替の XSLT 2.0 スタイルシートです。これは、最も単純でありながら汎用的なソリューションであると私は信じています。
この変身…
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:variable name="sep" select="' > '" />
<xsl:template match="categories" name="cat-grouper">
<xsl:param name="cat-strs" as="xs:string*" select="category" />
<categories>
<xsl:for-each-group select="$cat-strs[contains(.,$sep)]" group-by="substring-before(.,$sep)">
<category name="{current-grouping-key()}">
<xsl:call-template name="cat-grouper">
<xsl:with-param name="cat-strs" select="for $s in current-group() return substring-after($s,$sep)" />
</xsl:call-template>
</category>
</xsl:for-each-group>
<xsl:for-each-group select="$cat-strs[not(contains(.,$sep))]" group-by=".">
<category name="{current-grouping-key()}" />
</xsl:for-each-group>
</categories>
</xsl:template>
</xsl:stylesheet>
...次の入力に適用されます(OPのサンプル入力から適合させて、<category>För honom > Badkläder</category>
入力での2回の出現に関連する彼のコメントに対処します)...
<categories>
<category>För henne > Ansikte</category>
<category>För henne > Pumps & klackskor</category>
<category>För henne > Stövlar & stövletter</category>
<category>För honom > Badkläder</category>
<category>För honom > Badkläder</category>
</categories>
...収量...
<categories>
<category name="För henne">
<categories>
<category name="Ansikte"/>
<category name="Pumps & klackskor"/>
<category name="Stövlar & stövletter"/>
</categories>
</category>
<category name="För honom">
<categories>
<category name="Badkläder"/>
</categories>
</category>
</categories>
ノート
唯一無二のテンプレートに二重の目的を持たせることで、ある程度の単純さが得られます。これは、ルート要素に一致するテンプレートであるcategories
と同時に、カテゴリ文字列のリストを処理するための名前付きテンプレートでもあります。
もう一つ
別の代替ソリューションを次に示します。私が提供した最初のものを好む場合は、これを見てみる価値があります. 同様に tokenize() を使用すると、これは Dimitre のソリューションの微調整に過ぎないと考えるかもしれません。
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:variable name="sep" select="' > '" />
<xsl:template match="categories" name="cat-grouper">
<xsl:param name="cat-strs" as="xs:string*" select="category" />
<categories>
<xsl:for-each-group select="$cat-strs" group-by="tokenize(.,$sep)[1]">
<category name="{current-grouping-key()}">
<xsl:variable name="subcats" select="
for $s in current-group()[contains(.,$sep)]
return substring-after($s,$sep)" />
<xsl:if test="exists($subcats)">
<xsl:call-template name="cat-grouper">
<xsl:with-param name="cat-strs" select="$subcats" />
</xsl:call-template>
</xsl:if>
</category>
</xsl:for-each-group>
</categories>
</xsl:template>
</xsl:stylesheet>
補遺
Dimitre の入力ドキュメントに最初のソリューションを適用した結果の出力を次に示します。これが彼の変換規則の正しい解釈であるかどうか、OP にアドバイスを求めています。これは私の理解ですが、もしかしたら私の認識が間違っているのでしょうか?
<categories>
<category name="A">
<categories>
<category name="AB1">
<categories>
<category name="AB1C1"/>
</categories>
</category>
<category name="AB2">
<categories>
<category name="AB2C1">
<categories>
<category name="AB2C1D1"/>
<category name="AB2C3"/>
</categories>
</category>
<category name="AB2C1"/>
</categories>
</category>
</categories>
</category>
<category name="F">
<categories>
<category name="XY1">
<categories>
<category name="XY1Z1"/>
</categories>
</category>
<category name="XY2">
<categories>
<category name="XY2Z1">
<categories>
<category name="XY2Z1T1"/>
<category name="XY2Z3"/>
</categories>
</category>
<category name="XY2Z1"/>
</categories>
</category>
</categories>
</category>
</categories>