当前位置: 首页 > 知识库问答 >
问题:

如何使用XSLT或Xquery根据XML中的属性删除某些节点?

澹台景辉
2023-03-14

我需要删除一些节点在我的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>

这就是秩序的运作方式。如果“停止”最后发生,那么具有相同用户标识的其他方法的任何其他节点(如暂停和运行)将被删除。但是如果不是,那么具有“停止”本身的节点和“停止”之前的所有节点将被删除。

这必须发生在相同的节id中,并且它将仅删除用户节点(保留节id,即使删除用户节点后该节id为空)。希望解释不要让人困惑。

仅使用XSLT可以做到这一点吗?还是必须使用xQuery遍历每个节点?有人能开导我一下吗?非常感谢。

约翰

共有1个答案

闾丘山
2023-03-14

下面是一个使用XSLT2.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>
 类似资料:
  • 我的目标是在StatusDate为1900-01-01T00:00:00时使用此XSLT样式表删除整个LoanSecondaryStatus节点,但在其他日期时保留该节点。 我有以下XML: 这是我用来尝试删除Loan二级状态节点的XSLT:

  • 我有一个XML: 我想向根元素:/doc添加一个属性(名称空间),以便输出如下所示: 我尝试了三种xslt(跳过了默认的“复制所有”部分以减少问题的长度)。 xslt1:见下文,问题在于将空名称空间xmlns=”“添加到/doc的所有子节点(即:/doc/tag1和/doc/tag2) Xslt2:见下文,问题是“ns”被添加到根节点:和 xslt3:请参见下文,问题是报告了错误:未定义名称空间前

  • 我正在尝试处理这个XML文件,我想根据最新的节点值删除所有匹配的节点。在以下示例中,最新节点值为“${DELETE}”,最新节点值将始终为“${DELETE}”,并且该节点将始终位于XML文件的底部。 示例: 预期产出为:

  • 我是XSLT新手。我想根据其他子节点的条件更改XML中的根节点。但子节点始终保持不变。例如,我有以下XML: 我喜欢将XML更改为: 这意味着依赖于<代码> 我不想在每个<代码>

  • 我的java密码如下: 它可以在cypher控制台上工作,但不能在JDBC上工作。 我得到了这个错误: 密码:

  • 输入: 如何删除列顺序中没有值的记录? 期望输出: 我当前的XSL只删除空节点 我似乎无法掌握模板匹配来删除整个“记录”标签。。。非常感谢你!