XSL模板优先级

时间:2014-04-09 14:54:55

标签: xml xslt

我有一个XSL样式表,需要针对两个不同的XML输入应用 - 成功响应和错误响应,并为每个输入返回有效的XML。

两个输入文档都具有相同的一般结构。我已尝试使用模板优先级来接近此功能,但这并不像我期望的那样 - 尽管优先级较低,但第一个模板始终在应用。

为什么这个模板优先应用于第二个模板,即使是成功的XML?如果我完全删除第一个模板,则第二个模板可以正确应用。

我能采取更好的方法吗?

成功回应:

<SOAP_Domain_Msg xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <Context>
        <Namespace xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"/>
    </Context>
    <Header/>
    <Body>
        <GetCustomerResponse>
            <Title>Mr</Title>
            <FirstName>Test</FirstName>
            <Surname>Person</Surname>
        </GetCustomerResponse>
    </Body>
</SOAP_Domain_Msg>

错误回复:

<SOAP_Domain_Msg xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
    <Context>
        <SOAP_Version>1.1</SOAP_Version>
        <Namespace xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"/>
    </Context>
    <Body>
        <soapenv:Fault>
            <faultcode>soapenv:Server</faultcode>
            <faultstring>2014-04-09T14:16:41: InternalFault</faultstring>
            <detail/>
        </soapenv:Fault>
    </Body>
</SOAP_Domain_Msg>

XSLT:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
  <xsl:template match="SOAP_Domain_Msg" priority="-1">
        <xsl:copy-of select="Body" />
  </xsl:template>
  <xsl:template match="Body/GetCustomerResponse" priority="0">
        <Applicants>
            <Applicant1>
                <xsl:if test="CustomerID != ''">
                    <Id>
                        <xsl:value-of select="CustomerID" />
                    </Id>
                </xsl:if>
                <xsl:if test="Title != ''">
                    <Title>
                        <xsl:value-of select="Title" />
                    </Title>
                </xsl:if>
                <xsl:if test="FirstName != ''">
                    <Forename1>
                        <xsl:value-of select="FirstName" />
                    </Forename1>
                </xsl:if>
                <xsl:if test="Surname != ''">
                    <Name>
                        <xsl:value-of select="Surname" />
                    </Name>
                </xsl:if>
            </Applicant1>
        </Applicants>
    </xsl:template>
</xsl:stylesheet>

1 个答案:

答案 0 :(得分:1)

当您有两个可以同时应用于同一节点的模板时,priority用于断开关系。

使用样式表,处理将从文档根节点(/)开始。没有与此节点匹配的显式模板,因此默认行为将启动,即apply-templates此节点的所有子节点。接下来,模板匹配器将尝试找到可与文档元素匹配的模板(/SOAP_Domain_Msg)。只有一个这样的模板:

<xsl:template match="SOAP_Domain_Msg" priority="-1">
    <xsl:copy-of select="Body" />
</xsl:template>

这样模板就会触发。由于此模板不包含任何apply-templates指令,因此这是流程的结束,最终结果将是原始Body元素的副本。

如果您删除此模板,那么您将获得SOAP_Domain_Msg的默认行为,即apply-templates给孩子的行为,依此类推。这将达到尝试将模板应用于GetCustomerResponse的程度,此时您的其他模板将会触发(与此同时,处理器会将默认模板应用于Context,{{1 }}和Namespace元素也是如此,但由于它们中没有一个包含任何文本内容,除了空格外,它们不会产生任何明显的输出。)

我会以稍微不同的方式构建一些东西,从身份模板开始(除非你另外说明,否则按原样复制所有内容),然后根据需要添加特殊情况。

Header

您不想更改的内容(故障情况和成功案例中的<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> <xsl:template match="@*|node()"> <xsl:copy><xsl:apply-templates select="@*|node()" /></xsl:copy> </xsl:template> <xsl:template match="/"> <xsl:apply-templates select="SOAP_Domain_Msg/Body/*" /> </xsl:template> <xsl:template match="GetCustomerResponse"> <Applicants> <Applicant1> <xsl:apply-templates select="CustomerID | Title | FirstName | Surname" /> </Applicant1> </Applicants> </xsl:template> <xsl:template match="CustomerID"> <Id><xsl:apply-templates /></Id> </xsl:template> <xsl:template match="FirstName"> <Forename1><xsl:apply-templates /></Forename1> </xsl:template> <xsl:template match="Surname"> <Name><xsl:apply-templates /></Name> </xsl:template> </xsl:stylesheet> 元素)不需要特定的模板。