XSLT1.0中经str:replace处理的变量传入key()返回false是何原因?
问题根因
你遇到的问题和key()、str:replace()本身的功能缺陷无关,核心是XSLT 1.0中key()函数的查询上下文规则导致的:key()函数默认会在「当前上下文节点所属的文档」中匹配节点,你在遍历$fruits-list的时候,上下文节点已经切换到了local-namespace.xsl文档里的lcl:fruit节点,此时调用key()会去local-namespace.xsl里查找匹配项,而你的fruitsKey是定义在源文件fruits.xml的结构上的,自然查不到结果。
疑问解答
XSLT1.0的
key()函数是否存在相关缺陷?
不存在,这是符合规范的设计。XSLT 1.0的key()始终绑定当前上下文所属的文档,当处理多文档(比如你这里用document('')读取了当前XSL文件本身作为额外数据源)时,切换上下文节点就会切换key()的查询目标文档。str:replace()是否会对返回值产生未预见的变更?
不会。你打印的结果已经验证替换后的字符串和预期完全一致,问题和字符串替换过程没有任何关系。有什么方法可以定位该问题的原因?
可以通过以下两个方向排查:
- 排除替换逻辑的影响:直接把固定值
'fresh-apple'赋值给$selector再调用key(),如果仍然返回false,就可以确认问题和替换逻辑无关。 - 打印当前上下文信息:在调用
key()前输出base-uri(.)(当前节点所属文档的路径)、name(.)(当前节点名称),就能发现此时上下文已经不在fruits.xml中。
修复方案
只需要在调用key()时把上下文切回源文档fruits.xml即可,修改代码如下:
- 先在遍历
$fruits-list前存储源文档的根节点:
<xsl:template match="fruits/fruit-selector"> <xsl:variable name="currentfruitElement" select="."/> <!-- 存储源文档根节点,后续用来切换上下文 --> <xsl:variable name="source-root" select="/"/> <xsl:for-each select="$fruits-list"> <xsl:call-template name="CheckFruits"> <xsl:with-param name="fruitElement" select="$currentfruitElement"/> <xsl:with-param name="currentFruit" select="."/> <!-- 把源文档根节点作为参数传入 --> <xsl:with-param name="source-root" select="$source-root"/> </xsl:call-template> </xsl:for-each> </xsl:template>
- 在
CheckFruits模板中切换上下文后再调用key():
<xsl:template name="CheckFruits"> <xsl:param name="fruitElement"/> <xsl:param name="currentFruit"/> <xsl:param name="source-root"/> <xsl:variable name="selector" select="str:replace($fruitElement, '${FRUIT-NAME}', string($currentFruit))"/> <!-- 切换上下文到源文档,再调用key --> <xsl:for-each select="$source-root"> <xsl:if test="not(key('fruitsKey', $selector))"> <Error><xsl:value-of select="concat('Fruit element: ', $selector, ' is not available')"/></Error> </xsl:if> </xsl:for-each> </xsl:template>
修改后执行就不会再误报错误了。
涉及核心概念补充
- 上下文节点:XSLT处理过程中当前正在操作的节点,所有相对路径查询、上下文相关函数(比如
key()、current())的行为都依赖这个节点。 - 多文档处理上下文切换:当你用
document()函数读取其他XML/XSL文件作为数据源时,只要选中了其他文档的节点作为当前上下文,后续的查询默认都会指向那个文档,需要主动切换回原文档才能操作原文档的节点。
内容的提问来源于stack exchange,提问作者DonBaka
相关产品推荐
相关产品推荐

