【问题标题】:Group/merge childs of same nodes in xml/xslt在 xml/xslt 中对相同节点的子节点进行分组/合并
【发布时间】:2012-08-07 15:47:18
【问题描述】:

我是 XSLT 的新手,手动更改它需要很长时间。

<GroupData ID="xxx" Key="4" Temp="yyy">
 <ItemData ID="zzz" Value="3"/>
</GroupData>

<GroupData ID="xxx" Key="4" Temp="yyy">
 <ItemData ID="www" Value="1982"/>
</GroupData>

我想让这些多个 GroupData 节点的子节点在同一个组中,即,

<GroupData ID="xxx" Key="4" Temp="yyy">
 <ItemData ID="zzz" Value="3"/>
 <ItemData ID="www" Value="1982"/>
</GroupData>

所以我需要在 GroupData 的 ID 和 Key 属性上合并/组合/匹配它们(这些在文件中有所不同)。还有一些没有 Key 属性。我怎样才能做到这一点?我阅读了一些其他线程(例如,在 C# 中,但我没有可用的)并且我检查了 W3 学校,但这些都是非常基本的示例。我正在使用 Notepad++ 的最新 XML Tools 2.3.2 r908 unicode (beta4) 来应用可能的转换(不知道它是否支持 XSLT2.0 或 XSLT1.0)。

编辑:在尝试了以下建议和各种事情后,我被卡住了,因为它有多个级别并且可能没有唯一的 ID: ...

【问题讨论】:

  • 您可以使用 XSLT2.0,还是只使用 XSLT1.0? XSLT2.0 具有用于分组的特定元素,这些元素在 XSLT1.0 中不存在。在 XSLT1.0 中,您必须使用一种称为 Muenchian Grouping 的技术。

标签: xml xslt merge nodes


【解决方案1】:

如果是 XSLT 2.0 那么你可以使用嵌套的&lt;xsl:for-each-group&gt;

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:template match="/">
    <Groups>
      <xsl:for-each-group select="/Groups/GroupData" group-by="@ID">
        <xsl:for-each-group select="current-group()" group-by="if(@Key) then @Key else 'no key'">
          <GroupData>
            <!-- Copy attributes off the *first* GroupData element in the group -->
            <xsl:copy-of select="current-group()[1]/@*"/>
            <!-- Copy ItemData children from *all* GroupData elements in the group -->
            <xsl:copy-of select="current-group()/ItemData" />
          </GroupData>
        </xsl:for-each-group>
      </xsl:for-each-group>
    </Groups>
  </xsl:template>
</xsl:stylesheet>

(我假设您的输入文件有一个根元素 &lt;Groups&gt; 并且不使用命名空间)。

如果是 XSLT 1.0 那么你需要使用Muenchian Grouping:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:key name="group-data" match="GroupData" use="concat(@ID, '___', @Key)" />
  <xsl:template match="/">
    <Groups>
      <!--
      Iterate over a node set containing just one GroupData element for
      each combination of ID and Key
      -->
      <xsl:for-each select="/Groups/GroupData[count( . | key('group-data', concat(@ID, '___', @Key))[1]) = 1]">
        <GroupData>
          <!-- Copy attributes from the "prototype" GroupData -->
          <xsl:copy-of select="@*"/>
          <!--
          Copy ItemData children from *all* GroupData elements with matching
          ID/Key
          -->
          <xsl:copy-of select="key('group-data', concat(@ID, '___', @Key))/ItemData" />
        </GroupData>
      </xsl:for-each>
    </Groups>
  </xsl:template>
</xsl:stylesheet>

在这里,我通过创建{ID}___{Key} 的合成key 值来基于 ID 和 Key 属性进行一次分组传递。

【讨论】:

    【解决方案2】:

    这个 XSLT 1.0 转换

    <xsl:stylesheet version="1.0"
     xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
     <xsl:output omit-xml-declaration="yes" indent="yes"/>
     <xsl:strip-space elements="*"/>
    
     <xsl:key name="kGDByIdKey" match="GroupData"
      use="concat(@ID, '+', @Key)"/>
    
     <xsl:template match="node()|@*">
         <xsl:copy>
           <xsl:apply-templates select="node()|@*"/>
         </xsl:copy>
     </xsl:template>
    
     <xsl:template match=
     "GroupData
        [generate-id()
        =
         generate-id(key('kGDByIdKey', concat(@ID, '+', @Key))[1])
         ]">
        <xsl:copy>
          <xsl:apply-templates select=
           "@*|key('kGDByIdKey', concat(@ID, '+', @Key))/node()"/>
        </xsl:copy>
     </xsl:template>
    
      <xsl:template match="GroupData"/>
    </xsl:stylesheet>
    

    应用于此 XML 文档时:

    <t>
        <GroupData ID="xxx" Key="4" Temp="yyy">
            <ItemData ID="zzz" Value="3"/>
        </GroupData>
        <GroupData ID="yyy" Key="4" Temp="yyy">
            <ItemData ID="abc" Value="3"/>
        </GroupData>
        <GroupData ID="zzz" Temp="yyy">
            <ItemData ID="pqr" Value="1982"/>
        </GroupData>
        <GroupData ID="xxx" Key="4" Temp="yyy">
            <ItemData ID="www" Value="1982"/>
        </GroupData>
        <GroupData ID="yyy" Key="4" Temp="yyy">
            <ItemData ID="def" Value="1982"/>
        </GroupData>
        <GroupData ID="zzz" Temp="yyy">
            <ItemData ID="tuv" Value="1982"/>
        </GroupData>
    </t>
    

    产生想要的正确结果

    <t>
       <GroupData ID="xxx" Key="4" Temp="yyy">
          <ItemData ID="zzz" Value="3"/>
          <ItemData ID="www" Value="1982"/>
       </GroupData>
       <GroupData ID="yyy" Key="4" Temp="yyy">
          <ItemData ID="abc" Value="3"/>
          <ItemData ID="def" Value="1982"/>
       </GroupData>
       <GroupData ID="zzz" Temp="yyy">
          <ItemData ID="pqr" Value="1982"/>
          <ItemData ID="tuv" Value="1982"/>
       </GroupData>
    </t>
    

    解释

    正确使用 Muenchian grouping methodidentity rule

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2015-05-15
      • 2021-03-14
      • 1970-01-01
      • 1970-01-01
      • 2018-04-20
      • 1970-01-01
      • 2013-08-15
      相关资源
      最近更新 更多