2012-08-10 99 views
4

我是XSLT的新手,并且手动进行更改将花费大量时间。在xml/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属性。我怎样才能做到这一点?我阅读了其他一些主题(例如,在C#中,但我没有这些主题),并检查了W3学校,但这些都是非常基本的示例。我正在使用Notepad ++的最新XML Tools 2.3.2 r908 unicode(beta4)来应用可能的转换(不知道它是否支持XSLT2.0或XSLT1.0)。

编辑:尝试下面的建议和各种事情之后,我坚持,因为它具有多层次,多possiblly不具有唯一ID: ...

+1

您是否可以使用XSLT2.0或XSLT1.0? XSLT2.0具有用于分组的特定元素,这些元素在XSLT1.0中不存在。在XSLT1.0中,您必须使用称为Muenchian分组的技术。 – 2012-08-10 11:05:12

回答

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

6

如果是XSLT 2.0,那么你可以使用嵌套<xsl:for-each-group>

<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> 

(我假设你的输入文件有一个根元素<Groups>和不使用命名空间)。

如果它是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,并通过创建的{ID}___{Key}合成key值的关键属性的单一分组通。

相关问题