如何使用XSLT基于节点属性位置进行xml消除?

时间:2012-05-24 09:29:35

标签: xml xslt

输入文件:

<root>
    <sector>
        <nodeA id="a">
            <section id="i">
                <item1 id="1" method="create"> 
                    <somechild>a</somechild>
                </item1>

                <item1 id="1" method="delete" />
            </section>                   
        </nodeA>

        <nodeA id="b">
            <cell id="ii">  
                <item2 id="2" method="create"> 
                    <otherchild>a</otherchild>
                </item2>
            </cell>
            <cell id="ii">
                <item2 id="2" method="delete" />
            </cell>                   
        </nodeA>

        <nodeB id="i">
            <cell id="ii">  
                <item3 id="1" method="create"> 
                    <child>b</child>
                </item3>
            </cell>

            <cell id="ii">
                <item3 id="1" method="delete" />
                <item3 id="1" method="create"> 
                    <otherchild>a</otherchild>
                </item3>
            </cell>                   
        </nodeB>
    </sector> 
</root>

预期输出:

<root>
    <sector>
        <nodeA id="a">
            <section id="i">
            </section>                   
        </nodeA>

        <nodeA id="b">
            <cell id="ii">  
            </cell>
            <cell id="ii">
            </cell>                   
        </nodeA>

        <nodeB id="i">
            <cell id="ii">  
                <item3 id="1" method="create"> <!-- this is not eliminated as it violates the rule by having create followed by delete and followed by create again -->
                    <child>b</child>
                </item3>
            </cell>

            <cell id="ii">
                <item3 id="1" method="delete" />
                <item3 id="1" method="create"> 
                    <otherchild>a</otherchild>
                </item3>
            </cell>                   
        </nodeB>
    </sector> 
</root>

我需要使用此规则消除xml中的节点:

  • 一个节点method="create"后跟一个method="delete"节点将被删除
  • 该场景可以在一个父级中发生,也可以在两个父级中传播,只要它具有相同的元素名称和标识<cell id="ii">

如何使用XSLT 1.0或2.0进行此转换?

谢谢。

1 个答案:

答案 0 :(得分:1)

这是一种方法。您可以定义一个键,用于对要删除的项目进行分组。我认为你是通过元素的@id属性和两个父节点的@id属性进行分组

<xsl:key 
   name="items" 
   match="*[@method != '']" use="concat(@id, '|', ../@id, '|', ../../@id)" />

接下来,你可以有一个模板来匹配 @ method ='create'项目,其中键中有两个元素,另一个项目是 @ method ='delete “

<xsl:template match="*
   [@method = 'create']
   [count(key('items', concat(@id, '|', ../@id, '|', ../../@id))) = 2]
   [key('items', concat(@id, '|', ../@id, '|', ../../@id))[@method = 'delete']]" />

您还需要一个模板,以类似的方式匹配其他 @ method ='delete'

这是完整的XSLT

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

   <xsl:key name="items" match="*[@method != '']" use="concat(@id, '|', ../@id, '|', ../../@id)" />

   <xsl:template match="*[@method = 'create'][count(key('items', concat(@id, '|', ../@id, '|', ../../@id))) = 2][key('items', concat(@id, '|', ../@id, '|', ../../@id))[@method = 'delete']]" />
   <xsl:template match="*[@method = 'delete'][count(key('items', concat(@id, '|', ../@id, '|', ../../@id))) = 2][key('items', concat(@id, '|', ../@id, '|', ../../@id))[@method = 'create']]" />

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

当应用于您的示例XML时,输出以下内容

<root>
   <sector>
      <nodeA id="a">
         <section id="i"/>
      </nodeA>
      <nodeA id="b">
         <cell id="ii"/>
         <cell id="ii"/>
      </nodeA>
      <nodeB id="i">
         <cell id="ii">
            <item3 id="1" method="create">
               <child>b</child>
            </item3>
         </cell>
         <cell id="ii">
            <item3 id="1" method="delete"/>
            <item3 id="1" method="create">
               <otherchild>a</otherchild>
            </item3>
         </cell>
      </nodeB>
   </sector>
</root>