XSLT 中的排列

Permutation in XSLT

我确定答案会是某种 'recursion' 不过我正在努力做到这一点 -- 对于一组节点,我想 return 他们所有的排列:

输入:

<animals>       
            <animal>Rabbit</animal>
            <animal>Turtle</animal>
            <animal>Moose</animal>
    </animals>

期望的输出:

MooseRabbitTurtle
MooseTurtleRabbit
RabbitMooseTurtle
RabbitTurtleMoose
TurtleMooseRabbit
TurtleRabbitMoose

请注意按字母顺序排序,但如果这不可能,我也可以没有它。此外,不会总是有 3 个输入节点,因此理想情况下它可以使用任意数量的节点

感谢您指出正确的方向!

这是一个 XSLT 2.0 样式表示例

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:mf="http://example.com/mf"
    exclude-result-prefixes="xs mf"
    version="2.0">

    <xsl:output indent="yes"/>

    <xsl:function name="mf:permute" as="item()*">
        <xsl:param name="head" as="item()*"/>
        <xsl:param name="tail" as="item()*"/>
        <xsl:choose>
            <xsl:when test="count($tail) eq 1">
                <permutation>
                    <xsl:for-each select="$head, $tail">
                        <item>
                            <xsl:value-of select="."/>
                        </item>
                    </xsl:for-each>
                </permutation>
            </xsl:when>
            <xsl:otherwise>
                <xsl:sequence select="for $pos in (1 to count($tail)) return mf:permute(($head, $tail[$pos]), $tail[position() ne $pos])"/>
            </xsl:otherwise>
        </xsl:choose>
    </xsl:function>

    <xsl:function name="mf:permutations" as="element(permutations)">
        <xsl:param name="input" as="item()*"/>
        <permutations>
            <xsl:sequence select="for $pos in (1 to count($input)) return mf:permute($input[$pos], $input[position() ne $pos])"/>
        </permutations>
    </xsl:function>

    <xsl:template match="animals">
        <xsl:variable name="sorted-animals" as="element(animal)*">
            <xsl:perform-sort select="animal">
                <xsl:sort select="."/>
            </xsl:perform-sort>
        </xsl:variable>
        <xsl:copy-of select="mf:permutations($sorted-animals)"/>
    </xsl:template>

</xsl:stylesheet>

转换输入

<animals>       
    <animal>Rabbit</animal>
    <animal>Turtle</animal>
    <animal>Moose</animal>
</animals>

进入输出

<permutations>
   <permutation>
      <item>Moose</item>
      <item>Rabbit</item>
      <item>Turtle</item>
   </permutation>
   <permutation>
      <item>Moose</item>
      <item>Turtle</item>
      <item>Rabbit</item>
   </permutation>
   <permutation>
      <item>Rabbit</item>
      <item>Moose</item>
      <item>Turtle</item>
   </permutation>
   <permutation>
      <item>Rabbit</item>
      <item>Turtle</item>
      <item>Moose</item>
   </permutation>
   <permutation>
      <item>Turtle</item>
      <item>Moose</item>
      <item>Rabbit</item>
   </permutation>
   <permutation>
      <item>Turtle</item>
      <item>Rabbit</item>
      <item>Moose</item>
   </permutation>
</permutations>

函数mf:permutations获取输入序列(在将其传递给函数之前可以按所示排序),然后为序列中的每个项目计算由该项目形成的序列的可能排列和递归调用传递除了项目之外的序列。

使用 Saxon 9.7 支持的 XSLT 3.0,我们可以缩短代码和 return 数组序列,而不是具有排列的 XML 结构:

<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:xs="http://www.w3.org/2001/XMLSchema"
    xmlns:math="http://www.w3.org/2005/xpath-functions/math"
    xmlns:array="http://www.w3.org/2005/xpath-functions/array"
    xmlns:mf="http://example.com/mf"
    exclude-result-prefixes="xs math array mf"
    version="3.0">

    <xsl:output method="adaptive"/>

    <xsl:function name="mf:permute" as="array(*)*">
        <xsl:param name="head" as="array(*)"/>
        <xsl:param name="tail" as="item()*"/>
        <xsl:sequence select="if (count($tail) eq 1)
                              then array:append($head, $tail)
                              else for $pos in (1 to count($tail)) return mf:permute(array:append($head, $tail[$pos]), $tail[position() ne $pos])"/>
    </xsl:function>

    <xsl:function name="mf:permutations" as="array(*)*">
        <xsl:param name="input" as="xs:untypedAtomic*"/>
        <xsl:sequence select="mf:permute([], $input)"/>     
    </xsl:function>

    <xsl:template match="animals">
        <xsl:sequence select="mf:permutations(sort(animal))"/>
    </xsl:template>

</xsl:stylesheet>

这样的结果是

["Moose","Rabbit","Turtle"]
["Moose","Turtle","Rabbit"]
["Rabbit","Moose","Turtle"]
["Rabbit","Turtle","Moose"]
["Turtle","Moose","Rabbit"]
["Turtle","Rabbit","Moose"]