通过XSLT从XML中删除空标记

时间:2011-07-11 10:18:24

标签: xslt

我有一个以下模式的xml

<?xml version="1.0" encoding="UTF-8"?>
    <Person>
      <FirstName>Ahmed</FirstName>
      <MiddleName/>
      <LastName>Aboulnaga</LastName>
      <CompanyInfo>
        <CompanyName>IPN Web</CompanyName>
        <Title/>
    <Role></Role>
        <Department>
    </Department>
      </CompanyInfo>
    </Person>

我尝试删除空标记时使用了以下xslt(来自论坛)

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

使用的xslt成功删除了像

这样的标签
<Title/>
    <Role></Role>

...但是当空标签位于两行时失败,例如:

<Department>
    </Department>

有没有解决这个问题?

6 个答案:

答案 0 :(得分:13)

此转换根本不需要任何条件XSLT指令,并且不使用明确的优先级:

<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=
    "*[not(@*|*|comment()|processing-instruction()) 
     and normalize-space()=''
      ]"/>
</xsl:stylesheet>

应用于提供的XML文档

<Person>
    <FirstName>Ahmed</FirstName>
    <MiddleName/>
    <LastName>Aboulnaga</LastName>
    <CompanyInfo>
        <CompanyName>IPN Web</CompanyName>
        <Title/>
        <Role></Role>
        <Department>
        </Department>
    </CompanyInfo>
</Person>

会产生想要的正确结果

<Person>
   <FirstName>Ahmed</FirstName>
   <LastName>Aboulnaga</LastName>
   <CompanyInfo>
      <CompanyName>IPN Web</CompanyName>
   </CompanyInfo>
</Person>

答案 1 :(得分:3)

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

答案 2 :(得分:2)

  

(..)有没有解决这个问题?

两行上的标记不是空标记。它是一个包含空格的标记(如新行和可能的某些空白字符)。 XPath 1.0函数normalize-space()允许您规范化标记的内容通过剥离不需要的新行。

将功能应用于标记内容后,您可以检查空字符串。执行此操作的一种好方法是将XPath 1.0 boolean()函数应用于标记内容。 如果内容为零长度字符串,则其结果为false

最后,您可以嵌入所有内容,稍微改变您的身份转换。您不需要xsl:if说明或任何其他附加模板。

最终的转换将如下所示:

<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()[boolean(normalize-space())]
                         |@*"/>
     </xsl:copy>
 </xsl:template>

</xsl:stylesheet>

附加说明

您的xsl:if指令当前也在检查空属性。以这种方式您实际上也删除了具有空属性的非强制标记。这听起来不像只是“删除空标签”。所以要小心,否则你的问题会遗漏一些细节,或者你使用的是不安全的代码。

答案 3 :(得分:1)

您的问题未明确。 是什么意思? <outer>在这里是空的吗?

<outer><inner/></outer>

无论如何,这是一种可能符合您账单的方法:

<xsl:template match="*[not(.//@*) and not( normalize-space() )]" priority="3"/>

请注意,您可能需要调整优先级以满足您的需求。

答案 4 :(得分:1)

根据我在网上发现的内容,这是最正确的答案:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml"/>
    <xsl:template match="/">
        <xsl:apply-templates select="*"/>
    </xsl:template>
    <xsl:template match="*">
            <xsl:if test=".!=''">
                <xsl:copy>
                  <xsl:copy-of select="@*"/>
                  <xsl:apply-templates/>
                </xsl:copy>
            </xsl:if>
    </xsl:template>
</xsl:stylesheet>

答案 5 :(得分:1)

您可以使用以下xslt删除空标记/属性:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
    <xsl:output method="xml" version="1.0" encoding="UTF-8" indent="yes"/>

    <xsl:template match="node()">
        <xsl:if test="normalize-space(string(.)) != ''
                        or count(@*[normalize-space(string(.)) != '']) > 0
                        or count(descendant::*[normalize-space(string(.)) != '']) > 0
                        or count(descendant::*/@*[normalize-space(string(.)) != '']) > 0">
        <xsl:copy>
            <xsl:apply-templates select="@*|node()" />
        </xsl:copy>
        </xsl:if>
    </xsl:template>

    <xsl:template match="@*">
        <xsl:if test="normalize-space(string(.)) != ''">
            <xsl:copy>
                <xsl:apply-templates select="@*" />
            </xsl:copy>
        </xsl:if>
    </xsl:template>
</xsl:stylesheet>