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 为真。基于这个返回值,我想:
- 当返回值为
true
时,将for-each
的当前元素添加到前一个元素的组中
- 关闭上一个组,创建一个新组并在返回值为
false
时将 for-each
循环的当前元素添加到它
我在如何创建组并在 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.0
和 saxon-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 处给出了想要的结果。
我有 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 为真。基于这个返回值,我想:
- 当返回值为
true
时,将 - 关闭上一个组,创建一个新组并在返回值为
false
时将
for-each
的当前元素添加到前一个元素的组中
for-each
循环的当前元素添加到它
我在如何创建组并在 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.0
和 saxon-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 处给出了想要的结果。