【问题标题】:XSLT 1.0 How to keep namespace declaration at rootXSLT 1.0 如何将命名空间声明保留在根目录
【发布时间】:2018-04-04 06:47:30
【问题描述】:

我正在使用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 新手,所以任何对此的帮助(或一些我可以学习如何做到这一点的文献的指导)将不胜感激

【问题讨论】:

  • 感谢编辑=D

标签: xml xslt namespaces xslt-1.0


【解决方案1】:

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

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

如果要从源文档中复制元素名称和命名空间,则可以使用&lt;xsl:copy&gt;

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

<xsl:element name="{$name}">
   <xsl:copy-of select="//namespace::*"/>
   ...
</xsl:element>

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

【讨论】:

    【解决方案2】:

    我建议您使用文字结果元素与 i.e.

    <xsl:template match="/">
        <A:Document>
    

    那么你只需要 exclude-result-prefixes="xsi C local msxsl" 和 i.e.

    <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">
    

    这样 XSLT 处理器就会输出

    <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">
    

    如果您需要在运行时计算元素名称或命名空间,请仅使用 xsl:element

    至于资源和教程,现在我们https://cranesoftwrights.github.io/books/ptux/在线免费提供一本书。

    【讨论】:

    • 哦,完全解决了。感谢您的帮助和链接=D
    猜你喜欢
    • 2012-08-16
    • 1970-01-01
    • 1970-01-01
    • 2012-05-22
    • 2012-10-07
    • 2015-05-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多