2011-04-13 79 views
6

我已經找遍了所有周圍找到一個解決我的問題,但我得到了更多的問題......帶動態QName的XSLT調用模板?

考慮以下XML:

<dynamicStuff> 
     <dyn id="name1">...</dyn> 
     <dyn id="name2">...</dyn> 
     <dyn id="name3">...</dyn> 
     <dyn id="name4">...</dyn> 
</dynamicStuff> 

,並假設我有一個XSLT文件如下:

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

    <xsl:template name="name1">  
     ... 
    </xsl:template> 

    <xsl:template name="name2">  
     ... 
    </xsl:template> 

    <xsl:template name="name3">  
     ... 
    </xsl:template> 

    <xsl:template name="name4">  
     ... 
    </xsl:template> 

</xsl:stylesheet> 

我想要做的就是從第二XSLT文件動態確定的是這樣調用哪個模板:

<xsl:variable name="templateName"> 
    <xsl:value-of select="dyn/@id"/> 
</xsl:variable> 

<xsl:call-template name="$templateName"/> 

遺憾的是它不工作,相信我,當我說,我已經嘗試了很多不同的東西,雖然這聽起來太簡單了,沒有工作,要麼...

我缺少的東西?

編輯:

我已經成功地做到以下幾點:

<xsl:template name="staticName"> 
    <xsl:param name="id" /> 

    <xsl:if test="$id = 'name1'">....</xsl:if> 
    <xsl:if test="$id = 'name2'">....</xsl:if> 
    ... 
</xsl:template> 

調用這種方式:

<xsl:call-template name="staticName"> 
    <xsl:with-param name="id" select="@id"/> 
</xsl:call-template> 

不用說多麼不方便,這是...第我所有的代碼都會被綁定到那個staticName上(假設我需要在十幾個文件中完成這個調用)...第二步,我將有一堆(un)相關的cont當它可以更分開相同的模板內耳鼻喉科......一場噩夢升級系統UU

據我想要做什麼,但不是我需要的方式......

預先感謝任何光線在這個問題上!

回答

6

http://www.w3.org/TR/xslt#named-templates

name屬性的值是 QName, ,其按照 [2.4 Qualified Names]中所述展開。

這意味着既不是一個表達式也不是一個AVT。

明確xsl:call-template說明是否罰款由邏輯指令或模式匹配,如:

<xsl:template match="dyn[@id='name1']" mode="dynamic"> 
<xsl:call-template name="name1"/> 
</xsl:template> 

另一種方法命名模板引用...

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:variable name="vTemplate" select="document('')/*/xsl:template"/> 
    <xsl:template match="dyn"> 
     <xsl:apply-templates select="$vTemplate[@name = current()/@id]"/> 
    </xsl:template> 
    <xsl:template match="xsl:template[@name='name1']" 
        name="name1"> one </xsl:template> 
    <xsl:template match="xsl:template[@name='name2']" 
        name="name2"> two </xsl:template> 
    <xsl:template match="xsl:template[@name='name3']" 
        name="name3"> three </xsl:template> 
    <xsl:template match="xsl:template[@name='name4']" 
        name="name4"> four </xsl:template> 
</xsl:stylesheet> 

輸出:

one two three four 


注意:因爲此技術使用 document('')來處理XSLT而不是原始XML文件,所以正在處理的原始文檔在命名模板中不可用。然而,如果需要的話,你可以明確地傳遞 current()作爲參數傳遞給模板:

<xsl:template match="dyn"> 
     <xsl:apply-templates select="$vTemplate[@name = current()/@id]"> 
      <xsl:with-param name="current" select="current()"/> 
     </xsl:apply-templates> 
    </xsl:template> 

如果需要的話,$current可以用來訪問原始文件:

<xsl:template match="xsl:template[@name='name1']" name="name1"> 
     <xsl:param name="current"/> 
     <xsl:value-of select="$current/@id"/> 
     <xsl:text> becomes one</xsl:text> 
    </xsl:template> 

如果需要的話,$current可以重新確立爲使用for-each當前節點:

<xsl:template match="xsl:template[@name='name2']" name="name2"> 
    <xsl:param name="current"/> 
    <xsl:for-each select="$current"> 
      <xsl:value-of select="@id"/> 
      <xsl:text> becomes two</xsl:text> 
    </xsl:for-each> 
</xsl:template> 
1

如果您只有有限數量的可能模板,是否可以使用xsl if構造來選擇在主模板中執行什麼操作?

<xsl:if test="$templateName = 'name1'"> 
    <xsl:call-template name="name1"/> 
</xsl:if> 
+0

可悲的是,我的可能事件數量並不小。儘管它是有限的。最大的問題是,它沒有分組到一個文件 – Fawix 2011-04-13 22:39:06

+0

那麼問題是,我沒有一個固定的xml佈局,它可以發生在幾個不同的標籤(和幾個不同的xmls)只是與id來識別它,和我的XSLT是太泛泛,無法確定名稱..到目前爲止最好的是使用參數的解決方法。 – Fawix 2011-04-13 23:52:56

0

你嘗試什麼是不能直接,但爲什麼不乾脆在首位匹配的id屬性的值?如果你確實需要被調用模板的間接,然後通過id匹配的模板調用它(見下文name4):

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:template match="/"> 
     <t><xsl:apply-templates select="dynamicStuff/dyn"/></t> 
    </xsl:template> 
    <!-- match on attribute value --> 
    <xsl:template match="dyn[@id='name1']">name1</xsl:template> 
    <xsl:template match="dyn[@id='name2']">name2</xsl:template> 
    <xsl:template match="dyn[@id='name3']">name3</xsl:template> 
    <xsl:template match="dyn[@id='name4']"> 
     <xsl:call-template name="name4"/> 
    </xsl:template> 
    <!-- named templates --> 
    <xsl:template name="name1">name1</xsl:template> 
    <xsl:template name="name2">name2</xsl:template> 
    <xsl:template name="name3">name3</xsl:template> 
    <xsl:template name="name4">name4</xsl:template> 
</xsl:stylesheet> 

輸入:

<dynamicStuff> 
    <dyn id="name1">...</dyn> 
    <dyn id="name2">...</dyn> 
    <dyn id="name3">...</dyn> 
    <dyn id="name4">...</dyn> 
</dynamicStuff> 

輸出:

<t>name1name2name3name4</t> 
+0

感謝您的回答!可悲的是,我沒有一個XML,它可以發生在幾個不同的標籤(由相同的ID標識),因此與dyn [@ id ='name1']映射將使我的代碼非常巨大,因爲我需要映射每個標籤所有的XML文件 – Fawix 2011-04-13 23:56:00

1

通常,當有人試圖做到這一點,這意味着他們AR e沒有意識到xsl:apply-templates的全部功能。在XSLT中執行動態分發的方法是使用xsl:apply-templates。例如,對於這個問題引用,寫模板規則如

<xsl:template match="dyn[@id='name1']">...</xsl:template> 
<xsl:template match="dyn[@id='name2']">...</xsl:template> 
<xsl:template match="dyn[@id='name3']">...</xsl:template> 

,然後用<xsl:apply-templates select="dyn"/>做發貨。

0

如果您使用的是舊撒克遜-B或更新撒克遜-PE或撒克遜-EE作爲XSLT處理器,您可以使用撒克遜擴展,以實現動態模板調用:

<xsl:variable name="templateName"> 
    <xsl:value-of select="dyn/@id"/> 
</xsl:variable> 

<saxon:call-template name="{$templateName}"/> 

不要忘了在xsl-stylesheet元素中聲明撒克遜命名空間:

<xsl:stylesheet xmlns:saxon="http://saxon.sf.net/" [...] >