【问题标题】:How to remove unwanted elements and attributes from XML file using XSLT如何使用 XSLT 从 XML 文件中删除不需要的元素和属性
【发布时间】:2011-08-24 13:16:03
【问题描述】:

我有 XML 文件,我想照原样复制它,但我想过滤一些不需要的元素和属性,例如以下是原始文件:

<root>
<e1 att="test1" att2="test2"> Value</e1>
<e2 att="test1" att2="test2"> Value 2 <inner class='i'>inner</inner></e2>
<e3 att="test1" att2="test2"> Value 3</e3>

</root>

过滤后(e3元素和att2属性已被移除):

<root>
<e1 att="test1" > Value</e1>
<e2 att="test1" > Value 2 <inner class='i'>inner</inner></e2>
</root>

注意事项:

  • 如果可能的话,我更喜欢使用(for-each 元素而不是 apply-templates
  • 我在使用 xsl:elementxsl:attribute 时遇到了一些问题,因为我无法写入当前节点名称

谢谢

【问题讨论】:

  • 为什么你更喜欢使用for-each而不是apply-templates
  • @lwburk - 我认为“我对 xsl:element 和 xsl:attribute 有一些问题...”指出了一些更深层次的问题。
  • 不清楚您是在搜索通用解决方案(未知元素名称)还是特定解决方案(过滤器e3)。我提供的答案将在前一种情况下对您有所帮助,即使它很容易适应特定情况。
  • @lwburk:我认为 for-each 比 apply-templates 更接近编程语言风格,
  • 一开始认为for-each 是解决大多数问题的自然方法是很正常的,但我认为随着您对XSLT 越来越熟悉,您会发现它完全没有必要。

标签: xml xslt


【解决方案1】:

我知道您更喜欢使用 for-each,但为什么不使用身份转换,然后用您不想保留的内容覆盖该模板?

这个样式表:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes"/>
  <xsl:strip-space elements="*"/>

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

  <xsl:template match="e3|@att2"/>

</xsl:stylesheet>

产生:

<root>
   <e1 att="test1"> Value</e1>
   <e2 att="test1"> Value 2 <inner class="i">inner</inner>
   </e2>
</root>

【讨论】:

  • @DevNull:如果最后一个节点与e3 不同,这将不起作用。我已经概括了你的答案。
  • @empo - 没错,但我在原始帖子中没有看到任何关于删除最后一个节点的内容,无论名称是什么。原来的帖子刚刚指出 e3att2 已被删除。按照您的逻辑,我还可以假设 OP 试图删除名称以“3”结尾的所有元素。
  • @DevNull:是的,除非这个人直接感兴趣,否则谁知道:D!
  • @DevNull , @empo : Actullay 我想像@DevNull 所说的那样删除“e3”元素,而不是最后一个元素,谢谢大家,你的答案很完美
  • 这是解决这个问题的正确方法,也是很常见的模式。
【解决方案2】:

正如@DevNull 向您展示的那样,使用身份转换要容易得多,也不那么冗长。无论如何,这是一种可能的解决方案,有for-each,没有apply-templates,正如你所要求的:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
 <xsl:output omit-xml-declaration="yes" indent="yes"/>
  <xsl:template match="/root">
   <root>
    <xsl:for-each select="child::node()">
     <xsl:choose>
      <xsl:when test="position()=last()-1"/>
      <xsl:otherwise>
       <xsl:copy>
        <xsl:copy-of select="@att"/>
        <xsl:copy-of select="child::node()"/>
       </xsl:copy>
      </xsl:otherwise>
    </xsl:choose>
   </xsl:for-each>
  </root>
</xsl:template>


关于使用恒等变换的注​​意事项

如果你的情况真的像它看起来的那样,我的意思是元素的未知名称,@DevNull 将不起作用,你需要像这样更通用的东西:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
  <xsl:output indent="yes"/>
   <xsl:strip-space elements="*"/>

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

    <xsl:template match="root/child::node()[position()=last()]|@att2"/>

</xsl:stylesheet>

即使使用最后一个元素 e4e1000,此解决方案也适用。

【讨论】:

  • 非常感谢,实际上我想删除元素“e3”而不是最后一个元素,抱歉问题不清楚。您的解决方案在两种方面都很完美.. 但我选择了@DevNull 解决方案,因为它适用于我的情况。再次,非常感谢。
猜你喜欢
  • 1970-01-01
  • 2013-09-22
  • 1970-01-01
  • 2021-10-23
  • 2015-01-26
  • 2012-07-29
  • 2011-07-08
  • 1970-01-01
  • 2021-12-06
相关资源
最近更新 更多