XSL在转换后删除空元素

时间:2014-10-01 00:28:26

标签: xml xslt xpath

我需要编写一个广泛的XSLT,它不会输出(删除)任何空的元素。对于Attributes,这意味着如果路径的值为空,则不会在输出中填充该属性。对于节点,这意味着如果没有任何数据(空属性或没有属性/数据的子节点),它将不会在输出中填充该节点。以下是与棒球相关的示例,以更好地解释我正在寻找的内容。

输出现在如何:

  <Baseball>
    <Fields>
      <Equipment>
        <Bats>
          <Bat Brand="Louisville" Model="16534" Length="34" Weight="30" Description="Composite" />
          <Bat Brand="Easton" Model="asdfer" Length="32" Weight="29" Description="" />
          <Bat Brand="" Model="" Length="" Weight="" Description="" />
        </Bats>
        <Gloves>
          <Glove Brand="" Model="" Length="" Description="" />
        </Gloves>
      </Equipment>
    </Fields>
  </Baseball>

我需要输出如何:

<Baseball>
    <Fields>
      <Equipment>
        <Bats>
          <Bat Brand="Louisville" Model="16534" Length="34" Weight="30" Description="Composite" />
          <Bat Brand="Easton" Model="asdfer" Length="32" Weight="29" />
        </Bats>
      </Equipment>
    </Fields>
  </Baseball>

我知道我可以通过写入检查值来解决这个问题但是考虑到转换的长度,我想尽可能避免这种情况。另外,给出我将要绘制的XML结构,给定输出节点的属性将具有彼此区分的路径。例如,属性&#34; Brand&#34;在输出节点&#34; Bat&#34;可能有一个&#34; ab / cd / ef / brand&#34;而属性&#34;模型&#34;可能有路径&#34; ab / wx / yz / model&#34;。 (我知道我上面的棒球例子不利于这一点)。有没有办法在不编写两个XSLT的情况下实现这一目标?你可以通过XSLT中的输出传回来吗?

2 个答案:

答案 0 :(得分:3)

为了达到目标,没有必要进行两次通过。您只需要将模板添加到现有样式表中,该模板将匹配不携带信息的节点并抑制它们。

由于您还没有向我们展示您的现有样式表,因此以下示例默认情况下仅将标识转换应用于输入,而另外两个模板则消除空节点/分支:

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

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

<!-- prune the tree -->    
<xsl:template match="*[not(descendant::text() or descendant-or-self::*/@*[string()])]"/>
<xsl:template match="@*[not(string())]"/>

</xsl:stylesheet>

作为测试输入应用于当前输出,结果为:

<?xml version="1.0" encoding="UTF-8"?>
<Baseball>
   <Fields>
      <Equipment>
         <Bats>
            <Bat Brand="Louisville" Model="16534" Length="34" Weight="30" Description="Composite"/>
            <Bat Brand="Easton" Model="asdfer" Length="32" Weight="29"/>
         </Bats>
      </Equipment>
   </Fields>
</Baseball>

答案 1 :(得分:1)

也许测试后代属性的字符串长度?像这样:

    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
        version="1.0">
        <xsl:template match="*">
            <xsl:choose>
                <xsl:when test="count(descendant-or-self::*/@*) > 0">
                    <xsl:if test="string-length(descendant-or-self::*/@*) > 0">
                        <xsl:copy>
                            <xsl:apply-templates select="@*|node()"/>
                        </xsl:copy>
                    </xsl:if>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:copy>
                        <xsl:apply-templates select="@*|node()"/>
                    </xsl:copy>    
                </xsl:otherwise>
            </xsl:choose>
        </xsl:template>
        <xsl:template match="@*">
            <xsl:if test="string-length(.) > 0">
                <xsl:copy/>
            </xsl:if>
        </xsl:template>
    </xsl:stylesheet>

注意:这只测试属性内容的长度,而不是实际的节点文本。样本中没有,您可以扩展测试。