local-name()返回节点本地名称(冒号后部分),忽略前缀和命名空间;name()返回源文档中带前缀的完整名称(若存在前缀),否则返回本地名。前者适用于跨命名空间匹配,后者多用于调试。

当XML文档使用命名空间时,local-name() 和 name() 的行为差异很关键:前者只返回元素或属性的本地名称(去掉前缀和命名空间),后者返回带前缀的完整名称(如果存在前缀)或无前缀的名称(如果没声明前缀)。
local-name():只取“名字本身”,无视命名空间和前缀
local-name() 总是返回节点的本地部分(local part),也就是冒号 : 后面那一段,没有前缀、没有URI、不依赖上下文绑定。即使节点属于某个命名空间,它也完全忽略。
- 对
,local-name(/ns:book)→"book" - 对
(默认命名空间),local-name(/book)→"book"(依然有效) - 对属性
,local-name(@id)→"id"
name():返回带前缀的“全名”,但依赖XPath引擎是否保留前缀信息
name() 返回的是节点在源文档中实际使用的名称形式——包括前缀(如果写了),但不包含命名空间URI。它的结果取决于解析器是否保留了前缀绑定,以及节点是否显式用了前缀。
- 对
,name(/ns:book)→"ns:book"(前提是解析器保留了ns前缀) - 对
(默认命名空间,无前缀),name(/book)→"book"(没前缀,所以就是本地名) - 注意:如果解析器做了命名空间规范化(比如某些DOM实现),可能把带前缀的节点转成无前缀+默认命名空间,此时
name()也可能返回"book",而非"ns:book"
为什么 local-name() 更常用于跨命名空间匹配?
因为真实XML中,前缀是任意的(ns、abc、my 都可能映射同一URI),而本地名才是语义核心。用 local-name() 可以安全地写不依赖前缀的表达式:
- 匹配任意前缀下的
book元素://*[local-name()='book'] - 匹配默认命名空间 + 带前缀命名空间中的同名元素,一条表达式搞定
- 而
name()='ns:book'很脆弱——换一个前缀就失效
name() 的适用场景有限,通常只用于调试或特殊判断
name() 主要价值在于观察原始文档结构,比如检查某个节点是否用了特定前缀,或区分同名但不同前缀的元素(虽然少见)。生产级XPath一般避免依赖它做逻辑判断,除非你明确控制输入格式且前缀固定。
基本上就这些。记住一个口诀:local-name 看“是什么”,name 看“怎么叫”——而 XML 的本质意义在“是什么”。










