2011-04-13 95 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/" [...] >