使用XSLT基于XML属性的值对XML内的节点进行分组

时间:2013-12-02 17:05:29

标签: xml xslt

我对XSL很新,需要一些帮助。我有一个XML文件需要转换如下: exisitng文件:

<root>
    <highernode> 
        <highernodename>Name1</highernodename>
        <highernodeId>Id1</highernodeId>
            <node name="node1">
                <somechild child-id="1"/>
            </node>
            <node name="node2">
                <somechild child-id="2"/>
            </node>
            <node name="node3">
                <somechild child-id="1"/>
            </node>
            <node name="node4">
                <somechild child-id="2"/>
            </node>
            <node name="node5">
                <somechild child-id="3"/>
            </node>
    </highernode>

    <highernode>
        <highernodename>Name2</highernodename>
        <highernodeId>Id2</highernodeId>
            <node name="node1">
                <somechild child-id="1"/>
            </node>
            <node name="node2">
                <somechild child-id="5"/>
            </node>
            <node name="node3">
                <somechild child-id="5"/>
            </node>
            <node name="node6">
                <somechild child-id="4"/>
            </node>
            <node name="node5">
                <somechild child-id="3"/>
        </node>
    </highernode>
</root>

必须成为这样的东西:

    <root>
        <highernode>
            <highernodename>Name1</highernodename>
            <highernodeId>Id1</highernodeId>
                <somechild>1
                    <node>node1</node>
                    <node>node3</node>
                </somechild>
                <somechild>2
                    <node>node2</node>
                    <node>node4</node>
                </somechild>
                <somechild>3
                    <node>node5</node>
                </somechild>
        </highernode>

    <highernode>
        <highernodename>Name2</highernodename>
        <highernodeId>Id2</highernodeId>
            <somechild>1
                <node>node1</node>
            </somechild>
            <somechild>5
                <node>node2</node>
                <node>node3</node>
            </somechild>   
            <somechild>4
                <node>node6</node>
            </somechild> 
            <somechild>3
                <node>node5</node>
            </somechild>
    </highernode>
</root>

换句话说,在每个高节点中,我必须将属性somechild切换到节点,保持顺序,然后检查是否有几个具有相同值的子节点,并且在这种情况下,将它们的前节点分组同一个孩子。 在阅读了这个主题之后:Grouping XML nodes by attribute value in XSLT 它有所帮助,但是,经过一段时间的调整以满足自己的需求,我遇到了一些问题。我的XSL看起来像这样:

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

    <xsl:key name="k" match="somechild" use="@child-id"/>
    <xsl:key name="n" match="node" use="somechild/@child-id"/>

    <xsl:template match="root/highernode">
        <xsl:copy>
            <xsl:copy-of select="highernodename"/>
            <xsl:copy-of select="highernodeId"/>
            <xsl:apply-templates 
                select="//somechild[generate-id(.) = generate-id(key('k', @child-id))]"/>
        </xsl:copy>
    </xsl:template>

    <xsl:template match="somechild">
        <xsl:copy>
            <xsl:apply-templates select="@*"/>
                <xsl:apply-templates select="key('n', @child-id)"/>
        </xsl:copy>
    </xsl:template>

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

</xsl:stylesheet>

结果如下:

    <highernode>
   <highernodename>Name1</highernodename>
   <highernodeId>Id1</highernodeId>
   <somechild>1<node>node1</node>
      <node>node3</node>
      <node>node1</node>
   </somechild>
   <somechild>2<node>node2</node>
      <node>node4</node>
   </somechild>
   <somechild>3<node>node5</node>
      <node>node5</node>
   </somechild>
   <somechild>5<node>node2</node>
      <node>node3</node>
   </somechild>
   <somechild>4<node>node6</node>
   </somechild>
</highernode>

    <highernode>
   <highernodename>Name2</highernodename>
   <highernodeId>Id2</highernodeId>
   <somechild>1<node>node1</node>
      <node>node3</node>
      <node>node1</node>
   </somechild>
   <somechild>2<node>node2</node>
      <node>node4</node>
   </somechild>
   <somechild>3<node>node5</node>
      <node>node5</node>
   </somechild>
   <somechild>5<node>node2</node>
      <node>node3</node>
   </somechild>
   <somechild>4<node>node6</node>
   </somechild>
</highernode>

如您所见,有两个问题: 1)在每个较高节点中,它从所有较高节点而不是当前节点带来“somechild”和“node” 2)它在自己的值之后命令“somechild”(参见highnode2,somechild3应该是last,但它不是。

我希望我已经足够清楚。

谢谢你, 米哈伊

1 个答案:

答案 0 :(得分:0)

如果要在每个节点中单独执行此类Muenchian分组,则需要在用于分组的键值中包含父节点特有的内容,例如:

<xsl:key name="k" match="somechild"
     use="concat(../../highernodeId, '|', @child-id)"/>
<xsl:key name="n" match="node"
     use="concat(../highernodeId, '|', somechild/@child-id)"/>

,当您取消引用密钥时也一样:

<xsl:template match="root/highernode">
    <xsl:copy>
        <xsl:copy-of select="highernodename"/>
        <xsl:copy-of select="highernodeId"/>
        <xsl:apply-templates 
            select="node/somechild[generate-id(.) = generate-id(
              key('k', concat(current()/highernodeId, '|', @child-id)))]"/>
    </xsl:copy>
</xsl:template>

<xsl:template match="somechild">
    <xsl:copy>
        <xsl:apply-templates select="@*"/>
            <xsl:apply-templates select="key('n',
                 concat(../../highernodeId, '|', @child-id))"/>
    </xsl:copy>
</xsl:template>