XSLT动态删除父项中的子项

时间:2013-05-13 18:58:59

标签: xslt

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

我的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 个答案:

答案 0 :(得分:1)

当这个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>

...适用于提供的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>

...生成了想要的结果:

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

<强>解释

  • 第一个模板是众所周知的Identity Template,它将源文档中的所有节点和属性复制到结果文档中。
  • 第二个模板会覆盖第一个模板并有效删除<MOD>的所有子项:
    • 与之前的兄弟或
    • 具有相同的名称
    • 与他们的<MOD>父母(“叔叔或姨妈”)的兄弟姐妹同名?

答案 1 :(得分: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>