当根节点可能具有多种类型时,将命名空间添加到根节点



我正在使用XLST 1.0,并希望转换XML以将"nil"属性添加到空元素中。我发现命名空间被添加到每个匹配的元素中,例如我的输出如下所示: <age xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true" />

我知道这是有效的,但我宁愿将其添加到我的顶部节点。我遇到了这个答案:如何使用 XSLT 将命名空间添加到 XML 的根元素?

但是我有多个可能的根节点,所以我想我可以做这样的事情:

  <xsl:template match="animals | people | things">
    <xsl:element name="{name()}">
      <xsl:attribute name="xmlns:xsi">http://www.w3.org/2001/XMLSchema-instance</xsl:attribute>
      <xsl:apply-templates/>
    </xsl:element>
  </xsl:template>

但是,我从Visual Studio收到一个错误"prexix xmlns未定义",我不确定该怎么办。

这是我的总XLST文件(由于某种原因它不会粘贴到SO中),它试图做一些事情:

  1. 将不同类型的动物转化为单一类型
  2. 将命名空间添加到根节点
  3. 向空元素添加xsi:nil = true(请注意,它们必须没有子元素,而不仅仅是没有文本,否则我的顶级节点被转换)

首先,命名空间声明不是属性,不能使用 xsl:attribute 指令创建。

可以使用xsl:copy-of在所需位置"手动"插入命名空间声明,例如:

XSLT 1.0

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<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>
<xsl:template match="/*">
    <xsl:copy>
        <xsl:copy-of select="document('')/xsl:stylesheet/namespace::xsi"/>
        <xsl:apply-templates/>
    </xsl:copy>
</xsl:template>
<xsl:template match="*[not(node())]">
    <xsl:copy>
        <xsl:attribute name="xsi:nil">true</xsl:attribute>
        <xsl:apply-templates/>
    </xsl:copy>
</xsl:template>
</xsl:stylesheet>

但是,结果相当依赖于处理器。例如,Xalan将忽略此指令,并像以前一样在它输出的每个空节点上重复声明。通常,您几乎无法控制 XSLT 处理器如何序列化输出。

另一种选择是在根级别实际使用命名空间声明,例如:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<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>
<xsl:template match="/*">
    <xsl:copy>
        <xsl:attribute name="xsi:nil">false</xsl:attribute>
        <xsl:apply-templates/>
    </xsl:copy>
</xsl:template>
<xsl:template match="*[not(node())]">
    <xsl:copy>
        <xsl:attribute name="xsi:nil">true</xsl:attribute>
        <xsl:apply-templates/>
    </xsl:copy>
</xsl:template>
</xsl:stylesheet>

这适用于我测试过的所有处理器 (YMMV)。

当然,最好的选择是不做任何事情,因为正如您所指出的,差异纯粹是装饰性的。

相关内容

  • 没有找到相关文章

最新更新