XML 通过根据某个值对标签进行分组,使用 XSLT 进行转换

XML transformation using XSLT by grouping the tags based on some value

我正在尝试通过对标签进行分组来创建新标签来转换一个 XML。喜欢将具有相同父值的项目分组。

 <root>
   <item id="100">
      <properties>
         <property attribute-id="parent">10</property>
      </properties>
      <properties>
         <property attribute-id="amount">1.1</property>
      </properties>
   </item>
   <item id="101">
      <properties>
         <property attribute-id="parent">10</property>
      </properties>
      <properties>
         <property attribute-id="amount">1.1</property>
      </properties>
   </item>
   <item id="102">
      <properties>
         <property attribute-id="parent">11</property>
      </properties>
      <properties>
         <property attribute-id="amount">1.1</property>
      </properties>
   </item>
   <item id="103">
      <properties>
         <property attribute-id="parent">10</property>
      </properties>
      <properties>
         <property attribute-id="amount">1.1</property>
      </properties>
   </item>
   <item id="104">
      <properties>
         <property attribute-id="parent">11</property>
      </properties>
      <properties>
         <property attribute-id="amount">1.1</property>
      </properties>
   </item>
</root>

新标签应该是:

<item id = "10">  
       <childs>
         <child id="100" />
         <child id="101" />
         <child id="102" />
       </childs>
    </item>       
    <item id = "11">
       <childs>
         <child id="104" />
         <child id="105" />
       </childs>
    </item> 

这可以用 XSLT 实现吗?
这如何在 XSLT 中完成?

编辑初始 post 当标签为属性格式时,我遇到了一些问题。尝试更新第一个解决方案,但属性形式导致许多问题。

您可以使用 XSLT-1.0 方法 Muenchian Grouping 来实现。如果你搜索 SO,你会发现很多例子。应用此方法,您的样式表可能如下所示(我在源代码 XML 周围添加了一个假设的 <root> 元素以使其 格式正确 ):

外部 xsl:for-eachxsl:keyselect 表达式确实实现了 Muenchian 分组。循环内部应该有点不言自明。

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>
<xsl:key name="id" match="item" use="properties/property[@attribute-id='parent']" />   

<xsl:template match="/root">
    <xsl:copy>
        <xsl:for-each select="item[generate-id() = generate-id(key('id',properties/property[@attribute-id='parent'])[1])]">
            <item id="{parent}">
                <childs>
                    <xsl:for-each select="key('id',properties/property[@attribute-id='parent'])">
                        <child id="{@id}" />
                    </xsl:for-each>
                </childs>
            </item>
        </xsl:for-each>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

如果您可以使用 XSLT-2.0 或更高版本,您可以像这样使用 xsl:for-each-group

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:output indent="yes"/>

<xsl:template match="/root">
    <xsl:copy>
        <xsl:for-each-group select="item" group-by="properties/property[@attribute-id='parent']">
            <item id="{parent}">
                <childs>
                    <xsl:for-each select="current-group()">
                        <child id="{@id}" />
                    </xsl:for-each>
                </childs>
            </item>
        </xsl:for-each-group>
    </xsl:copy>
</xsl:template>

</xsl:stylesheet>

它稍微简单一些,但功能相同。


它的输出,在这两种情况下,都是:

<?xml version="1.0" encoding="UTF-8"?>
<root>
   <item id="">
      <childs>
         <child id="100"/>
         <child id="101"/>
         <child id="103"/>
      </childs>
   </item>
   <item id="">
      <childs>
         <child id="102"/>
         <child id="104"/>
      </childs>
   </item>
</root>

这不是您想要的,但我猜您示例的最后一个 child ID 是错误的。