XPath的namespace-uri()函数怎么获取节点命名空间

namespace-uri()函数返回节点实际归属的命名空间URI而非前缀,语法为namespace-uri(node),默认作用于当前节点;它不能枚举文档中所有命名空间声明,仅能查询已有节点的URI。

namespace-uri() 函数用于返回指定节点的命名空间 URI(即命名空间的地址,如 http://www.w3.org/1999/xhtml),而不是前缀(如 htmlxs)。它本身不“获取”命名空间声明,而是读取节点**实际归属的命名空间 URI**——这个 URI 是由该节点被创建时所处的上下文(比如元素的 xmlns 或带前缀的 xmlns:prefix="..." 声明)决定的。

怎么用 namespace-uri() 获取节点的命名空间 URI

语法很简单:namespace-uri(node)。如果不传参数,默认作用于当前上下文节点(.)。

  • 获取当前元素的命名空间 URI:直接写 namespace-uri()namespace-uri(.)
  • 获取某个子元素的命名空间 URI:比如 namespace-uri(child::book)namespace-uri(./book)
  • 配合谓词筛选特定命名空间的节点:例如 //book[namespace-uri() = 'http://example.com/ns'],只选属于该 URI 的 book 元素

注意:namespace-uri() 返回的是 URI,不是前缀

命名空间前缀(如 xs:ex:)只是别名,可变且无语义;真正起作用的是 URI。同一个 URI 可以用不同前缀声明,namespace-uri() 对所有情况都返回相同的 URI 字符串。

例如以下 XML 片段:


  

ex:item 节点执行 namespace-uri(),结果是 "http://example.com/ns",不是 "ex"

常见误区:它不能列出文档中所有声明的命名空间

namespace-uri() 是节点级函数,只能查**已有节点**的归属命名空间。它无法枚举根元素上写的全部 xmlns:xxx="..." 声明(尤其是未被任何节点使用的声明)。XPath 1.0 / 2.0 标准中没有内置函数能“遍历命名空间表”。如果需要获取所有声明,得靠宿主语言(如 Python 的 lxml、Java 的 JAXP)通过 DOM/SAX 接口专门提取。

在带命名空间的文档中写 XPath 要注意上下文绑定

很多 XPath 引擎(如浏览器 DevTools、lxml、Saxon)默认不自动识别 XML 中的 xmlns 前缀绑定。即使节点有命名空间,直接写 //book 通常匹配不到——因为无前缀的 book 被视为“无命名空间”,而实际节点属于某 URI。

  • 正确做法:注册命名空间前缀(如把 ex 绑定到 http://example.com/ns),再用 //ex:book
  • 或绕过前缀,用 local-name() + namespace-uri() 组合:例如 //*[local-name()='book' and namespace-uri()='http://example.com/ns']

基本上就这些。记住核心:namespace-uri() 是“读值”函数,反映节点真实归属,不是“解析声明”的工具。用它定位节点很可靠,但想反向查文档里写了哪些 xmlns,就得换方法。