如何使用参数值模拟调用模板匹配?

时间:2011-08-08 12:00:22

标签: xslt xslt-2.0

我正在寻找将参数传递给模板匹配的解决方法。我知道这在XPath中是不允许的,因此我正在寻找一个'计划B'解决方案。

这是我希望的工作:

xslt(2.0)的第1部分:

<xsl:template match="/">
    <xsl:for-each select="//Main/PageList/Page">
    <xsl:result-document href="{@ID}.xml">
        <Page ID="{@ID}">
            <xsl:apply-templates select="node()">
                <xsl:with-param name="theID" select="@ID"/>
            </xsl:apply-templates>
        </Page>
    </xsl:result-document>
    </xsl:for-each> 
</xsl:template>

如此相当简单,不要理会使用的标签,它本质上是通过一个节点,并为每个节点创建一个XML文件。每个节点都以一个ID开头,我想为其他模板提供这个ID。不幸的是,这适用于命名模板,但它不适用于匹配的模板(如果我至少正确理解了理论)

以下是我希望看到的工作:

<!-- identity template -->
    <xsl:template match="node()|@*">
    <xsl:param name="theID"/>
    <xsl:copy>
        <xsl:apply-templates select="node()|@*">
            <xsl:with-param name="theID" select="$theID"/>
        </xsl:apply-templates>
    </xsl:copy>
</xsl:template>

<!-- lots of templates here doing what I want them to do -->

<!-- one template creating an issue -->

<xsl:template match="@src">
<!-- would be nice to know the current ID, but unfortunately this one stays empty... -->
<xsl:param name="theID"/>

<!-- clean current attribute a bit -->
<xsl:variable name="S1" select="replace(.,'\.\.\/','')"/>

<xsl:attribute name="src">
<xsl:choose>
<xsl:when test="contains($S1,'common')">
<!-- just use current value, don't bother about current ID -->
    <xsl:value-of select="$S1"/>
</xsl:when>
<xsl:otherwise>
    <!-- use ID parameter -->
    <xsl:value-of select="concat($theID,'_',$S1)"/>
</xsl:otherwise>
</xsl:choose>
</xsl:attribute>
</xsl:template>

不要看这样的代码,它只是整个文件的一小部分,但实质是我想在另一个模板中使用我的第一部分(match =“/”)中的ID参数(match =“@ src”),但这似乎相当复杂。

我错过了什么吗?如果我运气不好而且确实不可能,那么有人会建议我如何继续吗?

提前致谢!

2 个答案:

答案 0 :(得分:1)

您的问题在这里

<xsl:apply-templates select="node()">
  <xsl:with-param name="theID" select="@ID"/>
</xsl:apply-templates>

select属性指定处理应该在当前节点的任何子节点上继续。

但是node()只选择子节点(元素,文本节点,处理说明和注释) - 而不是属性

<强>解决方案

  1. 要直接处理当前节点的(所有)属性,请使用:
  2. -

    <xsl:apply-templates select="@*">
      <xsl:with-param name="theID" select="@ID"/>
    </xsl:apply-templates>
    

    0.2。 为了仅处理当前节点的src属性的处理:

    -

    <xsl:apply-templates select="@src">
      <xsl:with-param name="theID" select="@ID"/>
    </xsl:apply-templates>
    

    0.3。为了间接处理当前节点后代的属性,请执行:

    -

    <xsl:apply-templates select="node()|@*">
      <xsl:with-param name="theID" select="@ID"/>
    </xsl:apply-templates>
    

    您还必须确保处理node()的任何模板必须具有名为xsl:param的{​​{1}},并且必须在任何theID指令中传递此参数< /强>

    在实践中,这意味着您将覆盖所有XSLT内置模板,因为他们不了解您的xsl:apply-templates

答案 1 :(得分:0)

我认为不是

        <xsl:apply-templates select="node()">
            <xsl:with-param name="theID" select="@ID"/>
        </xsl:apply-templates>

你想要

        <xsl:apply-templates select="node()">
            <xsl:with-param name="theID" select="parent::Page/@ID"/>
        </xsl:apply-templates>

假设您要传递父ID元素的Page属性。

另一方面,select="node()"选择任何子节点,如子元素,子注释节点,子文本节点,子处理指令节点,所以我不明白为什么你以后显示匹配属性节点的模板