この 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"
xmlns:my="my:my">
<xsl:output omit-xml-declaration="yes" indent="yes"/>
<xsl:strip-space elements="*"/>
<xsl:template match="node()|@*">
<xsl:copy>
<xsl:apply-templates select="node()|@*"/>
</xsl:copy>
</xsl:template>
<xsl:template match=
"subelement
[not(key eq my:max(../subelement/key))
or
key = preceding-sibling::subelement/key
]"/>
<xsl:function name="my:max" as="xs:string">
<xsl:param name="pValues" as="xs:string+"/>
<xsl:sequence select=
"if(not(distinct-values($pValues)[2]))
then $pValues[1]
else
for $vMax1 in
max(for $s in $pValues
return
xs:integer(substring-before(concat($s,'.'),'.'))
),
$vcntMax1Values in
count($pValues[starts-with(., string($vMax1))])
return
if($vcntMax1Values eq 1)
then $pValues[starts-with(., string($vMax1))]
[1]
else
for $submax in
(my:max(for $val in
$pValues[starts-with(., string($vMax1))]
[contains(., '.')],
$subval in substring-after($val, '.')
return
$subval
)
)
return
concat($vMax1, '.', $submax)
"/>
</xsl:function>
</xsl:stylesheet>
この変換が次の XML ドキュメント(より興味深いものにするために拡張された、提供されたもの) に適用されると、次のようになります。
<root>
<element>
<name>Foo</name>
<subelement>
<key>1.1</key>
<value>Lorem ipsum</value>
</subelement>
<subelement>
<key>1.2</key>
<value>Lorem ipsum dolor</value>
</subelement>
</element>
<element>
<name>Bar</name>
<subelement>
<key>7.3.4</key>
<value>Seven three four</value>
</subelement>
<subelement>
<key>7.3.8</key>
<value>Seven three eight</value>
</subelement>
<subelement>
<key>7.3.8.1</key>
<value>Seven three eight one</value>
</subelement>
<subelement>
<key>7.3.8.1</key>
<value>Seven three eight one</value>
</subelement>
<subelement>
<key>7.1</key>
<value>Seven one</value>
</subelement>
<subelement>
<key>10.1</key>
<value>Ten one</value>
</subelement>
<subelement>
<key>10.1</key>
<value>Ten one</value>
</subelement>
</element>
</root>
必要な正しい結果が生成されます。
<root>
<element>
<name>Foo</name>
<subelement>
<key>1.2</key>
<value>Lorem ipsum dolor</value>
</subelement>
</element>
<element>
<name>Bar</name>
<subelement>
<key>10.1</key>
<value>Ten one</value>
</subelement>
</element>
</root>
説明:
この一般的なソリューションの核となるのは、my:max()
「構造化された値」の空でないシーケンス (構造化された値は、「.」文字で結合された正の整数のシーケンスです) を指定すると、(多くの可能な値のうちの) 1 つを生成する関数です。最大値。
この関数は再帰的です。次のことを行います。
渡された値がすべて同一の場合、最初の値が返されます。
それ以外の場合は、最初のコンポーネントの最大値を見つけます。
見つかった最大値を持つ最初のコンポーネントを持つ値が 1 つだけの場合は、この値を返します。
それ以外の場合は、最大の最初のコンポーネントを持つすべての値の「テール」の最大値を (再帰的に) 見つけます。
最後に、最初のコンポーネントの最大値を、前のステップで見つかった「テール」の最大値と結合し、この値を返します。