You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

XSLT 2.0/3.0 遍历tokenize属性结果时上下文报错问题

问题根因

报错的核心是上下文项类型不匹配:

  • 执行xsl:for-each select="tokenize(.,'\s')时,循环内部的上下文项是tokenize返回的原子字符串值,不是XML节点。
  • XPath中以/开头的绝对路径,要求上下文项必须是节点(用于锚定所属文档的根节点),上下文为字符串时无法解析根路径,就会抛出Leading '/' selects nothing: the context item is not a node错误。
  • 之前用xsl:key无返回结果,是因为key函数默认在当前上下文项所属的文档内查找匹配节点,在字符串上下文下调用时没有文档锚点,自然查不到结果。
可落地方案

方案1:保留节点锚点修复原逻辑

如果不想用key,可在进入分词循环前提前缓存文档根节点,循环内用缓存的根作为XPath起点,避免依赖字符串上下文解析路径:

<xsl:template match="@cautionRefs | @warningRefs">
  <!-- 此时上下文还是属性节点,可正常获取所属文档根 -->
  <xsl:variable name="docRoot" select="root()"/>
  <!-- 分词时用\s+匹配多空格,加过滤条件跳过空值,兼容首尾/连续空格场景 -->
  <xsl:for-each select="tokenize(., '\s+')[normalize-space()]">
    <!-- 用current()取当前循环的分词ID,不要直接写.,避免和XPath步骤内的上下文节点混淆 -->
    <xsl:apply-templates select="$docRoot//*[@id = current()]"/>
  </xsl:for-each>
</xsl:template>

方案2:正确使用key提升性能(推荐,大文档下效率远高于全文档遍历)

你之前定义key的逻辑本身没问题,只要在节点上下文下调用key、传入分词后的ID序列即可,不需要额外写for-each循环:

<!-- 全局key定义,放在xsl:stylesheet根节点下、与模板同级 -->
<xsl:key name="elemById" match="*" use="@id"/>

<xsl:template match="@cautionRefs | @warningRefs">
  <!-- 此时上下文是属性节点,key可正常锚定当前文档,直接传入分词后的ID序列即可批量匹配节点 -->
  <xsl:apply-templates select="key('elemById', tokenize(., '\s+')[normalize-space()])"/>
</xsl:template>

key函数支持传入序列作为第二个参数,会自动返回所有匹配任意ID的节点,直接触发apply-templates后,就会自动匹配你已经写好的cautionRef、warningRef模板,拉取对应的声明内容输出,效果和你手写逐个ID调用apply-templates完全一致。

注意事项
  • 分词正则不要用单个\s,否则遇到连续多个空格会拆分出空字符串,导致匹配无效ID,用\s+加空值过滤的写法兼容性更好。
  • 循环内取当前分词值必须用current(),如果直接写$docRoot//*[@id = .],这里的.代表XPath遍历过程中的当前元素节点,不是外层分词循环的字符串值,会导致匹配逻辑错误。

内容的提问来源于stack exchange,提问作者Caroline

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.27 23:48:39