我试图让分组优化与xslt一起使用。优化应该将具有相同名称的项目收集到单个items元素中。当项目处于同一级别时,我可以使用它,但是一些输入将它们嵌套在任意级别,我无法弄清楚如何在这些情况下使分组工作。
这是一个有效的例子:
<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>
这是我的示例转换定义:
<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>
正确分组&#34; a&#34;项目在一起,离开&#34; c&#34;项目分开。 但是,如果&#34; a&#34;项目进一步嵌套,它们从结果中退出:
<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>
所需的结果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>
(如果存在多个带有&#39; c&#39;和&#39; x1&#39;的条目,它们也可以分组,但这不是必需的)
答案 0 :(得分:0)
您需要对所有元素进行分组,并确保那些没有密钥的元素以递归方式处理,这是尝试这样做的一次:
<?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>
如果可以有多个name
个元素构成分组键,那么使用XSLT 2.0,一种方法可以将string-join(item/name, '|')
计算为关键字(条|
应该被替换为适当的分隔符,确保它不会出现在name
s中。以下是首先对name
进行排序以确保<name>a</name><name>b</name>
和<name>b</name><name>a</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>