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

时间:2016-07-12 11:58:32

标签: xml xslt xslt-1.0

我正在使用XLST 1.0并希望Transform XML to add 'nil' attributes to empty elements。我发现命名空间被添加到每个匹配元素,例如我的输出如下: <age xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:nil="true" />

我知道这是有效的,但我宁愿将它添加到我的顶级节点。我看到了这个答案:How can I add namespaces to the root element of my XML using XSLT?

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

  <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 not defined”收到错误,我不知道该怎么做。

Here is my total XLST file(由于某种原因,它不会粘贴到SO中)试图做一些事情:

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

1 个答案:

答案 0 :(得分:0)

首先,名称空间声明不是属性,不能使用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)。

当然,最好的选择是什么都不做,因为正如你所指出的那样,差别纯粹是装饰性的。