XSLT:具有扩展值的 Xpath 查询在不存在此类节点时返回"node exists"



请考虑以下代码:

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format">
    <xsl:template name="getServiceDef">
        <services>
            <service>
                <serviceName>service</serviceName>
                <parameters>
                    <param1/>
                    <param2/>
                    <param3/>
                </parameters>
            </service>
        </services>
    </xsl:template>
    <xsl:template name="getInput">
        <parameters>
            <param1>10</param1>
            <param2>single</param2>
            <param3>2</param3>
            <param4>650</param4>
            <param5>750</param5>
        </parameters>
    </xsl:template>
    <xsl:template match="/">
        <xsl:variable name="serviceDef">
            <xsl:call-template name="getServiceDef"/>
        </xsl:variable>
        <xsl:variable name="inputParameters">
            <xsl:call-template name="getInput"/>
        </xsl:variable>
        <xsl:for-each select="$inputParameters/parameters/param4">
            <xsl:variable name="currentParameterName" select="./local-name()"/>
            <xsl:choose>
                <xsl:when test="$serviceDef/services/service/parameters/$currentParameterName">
                    <xsl:message>
                        $currentParameterName '<xsl:value-of select="$currentParameterName"/>'exists.
                        $serviceDef/services/service/parameters/param4 '<xsl:value-of select="$serviceDef/services/service/parameters/param4"/>'
                        $serviceDef/services/service/parameters/$currentParameterName '<xsl:value-of select="$serviceDef/services/service/parameters/$currentParameterName"/>' 
                    </xsl:message>
                </xsl:when>
                <xsl:otherwise>
                    <xsl:message>param '<xsl:value-of select="$currentParameterName"/>' does NOT exist</xsl:message>
                </xsl:otherwise>
            </xsl:choose>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

在以行开头的代码块中

<xsl:for-each select="$inputParameters/parameters/param4"> 

我试图决定节点是否也存在于$serviceDef中。它没有。但是,如果使用扩展变量执行 XPATH 查询,则查询将评估为"节点存在"(下面的控制台输出(。

问题:为什么要查询$serviceDef/services/service/parameters/param4 返回 "False" 和$serviceDef/服务/服务/参数/$currentParameterName返回"True" ?我希望查询是相同的。

要复制:

  1. 将上面的代码复制到文件堆栈OverFlowReplication.xsl

  2. 笔记本电脑:~$ 回显"><不需要 />">样本.xml

  3. laptop:~$ java -jar saxon9pe.jar -s:sample.xml -xsl:stackOverFlowReplication.xsl

控制台输出:

No license file found - running with licensable features disabled
Warning at xsl:stylesheet on line 2 column 125 of stackOverFlowReplication.xsl:
  Running an XSLT 10 stylesheet with an XSLT 20 processor
        $currentParameterName 'param4'exists.
        $serviceDef/services/service/parameters/param4 ''
        $serviceDef/services/service/parameters/$currentParameterName 'param4' 

您似乎希望test="$serviceDef/services/service/parameters/$currentParameterName"根据您在最后一步中插入的变量在运行时构造 XPath 表达式。这不会发生,您只需在最后一步中计算变量引用$currentParameterName,它就会计算为字符串param4和布尔上下文中的任何非空字符串,例如xsl:when/xsl:if test的计算结果为 true。

您需要使用 XSLT 3.0 中提供的xsl:evaluate进行动态 XPath 评估,或者对于您可以使用的简单情况,例如 test="$serviceDef/services/service/parameters/*[local-name() = $currentParameterName]" .

若要了解表达式的计算结果,请参阅 http://xsltransform.net/naZXpX1

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:fo="http://www.w3.org/1999/XSL/Format" xmlns:xs="http://www.w3.org/2001/XMLSchema"
    exclude-result-prefixes="xs fo">
    <xsl:template name="getServiceDef">
        <services>
            <service>
                <serviceName>service</serviceName>
                <parameters>
                    <param1/>
                    <param2/>
                    <param3/>
                </parameters>
            </service>
        </services>
    </xsl:template>
    <xsl:template name="getInput">
        <parameters>
            <param1>10</param1>
            <param2>single</param2>
            <param3>2</param3>
            <param4>650</param4>
            <param5>750</param5>
        </parameters>
    </xsl:template>
    <xsl:template match="/">
        <xsl:variable name="serviceDef">
            <xsl:call-template name="getServiceDef"/>
        </xsl:variable>
        <xsl:variable name="inputParameters">
            <xsl:call-template name="getInput"/>
        </xsl:variable>
        <xsl:for-each select="$inputParameters/parameters/param4">
            <xsl:variable name="currentParameterName" select="./local-name()"/>
            <xsl:variable name="exp1" select="$serviceDef/services/service/parameters/$currentParameterName"/>
            <debug-help string-sequence-test="{$exp1 instance of xs:string*}" node-sequence-test="{$exp1 instance of node()*}" value="{$exp1}"/>
        </xsl:for-each>
    </xsl:template>
</xsl:stylesheet>

它输出<debug-help string-sequence-test="true" node-sequence-test="false" value="param4"/>,因此它表明您永远不会有节点序列,而只是带有变量值的单个字符串序列。

最新更新