与子节点分组的问题

时间:2015-02-06 08:53:36

标签: xslt

我是XSL的新手,面临着使用相同名称对xml元素进行分组的问题。 这是我的输入xml元素

<Products>
 <Product type='Item' id='111'>
    <Group1>
        <color>Blue</color>
        <item>xxx</item>
    </Group1>
    <Group1>
        <color>Green</color>
            <item>yyy</item>
    </Group1>
    <Group2>
        <color>Yellow</color>
        <item>xxx</item>
    </Group2>
    <Group2>
        <color>White</color>
            <item>yyy</item>
    </Group2>
     <Product type='ChildItem'>
        <Group1>
            <color>Blue</color>
            <item>xxx</item>
        </Group1>
        <Group1>
            <color>Green</color>
                <item>yyy</item>
        </Group1>
        <Group2>
            <color>Yellow</color>
            <item>xxx</item>
        </Group2>
        <Group2>
            <color>White</color>
                <item>yyy</item>
        </Group2>
    </Product>
 </Product>
 <Product type='Item' id='222'>
    <Group1>
        <color>Blue</color>
        <item>xxx</item>
    </Group1>
    <Group1>
        <color>Green</color>
            <item>yyy</item>
    </Group1>
    <Group2>
        <color>Yellow</color>
        <item>xxx</item>
    </Group2>
    <Group2>
        <color>White</color>
            <item>yyy</item>
    </Group2>
     <Product type='ChildItem'>
        <Group1>
            <color>Blue</color>
            <item>xxx</item>
        </Group1>
        <Group1>
            <color>Green</color>
                <item>yyy</item>
        </Group1>
        <Group2>
            <color>Yellow</color>
            <item>xxx</item>
        </Group2>
        <Group2>
            <color>White</color>
                <item>yyy</item>
        </Group2>
    </Product>
</Products>

我们正试图获得如下输出:

<Products>
 <Product type='Item' id='111'>
    <Group1>
        <color>Blue</color>
        <item>xxx</item>
        <color>Green</color>
            <item>yyy</item>
    </Group1>
    <Group2>
        <color>Yellow</color>
        <item>xxx</item>
        <color>White</color>
            <item>yyy</item>
    </Group2>
    <Product type='ChildItem'>
        <Group1>
            <color>Blue</color>
            <item>xxx</item>
            <color>Green</color>
             <item>yyy</item>
        </Group1>
        <Group2>
             <color>Yellow</color>
            <item>xxx</item>
            <color>White</color>
             <item>yyy</item>
        </Group2>
    </Product>
 </Product>
 <Product type='Item' id='222'>
    <Group1>
        <color>Blue</color>
        <item>xxx</item>
        <color>Green</color>
            <item>yyy</item>
    </Group1>
    <Group2>
        <color>Yellow</color>
        <item>xxx</item>
        <color>White</color>
            <item>yyy</item>
    </Group2>
    <Product type='ChildItem'>
        <Group1>
            <color>Blue</color>
            <item>xxx</item>
            <color>Green</color>
             <item>yyy</item>
        </Group1>
        <Group2>
             <color>Yellow</color>
            <item>xxx</item>
            <color>White</color>
             <item>yyy</item>
        </Group2>
    </Product>
 </Product>
</Products>  

我使用下面的xsl文件进行转换,但未按预期获得输出

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:key name="elements" match="/Product/*" use="name()"/>
<xsl:template match="@* | node()">
    <xsl:copy>
        <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
</xsl:template>
<xsl:template match="/*">
    <xsl:copy>
        <xsl:for-each select="*[count(. | key('elements', name())[1]) = 1]">
            <xsl:copy>
                <xsl:apply-templates select="key('elements', name())/*"/>
            </xsl:copy>
        </xsl:for-each>
    </xsl:copy>
</xsl:template>
</xsl:stylesheet> 

1 个答案:

答案 0 :(得分:1)

您要按名称对Product的子元素进行分组,但是这个分组需要针对每个产品单独进行,因此您需要引用Product是关键用法

<xsl:key name="elements" 
         match="Product/*[not(self::Product)]" 
         use="concat(name(), '|', generate-id(..))"/>

注意密钥匹配如何没有/前缀,否则它只匹配一个名为Product的根元素,它在您的情况下不会匹配。还要注意它是如何仅与非Product元素匹配的。

(也不是使用generate-id()Product元素生成一个唯一ID来识别它?

接下来,您需要更改第二个模板以匹配Product,而不是\*,因为\*仅匹配根元素。然后在此模板中,您将获得如下所示的分组元素:

<xsl:for-each 
     select="*[generate-id() = generate-id(key('elements', concat(name(), '|', generate-id(..)))[1])]">

试试这个XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output method="xml" indent="yes"/>
<xsl:key name="elements" match="Product/*[not(self::Product)]" use="concat(name(), '|', generate-id(..))"/>

<xsl:template match="@* | node()">
    <xsl:copy>
        <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="Product">
    <xsl:copy>
        <xsl:apply-templates select="@*" />
        <xsl:for-each select="*[generate-id() = generate-id(key('elements', concat(name(), '|', generate-id(..)))[1])]">
            <xsl:copy>
                <xsl:apply-templates select="key('elements', concat(name(), '|', generate-id(..)))/*"/>
            </xsl:copy>
        </xsl:for-each>
        <xsl:apply-templates select="Product" />
    </xsl:copy>
</xsl:template>
</xsl:stylesheet>