在重复上层节点时,对xml / xslt中相同节点的子节点进行分组/合并

时间:2012-08-15 13:43:33

标签: xslt nodes

作为我的原始帖子Group/merge childs of same nodes in xml/xslt的补充,我遇到了为不同节点重复多次该结构的问题(在层次结构中更高的节点),例如,

<Collection>
    <Questionnaire Name="Preferences" VersionID="3QW">
        <Subject ID="2355">
            <EventData Name="First Part">
                <FormData Name="Past">
                    <GroupData ID="xxx" Key="4" Temp="yyy">
                        <ItemData ID="zzz" Value="3"/>
                    </GroupData>
                    <GroupData ID="xxx" Key="4" Temp="yyy">
                        <ItemData ID="qqq" Value="4"/>
                    </GroupData>
                    ...
                </FormData>
                <FormData Name="Present">
                    <GroupData ID="yyy" Key="9" Temp="yyy">
                        <ItemData ID="www" Value="32"/>
                    </GroupData>
                    ...
                </FormData>             
            </EventData>
            <EventData Name="SecondPart">
                ...
            </EventData>
        </Subject>
        <Subject ID="9812">
            ...
        </Subject>
    </Questionnaire>    
</Collection>   

尝试了我所接受的建议的变化以及其他一些我被困住的事情。我认为它与多个级别有关(并且GroupData分布在它将成为子节点的上/祖父节点上)然后它可能不再具有唯一ID。那么如何将每个GroupData节点的子节点放入一个GroupData节点(在ID上匹配,有时是Key,因为后者并不总是存在)?注意:必须将相同的GroupData节点(具有相应的属性)合并到每个FormData节点中的一个GroupData节点中。

1 个答案:

答案 0 :(得分:0)

以下是两个XSLT 1.0解决方案。

一个解决方案是从第一个问题中获取Dimite的解决方案,然后展开密钥以包含FormData ...

<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="FormData/GroupData"
  use="concat(@ID, '+', @Key, '+', generate-id(..))"/>

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

 <xsl:template match=
 "FormData/GroupData
    [generate-id()
    =
     generate-id(key('kGDByIdKey', concat(@ID, '+', @Key, '+', generate-id(..)))[1])
     ]">
    <xsl:copy>
      <xsl:apply-templates select=
       "@*|key('kGDByIdKey', concat(@ID, '+', @Key, '+', generate-id(..)))/node()"/>
    </xsl:copy>
 </xsl:template>

  <xsl:template match="GroupData"/>
</xsl:stylesheet>

另一个解决方案将分组测试从模板匹配条件移动到父FormData中调用xsl:apply-templates ...

<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="FormData/GroupData" use="concat(@ID, '+', @Key)" />

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

 <xsl:template match="FormData">
     <xsl:copy>
       <xsl:apply-templates select="
          @* |
          node()[not(self::GroupData)] |
          GroupData[generate-id() =
                    generate-id(key('kGDByIdKey', concat(@ID, '+', @Key))[1])]"/>
     </xsl:copy>
 </xsl:template>

 <xsl:template match="FormData/GroupData">
     <xsl:copy>
       <xsl:apply-templates select="@*|
           key('kGDByIdKey', concat(@ID, '+', @Key))/node()"/>
     </xsl:copy>
 </xsl:template>
  <xsl:template match="GroupData"/>
</xsl:stylesheet>

两个样式表都假设GroupData的父级只是FormData。任何没有FormData父级的GroupData都将被删除。