2017-06-23 75 views
0

我正在編寫一個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> 
+2

您可能想向我們展示最少但完整的XML輸入示例,您擁有的XSLT代碼,您需要的結果以及您獲得的結果,以便我們重現和理解問題。你使用'>'的代碼片段似乎並不是必須的,因爲你在運行時不計算元素名稱,所以我不確定爲什麼你需要'xsl:元素「。如果你想讓名稱空間聲明在所有模板中的所有結果元素的範圍內,那麼你可以將它們放在'xsl:stylesheet'上,但是看起來你已經有了。 –

+0

無後顧之憂;請參閱更新版本的「完整示例」部分。 – JohnLBevan

+0

你爲什麼在意?您呈現的期望和實際結果具有相同的語義。 –

回答

2

你的小例子,並不能解釋爲什麼你需要使用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第一組的節點)。

至於爲什麼文字結果元素和xsl:element給你不同的結果,那麼,https://www.w3.org/TR/xslt#literal-result-element說:

創建的元素節點也將有存在的元素節點上的命名空間節點 副本樣式表樹...

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

+0

謝謝。很高興知道它是如何設計的......在我的'XslCompiledTransform'上將'EnableDocumentFunction'設置爲true後,上述技術完美運行。 – JohnLBevan

1

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

這充分說明了爲什麼Section 7.1.3 of the XSLT 1.0 spec明確禁止通過xsl:attribute要素創建一個命名空間聲明:

XSLT處理器可利用的QName 的選擇用於 前綴當name屬性指定的前綴將創建的屬性輸出爲XML;然而,他們不是 要求這樣做,而如果前綴是xmlns,他們不能這樣做。 因此,雖然它是不是一個錯誤的事:

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

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

(強調添加。)如果創建一個名稱空間聲明,那麼它將允許結果文檔表示名稱空間節點,而這些名稱空間節點實際上並不存在於結果樹中。

在結果樹的元素可以以任何的這些方式得到一個命名空間節點:通過xsl:copyxsl:copy-of創建

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

沒有理由期望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元素創建元素 - 這應該只是必要的,如果它的名字需要計算 - 然後您需要從輸入樹複製命名空間節點。

相關問題