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

问题描述

我收集了一些物品:

<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 可以将前一个产品与当前产品进行比较,如果有匹配,则返回 true。基于这个返回值,我想:

  • 当返回值为for-each时,将true的当前元素加入前一个元素组
  • 关闭一个组,创建一个新组并在返回值为for-each时将当前的false循环元素添加到其中

我在如何创建组并在 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 处给出了想要的结果。

相关问答

Selenium Web驱动程序和Java。元素在(x,y)点处不可单击。其...
Python-如何使用点“。” 访问字典成员?
Java 字符串是不可变的。到底是什么意思?
Java中的“ final”关键字如何工作?(我仍然可以修改对象。...
“loop:”在Java代码中。这是什么,为什么要编译?
java.lang.ClassNotFoundException:sun.jdbc.odbc.JdbcOdbc...