3

我试图保持我的 xsl 干燥,因此我想为 XML 文档的 2 个部分调用相同的模板,这些部分恰好是相同的复杂类型(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 个不同部分的更好方法,那么这也真的能帮助我吗?

谢谢

戴夫

4

2 回答 2

9

您是从错误的一端开始的(错误的一端几乎总是:试图将命令式编程范式应用于 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 - 您唯一的工作就是为您希望以特殊方式处理的那些节点提供匹配的模板。

You can drop in a custom template for those nodes that need special treatment and trust your XSLT processor with calling it once they come up. All you need to make sure in your templates is that traversal goes on by declaring an appropriate <xsl:apply-templates />.

于 2010-03-24T17:16:47.273 回答
2

为什么不做模板

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

并进行测试以确定模板内的输出元素名称?

于 2010-03-24T17:11:12.313 回答