xslt在多个嵌套级别按名称对类似项进行分组
我正在尝试使用xslt进行分组优化。优化应该将具有相同名称的项收集到单个items元素中。当所有项都在同一级别时,我可以使用它,但是一些输入将它们嵌套在任意级别,我不知道在这些情况下如何使分组工作 下面是一个工作示例:xslt在多个嵌套级别按名称对类似项进行分组,xslt,Xslt,我正在尝试使用xslt进行分组优化。优化应该将具有相同名称的项收集到单个items元素中。当所有项都在同一级别时,我可以使用它,但是一些输入将它们嵌套在任意级别,我不知道在这些情况下如何使分组工作 下面是一个工作示例: <process> <op> <group> <op> <item> <name>a</name>
<process>
<op>
<group>
<op>
<item>
<name>a</name>
<detail><value>1</value></detail>
</item>
</op>
<op>
<item>
<name>a</name>
<detail><value>2</value></detail>
</item>
</op>
<op>
<item>
<name>c</name>
<name>x1</name>
<detail><value>3</value></detail>
</item>
</op>
</group>
</op>
A.
1.
A.
2.
C
x1
3.
下面是我的示例转换定义:
<xs:template match="group[op[item[detail]]]">
<xs:copy>
<xs:for-each-group select="op" group-by="item/name">
<op><item>
<xs:copy-of select="item/name"/>
<xs:choose>
<xs:when test="count(current-group()) > 1">
<details>
<xs:for-each select="current-group()">
<detail><value>
<xs:value-of select="item/detail/value"/>
</value></detail>
</xs:for-each>
</details>
</xs:when>
<xs:otherwise>
<detail><value>
<xs:value-of select="item/detail/value"/>
</value></detail>
</xs:otherwise>
</xs:choose>
</item></op>
</xs:for-each-group>
</xs:copy>
</xs:template>
<xs:template match="@*|node()">
<xs:copy>
<xs:apply-templates select="@*|node()"/>
</xs:copy>
</xs:template>
将“a”项正确分组在一起,将“c”项分开。
但是,如果“a”项被进一步嵌套,它们将从结果中删除:
<process>
<op>
<group>
<op>
<group>
<op>
<item>
<name>a</name>
<detail><value>1</value></detail>
</item>
</op>
<op>
<item>
<name>a</name>
<detail><value>2</value></detail>
</item>
</op>
</group>
</op>
<op>
<item>
<name>c</name>
<name>x1</name>
<detail><value>3</value></detail>
</item>
</op>
</group>
</op>
A.
1.
A.
2.
C
x1
3.
所需的结果XML是:
<process>
<op>
<group>
<op>
<group>
<op>
<item>
<name>a</name>
<details>
<detail><value>1</value></detail>
<detail><value>2</value></detail>
</details>
</item>
</op>
</group>
</op>
<op>
<item>
<name>c</name>
<name>x1</name>
<detail><value>3</value></detail>
</item>
</op>
</group>
</op></process>
A.
1.
2.
C
x1
3.
(如果存在多个带有“c”和“x1”的条目,也可以对它们进行分组,但这不是一项要求)您需要对所有元素进行分组,并确保递归处理那些没有键的元素,下面是一种尝试:
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
exclude-result-prefixes="xs">
<xsl:strip-space elements="*"/>
<xsl:output indent="yes"/>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="group[op[item[detail]]]">
<xsl:copy>
<xsl:for-each-group select="*" group-by="string(item/name)">
<xsl:choose>
<xsl:when test="current-grouping-key() eq ''">
<xsl:apply-templates select="current-group()"/>
</xsl:when>
<xsl:otherwise>
<xsl:copy>
<item>
<xsl:copy-of select="item/name"/>
<xsl:choose>
<xsl:when test="current-group()[2]">
<details>
<xsl:copy-of select="current-group()/item/detail"/>
</details>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="item/detail"/>
</xsl:otherwise>
</xsl:choose>
</item>
</xsl:copy>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>
您需要显示并解释您想要的最后一个输入样本的结果,我不清楚。添加了所需的结果XML,因此您希望保留层次结构,并基本上对每个
组中的op
元素进行分组。如果有一些op
元素带有项
c
,然后是嵌套组,然后是一些op
元素带有项
,会发生什么情况?你想把所有的c
项目组合在一起,基本上把后面的元素拉起来吗?或者,如果原始XML中的op
元素相邻,您是否只想使用相同的item
对它们进行分组?只需要在原始XML中相邻。这适用于我的所有测试用例,但某些项具有多个name元素的情况除外(抱歉,我没有包括示例)。当存在多个名称时,它在string()调用中出错。只有在所有名称都匹配的情况下,它才应该组合这些项目。您是否可以编辑问题,并用多个名称显示示例和相应的结果?这些名字是排序的还是可排序的?我正在考虑使用例如groupby=“string join(item/name,“|”)”
,只有对名称进行排序,或者至少可以对名称进行排序,以获得一种指纹来对祖先进行分组。
<xsl:stylesheet
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
version="2.0"
xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:mf="http://example.com/mf"
exclude-result-prefixes="xs mf">
<xsl:param name="separator" as="xs:string" select="'|'"/>
<xsl:strip-space elements="*"/>
<xsl:output indent="yes"/>
<xsl:function name="mf:sort" as="xs:string*">
<xsl:param name="input"/>
<xsl:perform-sort select="$input">
<xsl:sort select="."/>
</xsl:perform-sort>
</xsl:function>
<xsl:template match="@*|node()">
<xsl:copy>
<xsl:apply-templates select="@*|node()"/>
</xsl:copy>
</xsl:template>
<xsl:template match="group[op[item[detail]]]">
<xsl:copy>
<xsl:for-each-group select="*" group-by="string-join(mf:sort(item/name), $separator)">
<xsl:choose>
<xsl:when test="current-grouping-key() eq ''">
<xsl:apply-templates select="current-group()"/>
</xsl:when>
<xsl:otherwise>
<xsl:copy>
<item>
<xsl:copy-of select="item/name"/>
<xsl:choose>
<xsl:when test="current-group()[2]">
<details>
<xsl:copy-of select="current-group()/item/detail"/>
</details>
</xsl:when>
<xsl:otherwise>
<xsl:copy-of select="item/detail"/>
</xsl:otherwise>
</xsl:choose>
</item>
</xsl:copy>
</xsl:otherwise>
</xsl:choose>
</xsl:for-each-group>
</xsl:copy>
</xsl:template>
</xsl:stylesheet>