XQuery 的函数是日常写查询时最强大、最常用的工具。下面把你真正会用到的所有函数,按“使用频率”和“场景”分类,直接上干货 + 真实例子(基于 XQuery 3.1,最实用版本)。
1. 最常用 30 个内置函数(99% 的查询都靠它们)
| 类别 | 函数名 | 真实例子(直接可复制) | 说明 |
|---|---|---|---|
| 节点操作 | node-name() | node-name($book) → QName("", "book") | 取节点名 |
| name() | name($book) → "book" | 常用 | |
| local-name() | local-name($book) → "book" | 去前缀 | |
| exists() | exists(//book) → true/false | 判断是否存在 | |
| empty() | empty($book/price) → true(如果没有 price) | ||
| 字符串 | contains() | contains($title, "XQuery") | |
| starts-with() | starts-with($title, "Learning") | ||
| ends-with() | ends-with($isbn, "-01") | ||
| substring() | substring($isbn, 1, 10) | ||
| substring-before() / after() | substring-before($email, "@") | ||
| string() | string($book/price) → “49.99”(取文本值) | ||
| normalize-space() | normalize-space($desc)(去首尾空格、换行变单空格) | 超实用 | |
| lower-case() / upper-case() | lower-case($title) | ||
| concat() | concat($first, " ", $last) | ||
| string-join() | string-join($authors/author, ", ") | 多个作者拼成一行 | |
| replace() | replace($phone, "\D", "") → 只留数字 | ||
| matches() | matches($isbn, "^\d{10}(\d{3})?$") | 正则 | |
| tokenize() | tokenize($tags, "\s+") → (“xml”,”xquery”,”xpath”) | 按空格切 | |
| 数值 | number() | number("123.45") → 123.45 | |
| round() / ceiling() / floor() | round($price * 0.9) | ||
| xs:decimal() / xs:integer() | xs:decimal($book/price) | 强制类型 | |
| 序列 | count() | count(//book) | |
| distinct-values() | distinct-values(//book/@category) | 去重神器 | |
| index-of() | index-of(("a","b","c","b"), "b") → (2,4) | ||
| reverse() | reverse(//book) | 倒序 | |
| subsequence() | subsequence(//book, 1, 10) → 前10本 | 分页必备 | |
| insert-before() | insert-before($seq, 3, <new/>) | ||
| remove() | remove($authors, 2) → 删除第2个作者 | ||
| 日期时间 | current-date() / current-time() / current-dateTime() | {current-dateTime()} → 2025-11-28T10:30:45Z | |
| adjust-date-to-timezone() | adjust-date-to-timezone(current-date(), xs:dayTimeDuration("PT8H")) | 转北京时间 | |
| format-date() | format-date(current-date(), "[Y]-[M01]-[D01]") → “2025-11-28” | ||
| 布尔逻辑 | not() | not(@in-stock) | |
| 高级 | doc() / collection() | doc("books.xml") 或 collection("db/books?select=*.xml") | 加载外部文档 |
| trace() | trace($price, "价格是: ") → 调试时打印 | 调试神器 | |
| serialize() | serialize($result, <output:serialization-parameters><output:method value="json"/></output:serialization-parameters>) | 转 JSON |
2. 自定义函数(XQuery 3.0+)
(: 声明函数 :)
declare function local:discount-price($book as element(book)) as xs:decimal {
let $p := xs:decimal($book/price)
return
if ($book/@category = "SALE") then $p * 0.7
else if ($p > 100) then $p * 0.85
else $p * 0.95
};
(: 使用 :)
for $b in //book
return <item>{ $b/title , local:discount-price($b) }</item>
带默认参数(XQuery 3.1):
declare function local:format-price($price as xs:decimal, $currency as xs:string := "USD") {
concat($currency, " ", $price)
};
3. 实务中最常见的函数组合(直接复制)
(: 1. 搜索标题或作者包含关键词(不区分大小写):)
let $kw := "xquery"
for $b in //book
where contains(lower-case($b/title), lower-case($kw))
or contains(lower-case(string-join($b/author, " ")), lower-case($kw))
return $b
(: 2. 分页(第3页,每页10条):)
let $page := 3
let $size := 10
for $b in //book
order by $b/@id
return subsequence($b, ($page-1)*$size + 1, $size)
(: 3. 按类别分组统计:)
for $cat in distinct-values(//book/@category)
let $books := //book[@category = $cat]
order by count($books) descending
return <category name="{$cat}" count="{count($books)}" avg-price="{avg($books/price)}"/>
(: 4. 生成 JSON(XQuery 3.1):)
map {
"total": count(//book),
"items": array { //book ! map { "title": string(title), "price": number(price) } }
}
4. 不同处理器提供的额外实用函数
| 处理器 | 超好用的专有函数 | 例子 |
|---|---|---|
| BaseX | ft:search() | ft:search("books", "XQuery") 全文搜索 |
| eXist-db | xmldb:size(), util:eval() | |
| MarkLogic | cts:search(), xdmp:document-insert() | 企业级 |
| Saxon | saxon:serialize($node, “json”) |
5. 一句话总结
- 简单查 → 直接用 XPath + 谓语
- 复杂逻辑、排序、分组、分页 → 必须用 FLWOR + 内置函数
- 要复用 → 自己写函数(local: 或声明命名空间)
- 要输出 JSON → XQuery 3.1 的 map/array 语法最香
把上面这些函数记下来,你写 XQuery 基本不会卡壳了!
有具体的 XML 数据或想要实现的效果,直接丢给我,我 10 秒给你最优写法!