【问题标题】:Remove all nodes from xml excluding specific nodes using XSLT从 xml 中删除所有节点,不包括使用 XSLT 的特定节点
【发布时间】:2026-01-26 18:10:01
【问题描述】:

我有一堆 xml 文件,其中包含不同数量的数据节点,我想使用 XSLT 更改文件以仅包含特定节点。 示例:

<?xml version="1.0" encoding="UTF-8"?> 
 <SomeName> 
 <identifier> 
    <UID> 1234 </UID> 
 </identifier> 
 <MainNode1> 
     <SubNode1> 
        <Subnode1a>DATA1a0</Subnode1a> 
     </SubNode1> 
     <SubNode1> 
        <Subnode1a>DATA1a1</Subnode1a> 
     </SubNode1> 
     <SubNode1> 
        <Subnode1a>DATA1a2</Subnode1a> 
     </SubNode1> 
  </MainNode1> 

  <MainNode2> 
     <SubNode2> 
        <Subnode2a>DATA2a0</Subnode2a> 
     </SubNode2> 
  </MainNode2> 

  <MainNodeIDONTCARE> 
       <SubnodeWhatever> 
       </SubnodeWhatever> 
  </MainNodeIDONTCARE> 

  <MainNodeuseless> 
       <SubnodeWhatever> 
       </SubnodeWhatever> 
  </MainNodeuseless>

  <MainNodewhatever> 
       <SubnodeWhatever> 
       </SubnodeWhatever> 
  </MainNodewhatever>
</SomeName> 

现在我的最终 XML 文件应该如下所示:

<?xml version="1.0" encoding="UTF-8"?> 
 <SomeName> 
 <identifier> 
    <UID> 1234 </UID> 
 </identifier> 
 <MainNode1> 
     <SubNode1> 
        <Subnode1a>DATA1a0</Subnode1a> 
     </SubNode1> 
     <SubNode1> 
        <Subnode1a>DATA1a1</Subnode1a> 
     </SubNode1> 
     <SubNode1> 
        <Subnode1a>DATA1a2</Subnode1a> 
     </SubNode1> 
  </MainNode1> 

  <MainNode2> 
     <SubNode2> 
        <Subnode2a>DATA2a0</Subnode2a> 
     </SubNode2> 
  </MainNode2>
</SomeName> 

我一直在尝试使用 XSLT 完成它,但我似乎无法完成它。

感谢您的帮助。

【问题讨论】:

  • 好问题 (+1)。请参阅我的答案,以获得同样符合 XSLT 精神且不使用任何 &lt;xsl:for-each&gt; 指令的最短解决方案。 :)

标签: xml xslt xpath


【解决方案1】:

可能最短的解决方案如下

<xsl:stylesheet version="1.0"
 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <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="MainNodeIDONTCARE | MainNodeuseless | MainNodewhatever"/>
</xsl:stylesheet>

当对提供的 XML 文档应用此转换时,会生成所需的输出

<SomeName>
    <identifier>
        <UID> 1234 </UID>
    </identifier>
    <MainNode1>
        <SubNode1>
            <Subnode1a>DATA1a0</Subnode1a>
        </SubNode1>
        <SubNode1>
            <Subnode1a>DATA1a1</Subnode1a>
        </SubNode1>
        <SubNode1>
            <Subnode1a>DATA1a2</Subnode1a>
        </SubNode1>
    </MainNode1>
    <MainNode2>
        <SubNode2>
            <Subnode2a>DATA2a0</Subnode2a>
        </SubNode2>
    </MainNode2>
</SomeName>

请注意最基本的 XSLT 设计模式的使用:使用和覆盖身份规则

【讨论】:

  • 只有当你知道所有你想丢弃的元素时,这个解决方案才有效
  • @Gart:是的,OP 没有具体说明他是否希望丢弃除某些已知元素之外的所有元素,或者是否希望复制除某些已知元素之外的所有元素。
  • 这确实是我需要的。当结构发生变化时,排除新节点比将所有节点都作为副本更新 XLST 容易得多。
【解决方案2】:

这应该可行:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"
>
  <xsl:output method="xml" indent="yes"/>

  <xsl:template match="SomeName">
    <xsl:copy>
      <xsl:for-each select="identifier|MainNode1|MainNode2">
        <xsl:copy>
          <xsl:apply-templates />
        </xsl:copy>
      </xsl:for-each>
    </xsl:copy>
  </xsl:template>

  <xsl:template match="@* | node()">
    <xsl:copy>
      <xsl:apply-templates select="@* | node()"/>
    </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

【讨论】:

    【解决方案3】:

    在这里

    <?xml version="1.0" encoding="utf-8"?>
    <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
        <xsl:output method="xml" indent="yes"/>
    
      <xsl:template match="SomeName">
        <xsl:copy>
          <xsl:for-each select="identifier|MainNode1|MainNode2">
            <xsl:apply-templates select="." />
          </xsl:for-each>
        </xsl:copy>
      </xsl:template>
    
        <xsl:template match="@* | node()">
            <xsl:copy>
                <xsl:apply-templates select="@* | node()"/>
            </xsl:copy>
        </xsl:template>
    </xsl:stylesheet>
    

    【讨论】:

    • 不包括OP要求的标识符,MainNode1,MainNode2。
    • @Obalix:感谢您的评论,我以自己的方式更正了错误。你的解决方案也很好。