避免在XSLT输出中使用空元素

时间:2014-08-11 08:44:39

标签: xml xslt

我想将输入XML映射到另一个XML,只需将输入中的值写入输出中的不同标记。

举个简单的例子,如下:

<root1>
  <a1>valA<a1>
  <b1>valB<b2>
</root1>

需要成为:

<root2>
  <a2>valA</a2>
  <b2>valB</b2>
</root2>

目前我的XSLT中有以下内容:

<xsl:apply-templates match="root1" />

<xsl:template match="root1">
  <a2>
    <xsl:value-of select="a1" />
  </a2>
  <b2>
    <xsl:value-of select="b1" />
  </b2>
</xsl:template>

问题是我的输出中不想要空标签。如果valAvalB为空,我会得到:

<root2>
  <a2></a2>
  <b2></b2>
<root2>

但我想省略空标签。我原本以为xsl:output可能有一个属性,但是没有...我在SO上遇到过这个问题:XSLT: How to exclude empty elements from my result? - 但答案是间接的,它是指定第二个样式表以在第一次转换后去除空输出元素。

我需要使用一个样式表来完成此操作。当然,必须有一些更简洁的事情:

<xsl:if test="string-length(a1) != 0">
  <a2>
    <xsl:value-of select="a1" />
  </a2>
</xsl:if>

甚至:

<xsl:template match="a1[string-length(.) != 0]">
  <a2>
    <xsl:value-of select="." />
  </a2>
</xsl:template>

为每个元素重复??

2 个答案:

答案 0 :(得分:1)

您的尝试在我看来很好,但不是测试字符串长度,而是许多人使用例如而是<xsl:template match="a1[normalize-space()]"><a2><xsl:value-of select="."/></a2></xsl:template>。但是如果你需要检查一个元素是否为空,那么你需要一些谓词或测试表达式,没有你可以全局开启的设置。

答案 1 :(得分:0)

你能做的是拥有一个通用模板,匹配任何没有文字的'leaf'元素,然后忽略这样一个元素

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

您可以将其与仅与a1b1元素匹配的模板与任意条件相结合,这样您就可以转换为a2b2当前

试试这个XSLT

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

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

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

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

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

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

请注意使用XSLT标识模板(在您的特定示例中不需要),因为您正在重命名所有元素,但如果您确实希望保留一些元素,则会使用它。