首页 文章

XSLT动态删除父项中的子项

提问于
浏览
-2

为了避免硬编码我要删除的子元素名称,我想在找到匹配的父元素名称时进行动态处理以删除子元素 .

我的XML文件:

<A>
    <B1>
        <C>C</C>
        <D>D</D>
        <E>E</E>
        <H>H</H>
        <MOD>
            <C>C</C>
            <D>D</D>
            <E>E</E>
            <F>F</F>
            <G>G</G>
        </MOD>
    </B1>
    <B2>
        <C>C</C>
        <E>E</E>
        <H>H</H>
        <MOD>
            <C>C</C>
            <D>D</D>
            <E>E</E>
            <F>F</F>
            <G>G</G>
        </MOD>
    </B2>
    <B3>
        <D>D</D>
        <E>E</E>
        <H>H</H>
        <X>X</X>
        <MOD>
            <C>C</C>
            <D>D</D>
            <E>E</E>
            <F>F</F>
            <G>G</G>
            <X>G</X>
        </MOD>
    </B3>
</A>

期望的输出:

我的XML文件:

<A>
    <B1>
        <C>C</C>
        <D>D</D>
        <E>E</E>
        <H>H</H>
        <MOD>
            <F>F</F>
            <G>G</G>
        </MOD>
    </B1>
    <B2>
        <C>C</C>
        <E>E</E>
        <H>H</H>
        <MOD>
            <D>D</D>
            <F>F</F>
            <G>G</G>
        </MOD>
    </B2>
    <B3>
        <D>D</D>
        <E>E</E>
        <H>H</H>
        <X>X</X>
        <MOD>
            <C>C</C>
            <F>F</F>
            <G>G</G>
        </MOD>
    </B3>
</A>

我的XSLT

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
                xmlns:xs="http://www.w3.org/2001/XMLSchema"
            exclude-result-prefixes="xs">
    <xsl:strip-space elements="*"/>
    <!-- copy all nodes -->
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>
    <!-- Remove child elements but keep parent element with same name -->
    <xsl:template match="C[../ancestor::*/C]"/>
    <xsl:template match="D[../ancestor::*/D]"/>
    <xsl:template match="E[../ancestor::*/E]"/>
</xsl:stylesheet>

我想我可以像这样组合删除元素代码

<xsl:template match="C|D|E[../ancestor::*/C|D|E]"/>

我不知道如何启动,但我认为该过程必须获取父节点名称(C,D,E,H),循环子节点将父节点名称与每个子节点名称进行比较 . 找到匹配项后,删除子元素 . 谢谢 .

2 回答

  • 1

    When this XSLT:

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
      <xsl:output omit-xml-declaration="yes" indent="yes"/>
      <xsl:strip-space elements="*"/>
    
      <xsl:template match="@*|node()">
        <xsl:copy>
          <xsl:apply-templates select="@*|node()"/>
        </xsl:copy>
      </xsl:template>
    
      <xsl:template
        match="MOD/*[../../* = self::* or preceding-sibling::* = self::*]"/>
    
    </xsl:stylesheet>
    

    ...is applied against the provided XML:

    <A>
      <B1>
        <C>C</C>
        <D>D</D>
        <E>E</E>
        <H>H</H>
        <MOD>
          <C>C</C>
          <D>D</D>
          <E>E</E>
          <F>F</F>
          <G>G</G>
        </MOD>
      </B1>
      <B2>
        <C>C</C>
        <E>E</E>
        <H>H</H>
        <MOD>
          <C>C</C>
          <D>D</D>
          <E>E</E>
          <F>F</F>
          <G>G</G>
        </MOD>
      </B2>
      <B3>
        <D>D</D>
        <E>E</E>
        <H>H</H>
        <X>X</X>
        <MOD>
          <C>C</C>
          <D>D</D>
          <E>E</E>
          <F>F</F>
          <G>G</G>
          <X>G</X>
        </MOD>
      </B3>
    </A>
    

    ...the wanted result is produced:

    <A>
      <B1>
        <C>C</C>
        <D>D</D>
        <E>E</E>
        <H>H</H>
        <MOD>
          <F>F</F>
          <G>G</G>
        </MOD>
      </B1>
      <B2>
        <C>C</C>
        <E>E</E>
        <H>H</H>
        <MOD>
          <D>D</D>
          <F>F</F>
          <G>G</G>
        </MOD>
      </B2>
      <B3>
        <D>D</D>
        <E>E</E>
        <H>H</H>
        <X>X</X>
        <MOD>
          <C>C</C>
          <F>F</F>
          <G>G</G>
        </MOD>
      </B3>
    </A>
    

    Explanation:

    • 第一个模板是众所周知的Identity Template,它将源文档中的所有节点和属性复制到结果文档中 .

    • 第二个模板会覆盖第一个模板并有效删除 <MOD> 的所有子项:

    • 与之前的兄弟或同名

    • 与其 <MOD> 父级的兄弟姐妹同名("uncle-or-aunt")

  • 1

    据我所知,这个样式表可以满足您的需求 . 它通过排除具有父母与前同胞相同名称的元素,生成与您所需要的输出匹配的输出 .

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet version="1.0"
        xmlns:xsl="http://www.w3.org/1999/XSL/Transform" >
    
      <xsl:strip-space elements="*"/>
      <xsl:output method="xml" omit-xml-declaration="yes" indent="yes"/>
    
      <xsl:template match="*">
        <xsl:if test="not(parent::*/preceding-sibling::*[name() = name(current())])">
          <xsl:copy>
            <xsl:apply-templates/>
          </xsl:copy>
        </xsl:if>
      </xsl:template>
    
    </xsl:stylesheet>
    

相关问题