XQuery 不负责数据映射,而是通过表达式将源 XML 节点关系转换为目标格式;需注意空序列语义、命名空间作用域、typeswitch 处理异构内容及 map/array 函数的正确使用。

XQuery 本身不负责“数据映射”——它不生成或修改 XML 结构,而是查询和构造结果。所谓“映射”,实际是用 XQuery 表达式把源 XML 的节点关系,转换成目标格式(如扁平化列表、嵌套 JSON 风格结构、关系表行等)。关键不在语法多高级,而在如何精准控制上下文、避免隐式重复、处理空值与命名空间。
用 for $x in ... return 替代隐式 FLWOR 循环陷阱
常见错误:直接对一个可能为空的节点集做 for $x in /root/item,结果整个表达式返回空序列(因 /root/item 不存在时,for 不执行任何迭代)。这不是 bug,是 XQuery 的空序列语义决定的。
实操建议:
- 先用
exists()或count()显式判断是否存在,再进入循环; - 更稳妥的做法是用
if (exists(/root/item)) then for $x in /root/item return ... else (); - 若需保底输出(比如空数组),用
(/root/item,这类“兜底取首项”技巧(注意类型一致性)。- )[1]
map:merge() 与 array:join() 构建嵌套结构(XQuery 3.1+)
当目标格式接近 JSON 对象或数组(如 REST API 响应),原生 XML 构造器写法冗长且难维护。XQuery 3.1 引入的函数式集合操作能显著提升可读性。
示例:把多个 转为 map 数组
array:join(
for $p in /people/person
return map {
"id": $p/@id/string(),
"name": $p/name/string(),
"tags": array { $p/tag/string() }
}
)
注意点:
AJAX即“Asynchronous Javascript And XML”(异步JavaScript和XML),是指一种创建交互式网页应用的网页开发技术。它不是新的编程语言,而是一种使用现有标准的新方法,最大的优点是在不重新加载整个页面的情况下,可以与服务器交换数据并更新部分网页内容,不需要任何浏览器插件,但需要用户允许JavaScript在浏览器上执行。《php中级教程之ajax技术》带你快速
-
map:merge()适合合并同 key 的多层结构,但会静默覆盖重复键——需提前用group by或distinct-values()处理; -
array:join()比for ... return更明确表达“聚合为单一数组”的意图,且对空序列返回空数组而非空序列; - 所有
string()调用不可省略:XQuery 不自动原子化节点,未转字符串直接塞进 map 会导致类型错误。
用 typeswitch 处理混合内容与异构子节点
真实 XML 常含混合内容(文本+元素)、可选子节点、不同命名空间下的同名标签。硬写 $node/name/text() 极易在某处断裂。
实操建议:
- 用
typeswitch ($node)分支处理:case element(name) return $node/string()、case text() return normalize-space($node)、default return ""; - 对可能带命名空间的节点,别依赖
name($node) = "name",改用local-name($node) = "name"并配合namespace-uri($node)校验; - 若需保留原始空白但过滤注释,用
$node/node()[not(self::comment())]而非$node/*。
declare namespace 与 declare default element namespace 的作用域差异
命名空间声明不是全局配置,其生效范围严格限于所在模块(module)或主查询体。很多人误以为在 prolog 中声明一次就能通吃所有路径表达式。
关键区别:
-
declare namespace ns = "http://example.com";仅影响后续使用ns:elem的显式前缀调用; -
declare default element namespace "http://example.com";让所有无前缀的元素名(如elem)自动绑定该 NS,但 不影响属性名(属性默认无命名空间); - 跨模块复用时,每个模块必须独立声明;XQuery 处理器(如 eXist-db、BaseX)不继承外部模块的默认命名空间。
最常被忽略的是:XPath 路径中写 /root/item 时,若 root 在默认命名空间下,这个表达式实际查的是无命名空间的 root——必须写成 /ns:root/ns:item 或启用默认命名空间声明。









