2012-01-24 138 views
6

我想在XSLT中執行條件包含,但xsl:include是頂級元素。您只能使用xsl:if或xsl:選擇模板內部。是否有任何類型的黑客或工作,允許有條件的包含外部文件?我試圖使用document()函數,但它無法加載我的外部文件(可能是因爲它不符合某些使其「有效」的規則集)。XSLT條件包含外部文件

我的外部xml文件是一堆xslt代碼片段。根據主XSLT文件中變量的值,來自外部文件的相應代碼應該「就地複製/粘貼」(如C或PHP中的條件包含)。

我的主要XSLT文件的流程應該按以下方式:

$configurationMode 
if ($configurationMode = Standard) { xsl:include="standard.xml" } else { xsl:include="alt.xml" } 

很顯然,我不能這樣做簡單,如上述,因此,爲什麼我問,如果有一個黑客或替代方法。

回答

3

據我瞭解的東西,「包括」當XML解析器解析和編譯樣式表發生。這意味着在包含進行處理之前不會發生任何邏輯或表達式評估,因此無法將其作爲條件。您需要使條件行爲發生在樣式表之外。

看一看這個http://www.dpawson.co.uk/xsl/sect2/N4760.html#d6065e100

尤其確實由Mike凱幫助此評論:

這已經提出了若干倍。在以前的線程,我們來到 到用戶試圖寫一個通用 樣式G和然後通過有條件地包括 專用樣式A或B,以滿足這一要求的方式專攻它的結論是 到有A和B包括G,而不是其他的方式,然後 有條件地選擇A或B作爲主要樣式表開始 改造時。

6

這不能用XSLT 1.0來完成,並且可以使用use-when屬性來完成(在非常有限的程度上)在XSLT 2.0。

存在着實現的xsl:include的想改變動態或xsl:import指令的非XSLT的方式。

一種這樣的方法是加載XSLT樣式表作爲一個如下,並使用可用的DOM方法用於訪問和屬性的修改,以設置href屬性爲所需的值。然後從這個內存中修改的XMLDocument包含的XSLT樣式表開始轉換。

3

嘗試反轉結構:如果你有兩個特殊用途的模塊pink.xsl和blue.xsl,和通用模塊baby.xsl,然後,而不是試圖導入/包括pink.xsl或藍色之一。 XSL到baby.xsl,改用pink.xsl或blue.xsl作爲頂級條目樣式表,並讓每個這兩進口baby.xsl的。這就是它被設計使用的方式,它只是一種黑客攻擊或解決方法。

或者,考慮到您的場景的描述「我的外部xml文件是一堆xslt代碼片段」,在您的情況下,更好的方法可能是將這些片段的樣式表作爲單獨的步驟組裝,使用XSLT轉換而不是使用xsl:include/xsl:import。

0

除了已經說過的內容外,可能的解決方案是將補充文件設置爲純文本,提供內容的XML文件(而不是XSLT文件)。這樣,您可以將它們包含在XPath的document()函數中(這將在運行時而不是編譯時進行評估)。

然後,您可以根據加載的XML文檔的內容更改轉換的行爲;但是,您無法在包含的文檔中提供可執行的XSLT片段。

它取決於你的用例是否是一個解決方案 - 如果額外的文檔對轉換的控制流有很大的影響,你不想用純XML來定義它們,因爲你基本上會重新 - 實現像XSLT一樣的東西。然而,當你的文檔作爲一種配置文件時,你可能想要考慮提供他們純粹的XML。

當您遇到document()問題時,對您的文件使用XML驗證程序。錯誤意味着您的文件不是有效的XML。

0
<xsl:variable name="CONDITIONAL" select="ELEMENT/CONDITION"/> 
<xsl:variable name="DOCUMENTNAME" select="document(concat($CONDITIONAL,'-DOCUMENT.xml'))/ELEMENT"/> 

這個例子是我如何做一個有條件的使用外部文件。我在基本XML中使用了XSL使用的標誌作爲變量來幫助指定另一個文件的名稱以便拉入模板。一旦該變量被定義爲在我的情況下,我用它來拉其他XML數據到生成的輸出。 concat命令強制數據一起給出一個文件名。

所以當我想從外部XML文件獲取信息時,我使用'$ DOCUMENTNAME'來引用外部數據。

1

不知道這是否適用於您的情況,但我打算在此處拋出此問題。

我在過去做過類似的事情,但不是做一個條件包含,而是根據xsl:when的計算結果,在兩個文件中的任何一箇中調用一個模板。如果您不想在您的案例中使用模板,請忽略此答案。

例如,說「父」 XSLT文件名爲root.xslt,和兩個有條件地使用的有child1.xsltchild2.xslt。假設我想針對名爲狀態的節點的值運行條件邏輯。如果值爲「CURRENT」,我想調用一個名爲isCurrent in child1.xslt的模板,否則在child2.xslt中調用一個名爲的模板isNotCurrent。爲了簡潔起見,在每種情況下,我只是將模板傳遞給根節點和所有孩子。

它會是這個樣子:

<?xml version="1.0" encoding="utf-8"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:msxsl="urn:schemas-microsoft-com:xslt" exclude-result-prefixes="msxsl"> 
    <xsl:import href="child1.xslt"/> 
    <xsl:import href="child2.xslt"/> 

    <xsl:template match="/"> 
     <xsl:choose> 
     <xsl:when test="rootNode/status = 'CURRENT'"> 
      <!-- template isCurrent defined in child1.xslt --> 
      <xsl:apply-templates select="rootNode" mode="isCurrent" /> 
     </xsl:when> 
     <xsl:otherwise> 
      <!-- template isNotCurrent defined in child2.xslt --> 
      <xsl:apply-templates select="rootNode" mode="isNotCurrent" /> 
     </xsl:otherwise> 
     </xsl:choose> 
    </xsl:template> 
</xsl:stylesheet> 

希望這至少可以幫助一點點。

0

隨着static parameters的增加,現在可以在XSLT 3.0中使用了。可以在xsl:includeuse-when屬性中使用靜態參數。

現在我們可以宣佈與false()默認值的參數,然後覆蓋,我們需要在運行時的...

<xsl:param name="someparam" as="xs:boolean" select="false()" 
    static="yes" required="no"/> 
<xsl:include href="include_me.xsl" use-when="$someparam"/> 

這裏是一個完整的工作示例與Saxon-HE V9.7(也與測試測試Saxon-PE 9.5)。

XML輸入(的test.xml)

<doc> 
    <foo/> 
</doc> 

主XSLT 3.0(test_main.xsl)

<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:xs="http://www.w3.org/2001/XMLSchema" exclude-result-prefixes="xs"> 
    <xsl:output indent="yes"/> 
    <xsl:strip-space elements="*"/> 

    <xsl:param name="inc1" as="xs:boolean" select="false()" 
    static="yes" required="no"/> 
    <xsl:param name="inc2" as="xs:boolean" select="false()" 
    static="yes" required="no"/> 

    <xsl:include href="test_inc1.xsl" use-when="$inc1"/> 
    <xsl:include href="test_inc2.xsl" use-when="$inc2"/> 

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

</xsl:stylesheet> 

首先可能包括XSLT 3.0(test_inc1.xsl)

<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

    <xsl:template match="foo"> 
    <xsl:copy>INCLUDE FILE 1!!!</xsl:copy> 
    </xsl:template> 

</xsl:stylesheet> 

第二種可能包括XSLT 3.0(test_inc2.xsl)

<xsl:stylesheet version="3.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

    <xsl:template match="foo"> 
    <xsl:copy>INCLUDE FILE 2!!!</xsl:copy> 
    </xsl:template> 

</xsl:stylesheet> 

命令行(設定inc2爲true)

java -cp "saxon9he.jar" net.sf.saxon.Transform -s:"test.xml" -xsl:"test_main.xsl" inc2="true" 

輸出

<doc> 
    <foo>INCLUDE FILE 2!!!</foo> 
</doc> 
0

有我發現一種方法有條件地使用XSLT 2.0中的use-when功能包含文件。

你必須創建它通過應用程序運行時通過一個系統屬性,就像在我的情況下,我使用Java,所以我創建了使用命令來運行我的應用程序「調試」屬性:

java -DDebug=yes myAppPath 

那麼在XSLT中使用這個屬性來包含條件文件。例如

<xsl:include href="file1.xslt" use-when="system-property('DEBUG') = 'yes'"/> 
<xsl:include href="file2.xslt" use-when="system-property('DEBUG') != 'yes'"/> 

那樣。

不知道它是否適合於問題場景,但是是否有辦法在XSLT 2.0中執行此操作。 在XSLT 3.0中,還添加了對局部變量的支持。所以這可以使用局部變量輕鬆完成。

感謝, 編碼快樂