XQuery 查询语言
本章定位 :掌握 XQuery 的 FLWOR 表达式核心语法,理解它作为"XML 世界的 SQL"的定位——如何用类 SQL 的声明式语句查询、过滤、排序和重组 XML 数据。
定义与作用
XQuery (XML Query Language)是 W3C 制定的 XML 数据查询语言标准(2007 年成为推荐标准)。它的定位非常精准:
如果说 SQL 是关系数据库的查询语言,那么 XQuery 就是 XML 数据的查询语言。
XQuery 能做什么?
- 从 XML 文档中提取和过滤元素
- 生成汇总报告
- 将 XML 转换为 XHTML
- 搜索 Web 文档中的相关信息
- 在 Web Service 中作为数据提取层
核心原理:FLWOR 表达式流程
图解释 :FLWOR(读作 flower)是 XQuery 的核心——For(迭代)、 Let(绑定)、 Where(过滤)、 Order by(排序)、 Return(输出)。每个子句对应关系代数的一个操作:For=投影、Where=选择、Order by=排序、Return=投影。
语法/结构要点
XQuery 基本语法
| 组件 | 语法 | 作用 |
|---|---|---|
| FLWOR 表达式 | for $var in path ... return ... | 核心查询结构 |
| 条件过滤 | where $var/element > value | 筛选数据 |
| 排序 | order by $var/element [ascending|descending] | 排序结果 |
| 文档函数 | doc("filename.xml") | 加载 XML 文档 |
| 集合函数 | collection("path/") | 加载目录下所有 XML |
| 条件函数 | if (condition) then ... else ... | 条件表达式 |
| 元素构造 | <tag>{expression}</tag> | 动态创建 XML 元素 |
| 属性构造 | attribute name {expression} | 动态创建属性 |
| 用户函数 | declare function local:name() { ... } | 自定义函数 |
XQuery 与 XPath 的关系
XQuery 1.0 和 XPath 2.0 共享同一套数据模型和函数库 。XPath 表达式可以出现在 XQuery 中任何允许表达式的位置——掌握了 XPath,XQuery 就掌握了大半。
XQuery vs SQL 对比
| 操作 | SQL | XQuery(FLWOR) |
|---|---|---|
| 选择所有 | SELECT * FROM table | for $x in doc("file.xml")//record return $x |
| 条件过滤 | WHERE price > 30 | where $x/price > 30 |
| 排序 | ORDER BY title ASC | order by $x/title ascending |
| 计数 | COUNT(*) | count($results) |
| 连接 | JOIN | 嵌套 FLWOR |
| 分组 | GROUP BY | let $groups := ... |
完整示例
场景说明
飞翔科技的 大翔 维护着一份 XML 格式的技术图书目录 books.xml。产品经理需要一个"定价超过 30 元、按书名排序"的清单。大翔用 XQuery 一条语句解决。
操作前:原始 XML 数据
books.xml :
<?xml version="1.0" encoding="UTF-8"?>
<bookstore>
<book category="编程">
<title lang="zh">XML入门指南</title>
<author>大翔</author>
<year>2025</year>
<price>59.00</price>
</book>
<book category="编程">
<title lang="en">Learning XML</title>
<author>Erik T. Ray</author>
<year>2003</year>
<price>39.95</price>
</book>
<book category="架构">
<title lang="zh">微服务设计</title>
<author>白歌</author>
<year>2024</year>
<price>79.00</price>
</book>
<book category="编程">
<title lang="zh">Java核心技术</title>
<author>Cay S. Horstmann</author>
<year>2022</year>
<price>25.50</price>
</book>
<book category="管理">
<title lang="zh">人月神话</title>
<author>Frederick Brooks</author>
<year>1975</year>
<price>49.00</price>
</book>
</bookstore>
应用 XQuery:查询 + 过滤 + 排序
XQuery 语句 :
(: 查询价格 > 30 的书,按书名排序,返回 HTML 片段 :)
<ul>
{
for $book in doc("books.xml")/bookstore/book
where $book/price > 30
order by $book/title ascending
return
<li>
<strong>{data($book/title)}</strong>
— {data($book/author)},¥{data($book/price)}
</li>
}
</ul>
操作结果
<ul>
<li>
<strong>Learning XML</strong> — Erik T. Ray,¥39.95
</li>
<li>
<strong>XML入门指南</strong> — 大翔,¥59.00
</li>
<li>
<strong>人月神话</strong> — Frederick Brooks,¥49.00
</li>
<li>
<strong>微服务设计</strong> — 白歌,¥79.00
</li>
</ul>
查询过程 :5 本书 → where price > 30 过滤掉 Java核心技术(25.50)→ 剩下 4 本 → order by title 按字母排序 → 构造 HTML <li> 输出。
进阶示例:嵌套 FLWOR(类 JOIN 操作)
需求 :按分类汇总图书数量和总价。
for $cat in distinct-values(doc("books.xml")/bookstore/book/@category)
let $books := doc("books.xml")/bookstore/book[@category = $cat]
order by $cat
return
<category>
<name>{$cat}</name>
<count>{count($books)}</count>
<total>{sum($books/price)}</total>
</category>
输出 :
<category><name>编程</name><count>3</count><total>124.45</total></category>
<category><name>管理</name><count>1</count><total>49.00</total></category>
<category><name>架构</name><count>1</count><total>79.00</total></category>
易错场景
忘记 data() 函数
return <li>{$book/title}</li>
<!-- 输出:<li><title lang="zh">XML入门指南</title></li> -->
不加 data() 或 text() 会把整个元素节点复制过来。正确写法:{data($book/title)} 或 {$book/title/text()}。
空序列的 where 比较
where $book/sale_price > 30
如果某些 <book> 元素没有 <sale_price> 子元素,该书的比较结果是空序列 (),where 将其视为 false——该书被静默跳过。需要防御性写法:where $book/sale_price and $book/sale_price > 30。
FLWOR 顺序错误
where $x/category = "编程" -- for 之前不能有 where
for $x in doc("books.xml")/bookstore/book
FLWOR 子句有严格顺序:for/let → where → order by → return。不能颠倒。
面试考点
| 考点 | 参考答案要点 |
|---|---|
| FLWOR 每个字母代表什么? | For(迭代), Let(绑定变量), Where(过滤), Order by(排序), Return(输出结果) |
| XQuery 和 XPath 是什么关系? | XPath 2.0 和 XQuery 1.0 共享同一数据模型和函数库。XPath 是 XQuery 的子集——XQuery 增加了 FLWOR、元素构造、函数定义等 |
| XQuery 和 SQL 的核心差异? | SQL 操作表(二维);XQuery 操作 XML 树(层次结构)。XQuery 能查询不规则的层次数据,SQL 对树形结构较吃力 |
| doc() 和 collection() 的区别? | doc() 加载单个 XML 文档;collection() 加载目录下所有 XML 文档的集合 |