xsl:key 和 key() 是 XSLT 中预建哈希表式索引机制,通过“一次建表、多次查表”提升重复查找性能;xsl:key 在顶层声明索引规则,key() 函数依名查键值节点组,适用于关联、分组、去重等高效场景。

xsl:key 和 key() 是 XSLT 中用于构建和查询索引的核心机制,本质是“预建哈希表”,让重复查找某个字段(如 ID、类别、状态)时无需遍历全树,大幅提升性能。关键不在语法多复杂,而在理解它“一次建表、多次查表”的设计逻辑。
用 xsl:key 声明一个索引规则
它不执行查找,只定义“按什么条件把哪些节点归为一组”。必须写在顶层( 或 内,不能嵌套在模板中)。
- 语法:
-
name:索引名,自定义,后续
key()函数靠它引用 - match:指定哪些节点要被纳入这个索引(支持 XPath 模式)
- use:计算每个匹配节点的“键值”(字符串),相同键值的节点会被分到同一组
例如,给所有 按 category 属性建立索引:
用 key() 函数按键值快速取节点组
key($name, $key-value) 在任意上下文调用,返回所有 match 节点中、use 表达式结果等于 $key-value 的节点集合(保持原文档顺序)。
- 第一个参数必须是
xsl:key中定义的name字符串(加引号) - 第二个参数是动态计算的键值,可以是字面量(
'fiction')、变量($cat)、或表达式(current()/@ref) - 返回的是节点集,可直接用
遍历,或用count()、position()等函数处理
比如,在某处列出所有 category="tech" 的书:
典型高效场景:关联数据 & 去重统计
真正体现价值的地方,是避免 N×M 嵌套循环。
-
主从关联(类似 SQL JOIN):有
和,用key('products', @product-id)直接拉出对应商品,不用//product[@id = current()/@product-id]全局扫描 -
分组统计:先用
xsl:key按城市分组客户,再用key('customers', 'shanghai')拿到全部上海客户,count()一下就是人数 -
去重输出:配合
generate-id()判断是否首见(generate-id() = generate-id(key('by-name', @name)[1])),比not(@name = preceding-sibling::*/@name)快得多
注意事项:作用域与性能真相
看似简单,但几个细节决定是否真高效:
-
xsl:key是全局声明,但索引构建发生在整个输入文档加载后、模板匹配前 —— 所以它对整个文档生效,不随当前模板变化 - 键值(
use表达式结果)自动转为字符串;若需多字段组合键,用concat(a, '|', b),确保分隔符不会出现在原始值中 - 不要为小数据(几十个节点)滥用;XSLT 处理器建索引本身有开销,节点少时线性查找反而更快
- XSLT 1.0 中
key()只能查当前文档(document('')除外);XSLT 2.0+ 支持跨文档索引(用key('k', 'v', $doc))










