代码之家  ›  专栏  ›  技术社区  ›  CraftyFella

为相同复杂类型的不同节点名调用相同的xsl:template

  •  3
  • CraftyFella  · 技术社区  · 15 年前

    我试图让xsl保持干燥,因此我想为xml文档的两个部分调用相同的模板,这两个部分恰好是相同的复杂类型(contactdetails和altcontactdetails)。给定以下XML:

    <?xml version="1.0" encoding="UTF-8"?>
    <RootNode>
        <Name>Bob</Name>
        <ContactDetails>
            <Address>
                <Line1>1 High Street</Line1>
                <Town>TownName</Town>
                <Postcode>AB1 1CD</Postcode>
            </Address>
            <Email>test@test.com</Email>
        </ContactDetails>
        <AltContactDetails>
            <Address>
                <Line1>3 Market Square</Line1>
                <Town>TownName</Town>
                <Postcode>EF2 2GH</Postcode>
            </Address>
            <Email>bob@bob.com</Email>
        </AltContactDetails>
    </RootNode>
    

    我编写了一个xsl样式表,如下所示:

    <?xml version="1.0" encoding="UTF-8"?>
    <xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
        <xsl:template match="/">
            <PersonsName>
                <xsl:value-of select="RootNode/Name"/>
            </PersonsName>
            <xsl:call-template name="ContactDetails">
                <xsl:with-param name="data"><xsl:value-of select="RootNode/ContactDetails"/></xsl:with-param>
                <xsl:with-param name="elementName"><xsl:value-of select="'FirstAddress'"/></xsl:with-param>
            </xsl:call-template>
            <xsl:call-template name="ContactDetails">
                <xsl:with-param name="data"><xsl:value-of select="RootNode/AltContactDetails"/></xsl:with-param>
                <xsl:with-param name="elementName"><xsl:value-of select="'SecondAddress'"/></xsl:with-param>
            </xsl:call-template>
        </xsl:template>
        <xsl:template name="ContactDetails">
            <xsl:param name="data"></xsl:param>
            <xsl:param name="elementName"></xsl:param>
            <xsl:element name="{$elementName}">
                <FirstLine>
                    <xsl:value-of select="$data/Address/Line1"/>
                </FirstLine>
    
                <Town>
                    <xsl:value-of select="$data/Address/Town"/>
                </Town>
                <PostalCode>
                    <xsl:value-of select="$data/Address/Postcode"/>
                </PostalCode>
            </xsl:element>
        </xsl:template>
    </xsl:stylesheet>
    

    当我尝试运行样式表时,它向我抱怨我需要:

    若要在路径表达式中使用结果树片段,请使用exsl:node-set()或指定版本1.1

    我不想去1.1版..那么有人知道如何让exsl:node-set()在上面的示例中工作吗?

    或者如果有人知道一个更好的方法来应用相同的模板到两个不同的部分,那么这也会真正帮助我?

    谢谢

    戴夫

    2 回复  |  直到 10 年前
        1
  •  9
  •   Tomalak    15 年前

    您是从错误的一端(错误的一端几乎总是:尝试将命令式编程范式应用于xslt)。

    这很容易通过模板匹配来实现。

    <xsl:template match="RootNode">
      <PersonsName>
        <xsl:value-of select="Name"/>
      </PersonsName>
      <xsl:apply-templates select="ContactDetails|AltContactDetails" />
    </xsl:template>
    
    <xsl:template match="ContactDetails|AltContactDetails">
      <xsl:copy>
        <FirstLine>
          <xsl:value-of select="Address/Line1"/>
        </FirstLine>
        <Town>
          <xsl:value-of select="Address/Town"/>
        </Town>
        <PostalCode>
          <xsl:value-of select="Address/Postcode"/>
        </PostalCode>
      </xsl:copy>
    </xsl:template>
    

    放弃这样一个概念,即必须告诉xslt处理器该做什么(通过制作命名模板并将其称为“命令式样式”)。

    xslt处理器选择要调用的模板。从根开始( / )它递归地检查它访问的每个节点的匹配模板。它独自遍历输入的XML—您唯一的任务是为它提供与您希望以特殊方式处理的节点匹配的模板。

    您可以为那些需要特殊处理的节点插入一个自定义模板,并信任xslt处理器在它们出现时调用它。在模板中,您需要确保遍历是通过声明适当的 <xsl:apply-templates /> .

        2
  •  2
  •   Xenos    10 年前

    为什么不制作模板

    <xsl:template match="ContactDetails|AltContactDetails">
    

    然后执行测试以确定模板中的输出元素名称?

    推荐文章