使用XSLT添加其他命名空间

时间:2013-02-28 15:03:40

标签: xslt namespaces

我需要为已经命名空间的XML文件添加一个额外的命名空间,但仅限于特定元素不存在。

我的XML文档如下所示:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<everyone xmlns="AAA" xmlns:ns2="BBB" xmlns:ns3="CCC" company="TestingCorp">
    <common>Stuff Here</common>
    <ns2:person id="123">
        <ns3:firstname>Billy</ns3:firstname>
        <ns2:lastname>Bobby</ns2:lastname>
    </ns2:person>
</everyone>

...如果person元素中没有ns3:firstname元素,我想添加一个新的命名空间和(例如xmlns:frog =&#34; FFF&#34;)以及人体内的其他元素如下所示:

期望输出:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<everyone xmlns="AAA" xmlns:ns2="BBB" xmlns:ns3="CCC" xmlns:frog="FFF" company="TestingCorp">
    <common>Stuff Here</common>
    <ns2:person id="123">
        <frog:title>
            <Master/>
        </frog:title>
        <ns2:lastname>Bobby</ns2:lastname>
    </ns2:person>
</everyone>

我的XSL doc目前是:

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

    <xsl:output method="xml" encoding="UTF-8" indent="yes"/>
    <xsl:strip-space elements="*"/>

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

  <xsl:template match="/*">
    <xsl:element name="ns:{local-name()}">
        <xsl:attribute name="frog">fff</xsl:attribute>
        <xsl:apply-templates select="node()|@*" />
    </xsl:element>
  </xsl:template>

</xsl:stylesheet>

....不幸的是,这不起作用。

我尝试过很多不同的东西,但似乎无法使用XSLT v1.0实现这一目标。任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:2)

首先,您需要在样式表中声明各种名称空间,以及"AAA"默认名称空间

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns="AAA"
    xmlns:frog="FFF"
    xmlns:ns2="BBB"
    xmlns:ns3="CCC">

    <xsl:output method="xml" encoding="UTF-8" indent="yes"/>
    <xsl:strip-space elements="*"/>

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

  <!-- for a Person with no firstname, add a frog:title -->
  <xsl:template match="ns2:person[not(ns3:firstname)]">
      <xsl:copy>
          <!-- must handle attributes before elements/text nodes -->
          <xsl:apply-templates select="@*" />
          <frog:title>
              <Master/>
          </frog:title>
          <xsl:apply-templates select="node()" />
      </xsl:copy>
  </xsl:template>

</xsl:stylesheet>

这将产生

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<everyone xmlns="AAA" xmlns:ns2="BBB" xmlns:ns3="CCC" company="TestingCorp">
    <common>Stuff Here</common>
    <ns2:person id="123">
        <frog:title xmlns:frog="FFF">
            <Master/>
        </frog:title>
        <ns2:lastname>Bobby</ns2:lastname>
    </ns2:person>
</everyone>

如果xmlns:frog绝对必须在everyone元素而不是每个frog:title,那么您可以添加另一个模板

<xsl:template match="/*">
  <xsl:copy>
    <xsl:copy-of select="document('')/xsl:stylesheet/namespace::frog" />
    <xsl:apply-templates select="@*|node()" />
  </xsl:copy>
</xsl:template>

从样式表元素中复制名称空间声明(尽管这意味着每个输出文档都有xmlns:frog声明,即使它不涉及任何frog:*元素。)


编辑:显然Xalan不喜欢来自copy-of的{​​{1}}名称空间,作为替代方案,如果您知道文档元素将始终具有相同的名称,那么您可以将其硬编码为文字结果元素

document('')

(从技术上讲,即使没有此模板中的显式<xsl:template match="/*"> <everyone xmlns:frog="FFF"> <xsl:copy-of select="namespace::*" /> <xsl:apply-templates select="@*|node()" /> </everyone> </xsl:template> ,它也可以执行您想要的操作,因为文字结果元素始终获取样式表中范围内的命名空间声明它们被宣告的地方,但如果你包括它,意图可以说是更明确的)

This mailing list post提供了一些可能的见解xmlns:frog无法正常工作的原因。