如何避免在XSLT中生成空属性?

时间:2011-04-21 10:18:17

标签: xslt

我用以下代码编写了XSLT文件:

<xsl:attribute name="subCode">
    <xsl:value-of select="Field[@key='XY']"/>
</xsl:attribute>

假设我的INPUT XML看起来像这样:

[...]
<Field key="XY"/>
[...]

在这种情况下,我的XSLT将生成以下输出:

<SomeElement subCode="">
[...]
</SomeElement>

我的问题是:如何删除空属性subCode=""

我知道通过使用像<xsl:if>这样的条件指令是可能的,但是,这似乎是一个丑陋的解决方案(因为我在我的XSLT中生成了数千个类似的属性)。

必须在同一个XSLT中完成。我无法在其他XSLT文件中添加后处理。

除此之外,输出XML已经定义了XSD Schema。模式表明此属性为可选。也许有一些方法可以将XSD架构应用于输出XML?

提前感谢您的帮助!

3 个答案:

答案 0 :(得分:4)

使用

<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="/*">
  <someElement>
    <xsl:apply-templates mode="attr"/>
  </someElement>
 </xsl:template>

 <xsl:template match="Field[@key='XY' and not(.='')]" mode="attr">
    <xsl:attribute name="subCode">
      <xsl:value-of select="."/>
    </xsl:attribute>
 </xsl:template>
</xsl:stylesheet>

将此转换应用于以下XML文档时:

<t>
 <Field key="XY"/>
</t>

生成了想要的,正确的结果(根本没有生成属性)

源XML文档是这样的:

<t>
 <Field key="XY">1</Field>
</t>

相同的转换再次产生正确的,想要的结果;

<someElement subCode="1"/>

答案 1 :(得分:1)

您可以定义一个模板以匹配该属性,该属性将为缺失的@key提供正确的输出,但如果您还添加谓词[.!=''],则它还应忽略没有值的属性。

<xsl:template match="@key[.!='']">
  <xsl:attribute name="subCode"><xsl:value-of select="."/></xsl:attribute>
</xsl:template>

或者在您的示例中,如果您只想使用@key='XY'匹配项:

<xsl:template match="@key[.='XY']">
  <xsl:attribute name="subCode"><xsl:value-of select="."/></xsl:attribute>
</xsl:template>

编辑:以下是我用来测试此内容的更完整示例。

源XML

<Fields>
   <Field key="XY">A</Field>
   <Field key="XY">B</Field>
   <Field key="">C</Field>
   <Field>D</Field>
</Fields>

伴随XSL

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

<xsl:template match="/">
  <output>
    <xsl:apply-templates />
  </output>
</xsl:template>

<xsl:template match="Field">
  <xsl:element name="NewField">
    <xsl:apply-templates select="@*"/>
    <xsl:value-of select="."/>
  </xsl:element>
</xsl:template>

<xsl:template match="@key[.='XY']">
  <xsl:attribute name="subCode"><xsl:value-of select="."/></xsl:attribute>
</xsl:template>
</xsl:stylesheet>

结果

<output>
  <NewField subCode="XY">A</NewField>
  <NewField subCode="XY">B</NewField>
  <NewField>C</NewField>
  <NewField>D</NewField>
</output>

答案 2 :(得分:0)

您应该将以下模板应用于您的属性:

此模板匹配所有属性值为'XY'的属性:

<xsl:template match="@key['XY']">
    <xsl:attribute name="subCode">
        <xsl:value-of select="."/>
    </xsl:attribute>
</xsl:template>

此模板匹配所有属性,其中(文本)值大于0:

<xsl:template match="@key[string-length(.)]">
    <xsl:attribute name="other">
        <xsl:value-of select="."/>
    </xsl:attribute>
</xsl:template>

最后,这个模板匹配所有空的属性(*):

<xsl:template match="@*[not(string-length(.))]" />

所以,如果您有像

这样的输入
<?xml version="1.0"?>
<Root>
    <Field key='v'>One</Field>
    <Field key='XY'>Two</Field>
    <Field key='a'>Three</Field>
    <Field key='v'>Four</Field>
    <Field key='XY'>Five</Field>
    <Field>Six</Field>
    <Field>Seven</Field>
    <Field key='b'>Eight</Field>
    <Field key=''>Nine</Field>
    <Field></Field>
    <Field key='x'>Eleven</Field>
    <Field key=''>Twelve</Field>
    <Field lat='x'>Thirteen</Field>
</Root>

您可以生成输出:

<?xml version='1.0' ?>
<Root>
    <SomeField other="v">One</SomeField>
    <SomeField subCode="XY">Two</SomeField>
    <SomeField other="a">Three</SomeField>
    <SomeField other="v">Four</SomeField>
    <SomeField subCode="XY">Five</SomeField>
    <SomeField>Six</SomeField>
    <SomeField>Seven</SomeField>
    <SomeField other="b">Eight</SomeField>
    <SomeField>Nine</SomeField>
    <SomeField/>
    <SomeField other="x">Eleven</SomeField>
    <SomeField>Twelve</SomeField>
    <SomeField>xThirteen</SomeField>
</Root>

使用以下xslt:

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

    <xsl:template match="/">
        <Root>
            <xsl:apply-templates/>
        </Root>
    </xsl:template>

    <xsl:template match="Field">
        <xsl:element name="SomeField">
            <xsl:apply-templates select="@*"/>
            <xsl:value-of select="text()"/>
        </xsl:element>
    </xsl:template>

    <xsl:template match="@key['XY']">
        <xsl:attribute name="subCode">
            <xsl:value-of select="."/>
        </xsl:attribute>
    </xsl:template>

    <xsl:template match="@key[string-length(.)]">
        <xsl:attribute name="other">
            <xsl:value-of select="."/>
        </xsl:attribute>
    </xsl:template>

    <xsl:template match="@key[not(string-length(.))]" />
</xsl:stylesheet>