2012-04-19 43 views
-1

我需要刪除在其包含一定的方法我的XML文件,並通過它出現例如這裏爲了一些節點是輸入:如何使用XSLT根據優先順序和屬性刪除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="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> 

所以這就是命令的工作原理。如果最後發生「停止」,則其他具有相同用戶標識的方法的其他節點(例如暫停和運行)將被刪除。 但是,如果它不是那麼'停止'本身的節點和之前的所有節點'停止'將被刪除。

這必須發生在相同的部分ID,它將只刪除用戶節點(即使在刪除用戶節點後它是空的,仍保留部分ID)。 希望這個解釋不會令人困惑。

非常感謝。

歡呼聲, 約翰

回答

2

試試這個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> 

這也應該產生預期的輸出

+0

謝謝!它的工作原理和很多整潔。只是想知道是否可以概括解決方案(元素名稱並不總是「用戶」,從我的輸入中也有'項目'在部分id = a_1)。 – John 2012-04-24 01:03:03

0

我想我已經找到了答案

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

請評論,如果這是解決這個問題的正確方式或任何人有更好的解決方案。