XSLT:如何删除自闭元素

时间:2010-03-16 12:38:39

标签: xslt

我有一个大的xml文件,其中包含许多自闭标签。如何使用XSLT删除它们。

例如。

<?xml version="1.0" encoding="utf-8" ?>
<Persons>
  <Person>
    <Name>user1</Name>
    <Tel />
    <Mobile>123</Mobile>
  </Person>
  <Person>
    <Name>user2</Name>
    <Tel>456</Tel>
    <Mobile />
  </Person>
  <Person>
    <Name />
    <Tel>123</Tel>
    <Mobile />
  </Person>
  <Person>
    <Name>user4</Name>
    <Tel />
    <Mobile />
  </Person>
</Persons>

我期待结果:

<?xml version="1.0" encoding="utf-8" ?>
<Persons>
  <Person>
    <Name>user1</Name>
    <Mobile>123</Mobile>
  </Person>
  <Person>
    <Name>user2</Name>
    <Tel>456</Tel>
    </Person>
  <Person>
    <Tel>123</Tel>
  </Person>
  <Person>
    <Name>user4</Name>
  </Person>
</Persons>

注意:有数千个不同的元素,如何以编程方式删除所有自闭标签。另一个问题是如何删除<name></name>之类的空元素。

任何人都可以帮我这个吗?非常感谢。

5 个答案:

答案 0 :(得分:9)

自闭标签相当于空标签。您可以删除所有空标记,但无法知道它们是否在输入XML中自行关闭(<tag/><tag></tag>无法区分)。

<!-- the identity template copies everything that has no special handler -->
<xsl:template match="node()|@*">
  <xsl:copy>
    <xsl:apply-templates select="node()|@*" />
  </xsl:copy>
</xsl:template>

<!-- special handler for elements that have no child nodes:
     they are removed by this empty template -->
<xsl:template match="*[not(node())]" />

如果您的定义中仅包含空格的元素也为“空”,则将第二个模板替换为:

<xsl:template match="*[normalize-space() = '']" />

答案 1 :(得分:1)

从XML的角度来看,“自闭”元素和空元素之间没有区别(见spec)。

这是一个去除所有空元素的转换:

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

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

</xsl:stylesheet>

答案 2 :(得分:0)

您可能想要检查是否需要它们。如果它们是:use =“required”,它应该看起来像这样。还要检查它们是否:type =“non Empty String”。

答案 3 :(得分:0)

您可以删除所有空元素 - 没有声明嵌套元素和属性的元素。如果此解决方案适合您,您可以执行以下操作:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

  <xsl:template match="*">
    <xsl:if test="string(.) != '' or descendant-or-self::*/@*[string(.)]">
      <xsl:element name="{name()}" >
        <xsl:copy-of select="@*[string(.)]"/>
        <xsl:apply-templates select="* | text()" />
      </xsl:element>
    </xsl:if>
  </xsl:template>

  <xsl:template match="text()">
    <xsl:value-of select="."/>
  </xsl:template>

</xsl:stylesheet>

答案 4 :(得分:0)

  

发布此答案的原因是,   你还没有接受任何一个   现有答案。

好。这是非常简单的XSLT挑战。只需将带有文本数据的节点与null匹配并关闭模板标记,这样,节点就不会出现在输出中。
像这样,<xsl:template match=*[.='']/>将它与您的身份模板一起添加。与Tomolak钉牢的方式类似。

这种方法的问题是,如果它为null,它甚至会删除你的父节点(例如<Person/>标记)。

如果这是你的xml:

<Persons>
   <Person>
     <data>text</data>
     <data2>text</data2>
     <data3/>
   </Person>
   <Person/>
</Persons>

从上面的xml中删除了标签。所以输出xml将是:

<Persons>
   <Person>
     <data>text</data>
     <data2>text</data2>
   </Person>
</Persons>

如果您想避免这种情况,请添加例外。

<xsl:template match="*[name()!='Person' and not(node())]"/>

添加您的身份模板。你的XSLT将是:

<?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="@* | node()">
        <xsl:copy>
            <xsl:apply-templates select="@* | node()"/>
        </xsl:copy>
    </xsl:template>
  <xsl:template match="*[name()!='Person' and not(node())]"/>
</xsl:stylesheet>

输出xml将是:

<Persons>
   <Person>
     <data>text</data>
     <data2>text</data2>
   </Person>
   <Person/>
</Persons>