2012-04-17 2 views
0

Мне нужно удалить некоторые узлы в моем файле XML, в котором он содержит определенный метод и в каком порядке он появляется, например, здесь вход:Как удалить определенный узел на основе атрибута в XML с помощью XSLT или Xquery?

<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» будет удален.

Это должно быть указано в том же идентификаторе раздела, и он удалит только пользовательский узел (оставьте идентификатор раздела, даже если он пуст после удаления пользовательского узла). Надеюсь, что это не смущает.

Можно ли это сделать только с помощью XSLT? или мне нужно использовать xQuery для перемещения по каждому узлу? Может кто-нибудь просветить меня? спасибо.

John

+0

Я думаю, что ваше повторение

является опечаткой, поскольку идентификаторы XML должны быть уникальными (если это действительно атрибут id). –

+0

Вы можете сделать это с помощью XSLT (или XQuery, я думаю), не нужно использовать оба. – LarsH

+0

Просьба пояснить, что вы подразумеваете под «если« остановка »происходит последним». Сначала я думал, что вы имели в виду, когда с методом = "stop" происходит как последний ребенок. Но поскольку это не совпадает с примером, который вы дали, я предполагаю, что нет. –

ответ

2

Вот решение, использующее XSLT 2.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> 

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

Прошу прощения, что мне нужно немного обновить запрос: «Если« остановить »происходит последним, тогда любой другой узел с другими методами с одним и тем же идентификатором пользователя (например, пауза и запуск) будет удален. это не тот узел с «остановкой» и всем узлом до того, как эта «остановка» будет удалена ». Могли бы вы обновить решения для этого? Огромное спасибо. – John

Смежные вопросы