2012-04-17 93 views
0

我需要删除在其包含一定的方法我的XML文件,并通过它出现例如这里为了一些节点是输入:如何使用XSLT或Xquery基于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)。 希望这个解释不会令人困惑。

是否有可能通过仅使用XSLT来完成?还是必须使用xQuery遍历每个节点? 有人可以启发我吗? 非常感谢。

约翰

+0

我认为你重复的

是一个错字,因为XML ID应该是唯一的(如果它确实是一个ID属性)。 – 2012-04-17 17:32:07

+0

你可以用XSLT(或者我认为的XQuery)来完成,不需要同时使用两者。 – LarsH 2012-04-17 17:44:16

+0

请澄清“if'stop'最后发生的含义。起初,我以为你的意思是当与方法=“停止”作为最后一个孩子发生。但既然这不符合你给的例子,我猜不是。 – 2012-04-17 18:19:58

回答

2

下面是使用XSLT 2.0的解决方案。第一条规则是规范的身份转换。第二条规则删除你想要删除的节点(如果我正确理解你的话)。每个用户列表(正如我现在所理解的那样)由段ID和用户ID的组合来标识。

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

    <!-- But remove the "stop" method if it's not last for the user/section; 
     also, remove other methods where the last one is "stop" --> 
    <xsl:template match="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> 

让我知道你是否对上述工作有任何疑问。

+0

对不起,我必须稍微更新一下查询,它应该是“如果'停止'最后发生,那么任何其他具有相同用户ID(例如暂停和运行)的其他方法的节点都将被删除。它不是那个自身具有“停止”的节点,并且在“停止”之前的所有节点都将被删除。“您能否更新解决方案?非常感谢。 – John 2012-04-19 10:10:33