如何使用 XSLT 根据优先级顺序和属性删除 XML 中的节点



我需要在我的xml文件中删除一些节点,其中包含某些方法以及它出现的顺序,例如这里是输入:

<root> 
<node id="a">
    <section id="a_1">
        <item id="0">
            <attribute>
                <color>Red</color>
            </attribute>
        </item>
    </section>
    <section id="a_2">
        <item id="0">
            <attribute>
                <color>Red</color>
            </attribute>
        </item>
    </section>            
</node>
<node id="b">
    <section id="b_1">         
        <user id="b_1b" method="pause">
            <attribute>a</attribute>
        </user>      
        <user id="b_1b" method="run">
            <attribute>a</attribute>
        </user>             
        <user id="b_1a" method="run">
            <attribute>
                <name>John</name>
            </attribute>
        </user>
        <user id="b_1a" method="pause">
            <attribute>a</attribute>
        </user>
    </section>
    <section id="b_1" method="create">   
        <user id="b_1b" method="stop">
            <attribute>a</attribute>
        </user>            
        <user id="b_1a" method="stop">
            <attribute>a</attribute>
        </user>
        <user id="b_1b" method="run">
            <attribute>a</attribute>
        </user>
        <user id="b_1b" method="pause">
            <attribute>a</attribute>
        </user>
    </section>
    <section id="b_2">                
        <user id="b_1a" method="run">
            <attribute>
                <name>John</name>
            </attribute>
        </user>
    </section>
</node>

如果我使用此方法:

<xsl:transform version="2.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:my="http://localhost"
  exclude-result-prefixes="my">
  <!-- Copy everything by default -->
  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>
  <xsl:template match=" user[not(@method eq 'stop' )][not(. is my:last(.))]
  | user[    @method eq 'stop' ][not(. is my:last(.))]
                     | user[not(@method eq 'stop')][my:last(.)/@method eq 'stop']"/>
          <!-- Get the last user for this section & user id -->
          <xsl:function name="my:last">
            <xsl:param name="user"/>
            <xsl:sequence select="($user/../../section[@id eq $user/../@id]
                                              /user   [@id eq $user/@id]
                                  )
                                  [last()]"/>
          </xsl:function>
</xsl:transform>

结果将是:

<root>
    <node id="a">
        <section id="a_1">
            <item id="0">
                <attribute>
                    <color>
Red
                    </color>
                </attribute>
            </item>
        </section>
        <section id="a_2">
            <item id="0">
                <attribute>
                    <color>
Red
                    </color>
                </attribute>
            </item>
        </section>
    </node>
    <node id="b">
        <section id="b_1">
        </section>
        <section id="b_1" method="create">
            <user id="b_1a" method="stop">
                <attribute>
a
                </attribute>
            </user>
            <user id="b_1b" method="pause">
                <attribute>
a
                </attribute>
            </user>
        </section>
        <section id="b_2">
            <user id="b_1a" method="run">
                <attribute>
                    <name>
John
                    </name>
                </attribute>
            </user>
        </section>
    </node>
</root>

而预期输出为:

<root>
    <node id="a">
        <section id="a_1">
            <item id="0">
                <attribute>
                    <color>Red</color>
                </attribute>
            </item>
        </section>
        <section id="a_2">
            <item id="0">
                <attribute>
                    <color>Red</color>
                </attribute>
            </item>
        </section>            
    </node>
    <node id="b">
        <section id="b_1">                                           
        </section>
        <section id="b_1" method="create">               
            <user id="b_1a" method="stop">
                <attribute>a</attribute>
            </user>
            **<user id="b_1b" method="run">
                <attribute>a</attribute>
            </user>**
            <user id="b_1b" method="pause">
                <attribute>a</attribute>
            </user>
        </section>
        <section id="b_2">                
            <user id="b_1a" method="run">
                <attribute>
                    <name>John</name>
                </attribute>
            </user>
        </section>
    </node>
</root>

所以这就是订单的运作方式。如果"stop"最后发生,那么具有相同用户 ID 的其他方法(例如暂停和运行)的任何其他节点都将被删除。但如果不是,那么带有"stop"本身的节点和"stop"之前的所有节点将被移除。

这必须发生在同一个节 id 中,并且它将只删除用户节点(即使删除用户节点后段 ID 为空,也要保留该段 ID)。希望解释不会令人困惑。

非常感谢。

干杯John

试试这个 XSLT,它减少了条件的数量,并且也可以在 XSLT 1.0 中工作

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
   <xsl:output method="xml" indent="yes"/>
   <!-- Ignore users with 'stop' method which are not the last such user -->
   <xsl:template match="user[@method='stop'][following::user[@method='stop']]"/>
   <!-- Match other users -->
   <xsl:template match="user">
      <!-- Copy the user if there isn't a following user with the same id and 'stop' method -->
      <xsl:if test="not(following::user[@id=current()/@id][@method='stop'])">
         <xsl:copy>
            <xsl:apply-templates select="@*|node()"/>
         </xsl:copy>
      </xsl:if>
   </xsl:template>
   <xsl:template match="@*|node()">
      <xsl:copy>
         <xsl:apply-templates select="@*|node()"/>
      </xsl:copy>
   </xsl:template>
</xsl:stylesheet>

这也应该生成预期的输出

我想

我已经找到了答案

<xsl:transform version="2.0"
  xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
  xmlns:my="http://localhost"
  exclude-result-prefixes="my">
  <!-- Copy everything by default -->
    <xsl:template match="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>
    <xsl:template match="user[not(@method eq 'stop')][following::user[@method eq 'stop']]
    | user[(@method eq 'stop')][not(. is my:last(.))] 
    | user[not(@method eq 'stop')][my:last(.)/@method eq 'stop']"/>
    <xsl:function name="my:last">
        <xsl:param name="user"/>
        <xsl:sequence select="($user/../../section[@id eq $user/../@id]
                                              /user   [@id eq $user/@id]
                                  )
                                  [last()]"/>
    </xsl:function>
</xsl:transform>

请评论这是否是解决它的正确方法,或者任何人有更好的解决方案。

相关内容

  • 没有找到相关文章

最新更新