我正在使用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中),它试图做一些事情:
- 将不同类型的动物转化为单一类型
- 将命名空间添加到根节点
- 向空元素添加
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)。
当然,最好的选择是不做任何事情,因为正如您所指出的,差异纯粹是装饰性的。