2

我需要向已命名空间的 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="FFF")以及 person 中的一个附加元素,如下所示:

期望的输出:

<?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 文档目前是:

<?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 实现这一点。任何帮助将不胜感激。

4

1 回答 1

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来自 的命名空间document(''),作为替代,如果您知道文档元素将始终具有相同的名称,那么您可以将其硬编码为文字结果元素

<xsl:template match="/*">
  <everyone xmlns:frog="FFF">
    <xsl:copy-of select="namespace::*" />
    <xsl:apply-templates select="@*|node()" />
  </everyone>
</xsl:template>

(从技术上讲,即使没有此模板中的显式,它也会执行您想要的操作,因为字面量结果元素始终获得在样式表xmlns:frog中声明它们的点的范围内的命名空间声明,但如果您包含它,则意图可以说更清楚)

此邮件列表帖子提供了一些可能的见解,以了解document('')无法正常工作的原因。

于 2013-02-28T15:21:54.530 回答