2009-04-30 81 views
4

我正在嘗試對XML文檔進行轉換。我的XML變換可導致兩種不同類型的底座元件的取決於特定元素的值:空白xmlns =「」來自導入的屬性

<StructureA xmlns="http://..."> 

StructureA &:

<xsl:template match="/"> 
    <xsl:choose> 
    <xsl:when test="/databean/data[@id='pkhfeed']/value/text()='200'"> 
     <xsl:call-template name="StructureA"> 
     <xsl:with-param name="structure" select="//databean" /> 
     </xsl:call-template> 
    </xsl:when> 
    <xsl:otherwise> 
     <xsl:call-template name="StructureB"> 
     <xsl:with-param name="structure" select="//databean" /> 
     </xsl:call-template> 
    </xsl:otherwise> 
    </xsl:choose> 
</xsl:template> 

StructureA或StructureB然後用自己的命名空間和schemaLocations創建B共享一些共同的元素,因此這些元素被定義在一個名爲「xmlcommon.xslt」的單獨文件中,這兩個結構都包含來自這些模板的文件。這個xmlcommon文件沒有定義默認名稱空間,因爲我希望它可以從StructureA或StructureB中定義的名稱空間使用。但是,當我跑我的改造,任何模板空白的xmlns從普通文件結果拉到屬性:

<StructureA xmlns="http://..."> 
    <SharedElement xmlns="">Something</SharedElement> 
</StructureA> 

驗證時,空白的命名空間則用來代替正確的父之一。 有誰知道我可以通過添加這些空白xmlns屬性來阻止我的公共文件中的模板嗎?

下面是從普通文件的片段:

<xsl:stylesheet version="1.0" xmlns:fn="http://www.w3.org/2005/02/xpath-functions" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

    <xsl:template name="ControlledListStructure"> 
    <xsl:param name="xmlElem" /> 
    <xsl:param name="structure" /> 

    <xsl:element name="{$xmlElem}"> 
     <!-- Blah blah blah --> 
    </xsl:element> 
    </xsl:template> 
</xsl:stylesheet> 

回答

9

實現的關鍵是,你的樣式表指示您添加到結果樹中的每個元素的名稱。元素的名稱包含兩部分:本地名稱和名稱空間URI。在上面的代碼中,您提供本地名稱(值爲$xmlElem),但不指定名稱空間URI,這意味着它將默認爲空字符串。 (實際上,它採用了該樣式表模塊的默認名稱空間;因爲沒有,所以它是空字符串)。換句話說,該元素將不在名稱空間中的。在序列化文檔時,XSLT處理器必須包含xmlns=""未聲明,以便取消聲明頂部出現的默認名稱空間。否則,該元素將採用該名稱空間,這不是您的樣式表規定的。解決這個問題的最少干擾方式是添加另一個參數(例如$namespaceURI),就像您使用$xmlElem一樣。然後,你會寫:

<xsl:element name="{$xmlElem}" namespace="{$namespaceURI}"> 

現在,所產生的元素將採取任何命名空間,你告訴它承擔(這將有刪除這些默認命名空間未聲明的效果)。

這應該回答你的問題。我提供以下免費獎金材料。 ;-)

您應該在您的值比較中刪除text()節點測試。很少需要直接比較文本節點的值。相反,您可以比較元素本身的字符串值(它被定義爲所有後代文本節點的字符串值的連接)。這將是這樣的:

<xsl:when test="/databean/data[@id='pkhfeed']/value = '200'"> 

做這種方式是,如果有一個評論躲藏在那裏,你的代碼不會打破的優點:

<value>2<!--test-->00</value> 

在這種情況下,有兩種文本節點(「2」和「00」)。您的原始測試會失敗,因爲它會檢查它們中的任何一個是否等於「200」。在這種情況下不太可能發生,但在任何情況下,測試元素的字符串值(而不是其文本節點子元素)是一種很好的練習,這是您的意圖。

最後,我鼓勵您瞭解模板規則和XPath上下文。我傾向於儘可能避免使用<xsl:choose><xsl:call-template><xsl:with-param>。首先,模板規則可以幫助您避免XSLT的許多醜陋的,冗長的部分。

<xsl:template match="/databean[data[@id='pkhfeed']/value = '200']" priority="1"> 
    <StructureA xmlns="http://..."> 
    ... 
    </StructureA> 
</xsl:template> 

<xsl:template match="/databean"> 
    <StructureB xmlns="http://..."> 
    ... 
    </StructureB> 
</xsl:template> 

即使您繼續使用<xsl:call-template>,你不應該來傳遞$structure參數,作爲當前節點將在所謂的模板保持不變。因爲當前節點仍然是「/」(文檔節點),所以您可以從StructureAStructureB模板中輕鬆訪問//databean(或/databean,我懷疑這是您的意思)。

如果您想了解更多關於XSLT的核心處理模式,其最強大的功能(模板規則),那麼我建議你從我XSLT 1.0袖珍參考退房"How XSLT Works",免費的樣章。

我希望這對你有幫助,即使它比你討價還價更多!

+0

很好的解釋,埃文。沒有更多要補充的。從我+1。歡迎來到SO。 – 2009-04-30 13:29:42