在 XQuery 中,“选择”和“过滤”是最核心、最常用的操作。下面系统地用清晰例子告诉你怎么写,各种场景全部覆盖。
1. 基本路径选择(XPath 表达式)
(: 选择所有 book 元素 :)
/books/book
(: 选择根下第一层 bookstore 下的所有 book :)
bookstore/book
(: 选择整个文档所有 book(任意层级):)
//book
(: 选择有 title 属性的 book :)
//book[@title]
(: 选择价格小于 30 的书 :)
//book[price < 30]
2. 常用过滤(谓语 [])写法大全
| 需求 | XQuery 写法 | 说明 |
|---|---|---|
| 第 n 个元素 | //book[1] | 第一个 book |
| 最后 1 个元素 | //book[last()] | 最后一个 |
| 最后 3 个元素 | //book[position() > last()-3] | 倒数 3 本书 |
| 第 3 到第 8 个 | //book[position() >= 3 and position() <= 8] | 或者简写成 [position() = 3 to 8] |
| 倒序取前 5 本 | reverse(//book)[position() <= 5] | XQuery 3.0+ |
| 价格在 20~50 之间 | //book[price >= 20 and price <= 50] | 常见 |
| 价格排序后取最便宜的前 3 本 | for $b in //book order by xs:decimal($b/price) ascending return $b[position() <= 3] | 推荐写法 |
| 类别是 “WEB” 且有库存 | //book[@category=”WEB” and stock > 0] | 多条件 and |
| 类别是 “WEB” 或 “XML” | //book[@category=”WEB” or @category=”XML”] | or 也可以写成 |
| //book[@category = (“WEB”, “XML”)] | 推荐!更简洁 | |
| 标题包含 “XQuery” (不区分大小写) | //book[contains(lower-case(title), “xquery”)] | XQuery 3.0 |
| 标题以 “Learning” 开头 | //book[starts-with(title, “Learning”)] | |
| 作者姓名包含 “Priscilla” | //book[author[contains(., “Priscilla”)]] | . 表示当前上下文节点文本 |
| 有多个作者,取至少有一个是中国作者的书 | //book[author = (“王磊”, “张三”, “李雷”)] | |
| 出版年份是 2020 年以后 | //book[year >= 2020] | |
| 没有 category 属性 | //book[not(@category)] | |
| 有 price 子元素但值为空 | //book[price and not(string(price)) ] |
3. FLWOR 语句:最强大、最灵活的“选择 + 过滤”方式
(: 1. 基本 FLWOR :)
for $book in //book
where $book/price < 30
order by $book/price descending
return $book/title
(: 2. 返回自定义结构 :)
for $b in //book
where $b/@category = "WEB"
order by xs:decimal($b/price)
return
<item>
<title>{ $b/title/text() }</title>
<price discount="10%">{ $b/price * 0.9 }</price>
</item>
(: 3. 分组统计(XQuery 3.0+) :)
for $cat in distinct-values(//book/@category)
let $books := //book[@category = $cat]
where count($books) >= 3
order by count($books) descending
return
<category name="{$cat}" count="{count($books)}"/>
(: 4. 前 10 本最贵的书(分页常见写法):)
for $b in //book
order by xs:decimal($b/price) descending
return $b
=> subsequence(1, 10) (: XQuery 3.1 箭头操作符,也可以用 [position()<=10] :)
4. 高级过滤技巧(实务中特别好用)
(: 模糊搜索标题包含 “xml” 或 “xquery”,不区分大小写 :)
let $keyword := "xml"
for $b in //book
where contains(lower-case($b/title), lower-case($keyword))
or contains(lower-case($b/author), lower-case($keyword))
return $b
(: 正则匹配(XQuery 3.0+) :)
//book[matches(title, "XQuery|XPath|XML", "i")] (: i 表示不区分大小写 :)
(: 深度过滤:取有至少一本价格 > 100 的类别的所有书 :)
let $expensive-cats := distinct-values(
//book[price > 100]/@category)
for $b in //book
where $b/@category = $expensive-cats
return $b
(: 条件返回不同结构(if 表达式):)
for $b in //book
return
if ($b/price > 80) then
<expensive>{ $b/title }</expensive>
else
<cheap>{ $b/title }</cheap>
5. 一句话总结“选”和“过滤”的最佳实践
| 场景 | 推荐写法 |
|---|---|
| 简单选择 | 直接 XPath://book[@category=”WEB”] |
| 多条件、排序、分页 | 用 FLWOR(for/let/where/order by/return) |
| 需要分组、统计 | FLWOR + group by(XQuery 3.1) |
| 性能要求高(大数据) | 加索引 + 避免在 where 里做类型转换 |
| 模糊搜索 | contains() + lower-case() 或 matches() 正则 |
把上面这些记熟,你写 XQuery 的“选择和过滤”就基本无敌了!
如果你贴一段具体的 XML 和你想要的结果,我可以立刻给你最优的 XQuery 写法。