xslt 按函数分组或追加到数组

xslt group by function or append to array

我有 collection 件物品:

<items>
    <result>
        <item>
            <product_name>some description</product_name>
        </item>
        <item>
            <product_name>some similar description</product_name>
        </item>
        <item>
            <product_name>other product size 1</product_name>
        </item>
        <item>
            <product_name>other product size 2</product_name>
        </item>
    </result>
</items>

我还有一些外部函数 strdist:string-distance 可以将以前的产品与当前的产品进行比较,如果有一些匹配,则它 returns 为真。基于这个返回值,我想:

我在如何创建组并在 for-loop 中添加元素的过程中遇到了一些困难。

这是我的模板

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
                xmlns:strdist="http://example.com/string-distance"
                exclude-result-prefixes="strdist">

    <xsl:output method="xml" indent="yes" omit-xml-declaration="yes"/>

    <xsl:template match="/">
        <xsl:variable name="items" as="element()*">
            <xsl:perform-sort select="items/result/item">
                <xsl:sort select="./product_name"/>
            </xsl:perform-sort>
        </xsl:variable>
        <xsl:variable name="groupedItems" as="element()*">
            <groups>
                <xsl:for-each select="$items">
                    <xsl:variable name="position" select="position()"/>
                    <xsl:variable name="currentProductName" select="./product_name/text()"/>
                    <xsl:choose>
                        <xsl:when test="$position -1 = 0">
                            <xsl:element name="group"/>
                            <xsl:message select="concat($position, ' # ', $currentProductName)"/>
                        </xsl:when>
                        <xsl:when test="$position -1 > 0">
                            <xsl:variable name="previousProductName"
                                          select="$items[position() = $position -1]/product_name/text()"/>
                            <xsl:message
                                    select="concat($position, ' # ', $previousProductName, ' # ', $currentProductName)"/>
                            <xsl:message select="strdist:string-distance($previousProductName, $currentProductName)"/>
                        </xsl:when>
                    </xsl:choose>
                </xsl:for-each>
            </groups>
        </xsl:variable>
        <xsl:message select="$groupedItems" />
    </xsl:template>
</xsl:stylesheet>

最后我想要这样的东西:

<items>
    <result>
        <group>
            <item>
                <product_name>some description</product_name>
            </item>
            <item>
                <product_name>some similar description</product_name>
            </item>
        </group>
        <group>
            <item>
                <product_name>other product size 1</product_name>
            </item>
            <item>
                <product_name>other product size 2</product_name>
            </item>
        </group>
    </result>
</items>

我正在使用 xslt 2.0saxon-he 10.3

这是使用 for-each-group group-starting-with 和示例函数的示例:

<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="#all"
    version="3.0">

  <xsl:mode on-no-match="shallow-copy"/>

  <xsl:output method="xml" indent="yes"/>
  
  <xsl:function name="mf:string-distance" as="xs:boolean">
      <xsl:param name="name1" as="xs:string"/>
      <xsl:param name="name2" as="xs:string"/>
      <xsl:sequence select="tokenize($name1)[1] = tokenize($name2)[1]"/>
  </xsl:function>

  <xsl:template match="result">
      <xsl:copy>
          <xsl:for-each-group select="item" group-starting-with="item[not(mf:string-distance(product_name, preceding-sibling::item[1]/product_name))]">
              <group>
                  <xsl:apply-templates select="current-group()"/>
              </group>
          </xsl:for-each-group>
      </xsl:copy>
  </xsl:template>
  
</xsl:stylesheet>

似乎在 https://xsltfiddle.liberty-development.net/bEJbVrR 处给出了想要的结果。