XSLT 1.0如何在root用户处保留名称空间声明

时间:2017-10-23 16:24:59

标签: xml xslt namespaces xslt-1.0

我正在使用XSLT 1.0(,因为处理软件不支持2.0 )而且我一直在寻找一种在输出xml上制作所有命名空间定义的方法放在根节点。任何人都知道如何做到这一点?

以下是我正在做的事情,我得到的以及我所追求的事情的一个小例子:

输入XML:

<document Version="1.4">
<Series>A</Series>
<Folio>321</Folio>
<Date>2017-05-05T01:00:00</Date>
<Complement>
    <Other>
        <Version>4.2</Version>
        <Type>K</Type>
        <PaymentDate>2016-12-13</PaymentDate> 
    </Other>
</Complement>
</document>

我的XSLT:

<xsl:stylesheet extension-element-prefixes="xsi" version="1.0" xmlns:A="http://example.com/A" xmlns:C="http://example.com/C" xmlns:local="urn:local" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:B="http://example.com/B" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xsi:schemaLocation="http://example.com/A http://example.com/A/A.xsd">
<xsl:output encoding="UTF-8" indent="yes" method="xml" version="1.0" omit-xml-declaration="yes"/>
<xsl:template match="/">
    <xsl:element name="A:Document">
        <xsl:attribute name="Version">
            <xsl:text>9.1</xsl:text>
        </xsl:attribute>
        <xsl:if test="/document/Series/node() and /document/Series != ''">
            <xsl:attribute name="Series">
                <xsl:value-of select="/document/Series"/>
            </xsl:attribute>
        </xsl:if>
        <xsl:if test="/document/Folio/node() and /document/Folio != ''">
            <xsl:attribute name="Folio">
                <xsl:value-of select="/document/Folio"/>
            </xsl:attribute>
        </xsl:if>
        <xsl:attribute name="Date">
            <xsl:value-of select="/document/Date"/>
        </xsl:attribute>
        <xsl:if test="/document/Complement/Other/node() or /document/Complement/Another/node()">
            <xsl:element name="A:Complement">
                <xsl:if test="/document/Complement/Other/node()">
                    <xsl:element name="B:Payment">
                        <xsl:call-template name="B:Payment">
                            <xsl:with-param name="Node" select="/document/Complement/Other"/>
                        </xsl:call-template>
                    </xsl:element>
                </xsl:if>
            </xsl:element>
        </xsl:if>
    </xsl:element>
</xsl:template>
<!--- COMPLEMENT-->
<xsl:template name="B:Payment">
    <xsl:param name="Node"/>
    <xsl:attribute name="Version">
        <xsl:value-of select="$Node/Version"/>
    </xsl:attribute>
    <xsl:attribute name="Type">
        <xsl:value-of select="$Node/Type"/>
    </xsl:attribute>
    <xsl:attribute name="PaymentDate">
        <xsl:value-of select="$Node/PaymentDate"/>
    </xsl:attribute>
</xsl:template>
</xsl:stylesheet>

输出:

<A:Document Version="9.1" Series="A" Folio="321" Date="2017-05-05T01:00:00" xmlns:A="http://example.com/A">
    <A:Complement>
        <B:Payment Version="4.2" Type="K" PaymentDate="2016-12-13" xmlns:B="http://example.com/B" />
    </A:Complement>
</A:Document>

我需要什么:

<A:Document Version="9.1" Series="A" Folio="321" Date="2017-05-05T01:00:00" xmlns:A="http://example.com/A" xmlns:B="http://example.com/B">
    <A:Complement>
        <B:Payment Version="4.2" Type="K" PaymentDate="2016-12-13" />
    </A:Complement>
</A:Document>

正如您所看到的,我需要的是两个名称空间声明都保存在根节点上(根据将处理此XML的软件的请求)

其他一些信息:

  • 我只能使用前面提到的XSLT 1.0,因为这是我可以使用的当前工具中唯一支持的(有计划改变它,但不会在不久的将来完成)
  • 这必须完全使用XSLT
  • 完成
  • 正如您可以从示例中推断的那样,“Other”节点是可选的,因此它可以存在(在这种情况下输出上的命名空间是必需的)或者不存在(在这种情况下,命名空间声明不应该是本)
  • 这个“可选”节点有更多,每个节点都有自己的命名空间
  • 它不一定只是1个XSLT,如果可以通过将输出传递给新的XSLT来修复,那就可以了。

我是一名XSLT新手,所以对此有任何帮助(或者我可以学习如何做到这一点的一些文献的方向)将不胜感激

2 个答案:

答案 0 :(得分:1)

我建议您使用文字结果元素,即ie。

Int

那么你只需要<xsl:template match="/"> <A:Document> 即。

exclude-result-prefixes="xsi C local msxsl"

这样XSLT处理器将输出

<xsl:stylesheet exclude-result-prefixes="xsi C local msxsl" version="1.0" xmlns:A="http://example.com/A" xmlns:C="http://example.com/C" xmlns:local="urn:local" xmlns:msxsl="urn:schemas-microsoft-com:xslt" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:B="http://example.com/B" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xsi:schemaLocation="http://example.com/A http://example.com/A/A.xsd">

如果需要在运行时计算元素名称或命名空间,则仅使用<A:Document xmlns:A="http://example.com/A" xmlns:B="http://example.com/B" Version="9.1" Series="A" Folio="321" Date="2017-05-05T01:00:00">

关于资源和教程,我们可以免费在线免费获取一本书https://cranesoftwrights.github.io/books/ptux/

答案 1 :(得分:1)

如果您静态地知道(即在编写样式表时)结果树中最外层的元素应该是什么,以及它应该具有哪些命名空间,那么您可以使用文字结果元素来实现这一点:

<A:Element xmlns:A="some.uri" xmlns:B="some.other.uri">
  ...
</A:Element>

如果要从源文档中复制元素名称和名称空间,则可以使用<xsl:copy>

要将源文档中的所有命名空间(无论它们出现在何处)复制到新的根元素中,您可以使用

构建根元素
<xsl:element name="{$name}">
   <xsl:copy-of select="//namespace::*"/>
   ...
</xsl:element>

在其他情况下,这更难。在XSLT 1.0中,在最常见的情况下,动态创建命名空间节点的唯一方法是在相关命名空间中构造虚拟元素,然后使用<xsl:copy-of select="exslt:node-set($dummy)//namespace::x"/>复制其命名空间节点。但这很少是必要的。