首页 文章

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

提问于
浏览
2

我对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切换到节点,保持顺序,然后检查是否有几个具有相同值的子节点,并且在这种情况下,将它们的前节点分组在同一节点下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”(参见在highernode2中,somechild3应该是last,但事实并非如此 .

我希望我已经足够清楚了 .

谢谢,Mihai

1 回答

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

相关问题