簡體   English   中英

將命名空間添加到根元素

[英]Add Namespaces to Root Element

我正在編寫一個XSLT轉換,我希望在根元素上定義所有名稱空間前綴。 默認情況下,MS似乎會在XML層次結構的第一個元素上創建一個新的前綴定義以使用該架構。 也就是說,如果那些元素與同一模式的共享祖先不相關,則可以在多個元素上引用同一模式。

通過這樣編碼根元素,所有元素都可以按需工作:

<!-- ... -->

<ns0:root xmlns:ns0="http://some/schema" xmlns:ns1 = "http://another/schema">
    <!-- rest of XSLT; including calls to other templates -->
</ns0:root>

<!-- ... -->

但是我找不到使用xsl:element進行編碼的任何方法; 例如

<xsl:stylesheet 
    version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:ns0="http://some/schema" 
    xmlns:ns1 = "http://another/schema"
>
    <!-- ... -->

    <xsl:element name="ns0:root">
        <xsl:attribute name="ns1" namespace="http://www.w3.org/2000/xslns/">http://another/schema</xsl:attribute>
        <!-- rest of XSLT; including calls to other templates -->
    </xsl:element> 

    <!-- ... -->

是否可以針對xls:element聲明除元素本身之外的其他模式的名稱空間前綴?


完整的例子

XML格式

<Demo xmlns="http://some/schema">
    <a>Hello</a>
    <b>World</b>
</Demo>

XSLT

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet 
    version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:ns0="http://some/schema" 
    xmlns:ns1 = "http://another/schema"
    exclude-result-prefixes="xsl"
>

    <xsl:output method="xml" indent="yes" version="1.0"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="/*"> 
        <xsl:element name="{name(.)}" namespace="{namespace-uri(.)}">
            <xsl:apply-templates select="@* | node()" />
        </xsl:element>
    </xsl:template> 

    <xsl:template match="/ns0:Demo/ns0:a">
        <xsl:element name="ns1:z">
            <xsl:value-of select="./text()" />
        </xsl:element>
    </xsl:template> 

    <xsl:template match="/ns0:Demo/ns0:b">
        <xsl:element name="ns1:y">
            <xsl:value-of select="./text()" />
        </xsl:element>
    </xsl:template> 

</xsl:stylesheet>

結果

<Demo xmlns="http://some/schema">
    <ns1:z xmlns:ns1="http://another/schema">Hello</ns1:z>
    <ns1:y xmlns:ns1="http://another/schema">World</ns1:y>
</Demo>

所需結果

<Demo xmlns="http://some/schema" xmlns:ns1="http://another/schema">
    <ns1:z>Hello</ns1:z>
    <ns1:y>World</ns1:y>
</Demo>

要么

<ns0:Demo xmlns:ns0="http://some/schema" xmlns:ns1="http://another/schema">
    <ns1:z>Hello</ns1:z>
    <ns1:y>World</ns1:y>
</ns0:Demo>

您的最小示例沒有說明為什么需要使用xsl:element而不是xsl:copy和/或文字結果元素,但由於XSLT 1.0沒有xsl:namespace指令( https://www.w3.org/TR/xslt20 /#creating-namespace-nodes ),唯一的方法是從樣式表根目錄復制名稱空間節點,如

<xsl:stylesheet 
    version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:ns0="http://some/schema" 
    xmlns:ns1 = "http://another/schema"
    exclude-result-prefixes="xsl"
    >

    <xsl:output method="xml" indent="yes" version="1.0"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="/*"> 
        <xsl:element name="{name(.)}" namespace="{namespace-uri(.)}">
            <xsl:copy-of select="document('')/*/namespace::*[. = 'http://another/schema']"/>
            <xsl:apply-templates select="@* | node()" />
        </xsl:element>
    </xsl:template> 

    <xsl:template match="/ns0:Demo/ns0:a">
        <xsl:element name="ns1:z">
            <xsl:value-of select="./text()" />
        </xsl:element>
    </xsl:template> 

    <xsl:template match="/ns0:Demo/ns0:b">
        <xsl:element name="ns1:y">
            <xsl:value-of select="./text()" />
        </xsl:element>
    </xsl:template> 

</xsl:stylesheet>

(或具有此功能的任何其他節點,例如參數或變量,但是這樣一來,您還可以首先使用exsl:node-setms:node-set將結果樹片段轉換為ms:node-set )。

至於字面結果元素和xsl:element為什么給您不同結果的原因, https//www.w3.org/TR/xslt#literal-result-element說:

創建的元素節點還將具有樣式表樹中元素節點上存在的名稱空間節點的副本...

雖然https://www.w3.org/TR/xslt#section-Creating-Elements-with-xsl:element並未這么說。

重要的是要理解,盡管它們在XML文檔中通過名稱空間聲明屬性表示,但在XPath和XSLT的數據模型中,每個元素的作用域內名稱空間都是通過名稱空間節點而不是屬性節點建模的。 此外,不同的元素不共享名稱空間節點; 每個都有自己的一套。 使用XML輸出方法時,XSLT處理器負責產生名稱空間聲明屬性,該屬性正確表示結果樹中存在的名稱空間節點。

這充分解釋了為什么XSLT 1.0規范的7.1.3節明確禁止通過xsl:attribute元素創建名稱空間聲明:

XSLT處理器在選擇用於將創建的屬性輸出為XML的前綴時,可以利用name屬性中指定的QName的前綴; 但是,不需要這樣做,並且如果前綴為xmlns ,則一定不能這樣做 因此,盡管這樣做不是錯誤:

 <xsl:attribute name="xmlns:xsl" namespace="whatever">http://www.w3.org/1999/XSL/Transform</xsl:attribute> 

它不會導致輸出名稱空間聲明。

(添加了強調。)如果允許以這種方式創建名稱空間聲明,則它將允許結果文檔表達結果樹中實際不存在的名稱空間節點。

結果樹中的元素可以通過以下任何一種方式獲得名稱空間節點:

  • 通過xsl:copyxsl:copy-of創建的result元素接收原始元素的名稱空間節點的副本。
  • 通過樣式表樹中的文字結果元素創建的result元素將獲取樣式表元素的所有命名空間節點的副本,無論是直接在該元素上還是在祖先元素上聲明,都有一些例外。
  • 通過xsl:element樣式表元素創建的result元素沒有顯式指定為接收任何名稱空間節點,但是在實踐中,為了正確實現規范,它們需要接收該元素名稱的名稱空間(如果有)的名稱空間節點。
  • 因為只有元素具有名稱空間節點,所以(但未明確指定)每個元素還必須為其屬性名稱之一所屬的每個名稱空間都接收一個名稱空間節點(如果該名稱空間不同於元素自身名稱的名稱空間)。
  • 命名空間節點本身可以​​復制到結果樹,如其他答案所示。

沒有理由期望XSLT處理器會在結果樹中創建除此以外的其他名稱空間節點。 尤其是,盡管這可能提供結果樹更簡單的XML序列化的可能性,但樹本身將嚴格更復雜。

然后,一種方法是確保結果文檔中的<Demo>元素為該元素自己的名稱空間攜帶一個名稱空間聲明,該名稱空間聲明是通過從輸入樹中復制結果元素或該元素的屬性復制而獲得的。 ,是使用文字結果元素:

<?xml version="1.0" encoding="utf-8"?>
<xsl:stylesheet 
    version="1.0" 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform"
    xmlns:ns0="http://some/schema" 
    xmlns:ns1 = "http://another/schema">

    <xsl:output method="xml" indent="yes" version="1.0"/>
    <xsl:strip-space elements="*"/>

    <xsl:template match="/ns0:Demo"> 
      <ns0:Demo>
        <xsl:apply-templates select="@* | node()" />
      <ns0:Demo>
    </xsl:template> 

    <!-- ... -->

</xsl:stylesheet>

另一方面,如果必須通過xsl:element元素創建該元素(僅在需要計算其名稱時才需要),則需要從輸入樹中復制一個名稱空間節點。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM