在 XQuery 中,要向现有的 XML 文档或节点添加新元素和添加属性,通常有两种主要场景:
- 在查询结果中构造新的元素和属性(最常见)
- 使用 XQuery Update Facility (XQuery Update) 真正修改原始 XML 文档(只有支持更新的处理器才行,如 BaseX、eXist-db、MarkLogic、Zorba 等)
下面分别详细说明这两种方式。
1. 构造新的元素和属性(所有 XQuery 处理器都支持)
这是最常用的方式,使用直接元素构造函数或计算元素/属性构造函数。
(: 假设有一个变量 $book 包含以下内容 :)
let $book := <book isbn="12345">
<title>XPath and XQuery</title>
<author>Priscilla Walmsley</author>
</book>
(: 方式1:直接元素构造函数(最常用):)
let $new-book :=
<book isbn="{$book/@isbn}" category="TECH">
{$book/*} (: 复制原有的所有子元素 :)
<price>49.99</price>
<publish_date>2023-01-01</publish_date>
<in-stock>true</in-stock>
</book>
return $new-book
结果:
<book isbn="12345" category="TECH">
<title>XPath and XQuery</title>
<author>Priscilla Walmsley</author>
<price>49.99</price>
<publish_date>2023-01-01</publish_date>
<in-stock>true</in-stock>
</book>
更灵活的写法(计算构造函数):
let $new-book :=
element {"book"} {
attribute {"isbn"} {$book/@isbn},
attribute {"category"} {"COMPUTER"},
attribute {"lang"} {"en"},
$book/title,
$book/author,
element {"price"} {49.99},
element {"discount"} {10}
}
return $new-book
在已有元素中插入新元素(拷贝后修改,称为“变换”):
(: 经典的“拷贝并修改”模式 :)
let $new-book :=
copy $b := $book
modify (
(: 添加属性 :)
insert node attribute {"category"} {"WEB"} into $b,
(: 在最后添加新元素 :)
insert node <edition>2</edition> as last into $b,
(: 在某个位置前/后插入 :)
insert node <translator>张三</translator> after $b/author
)
return $b
return $new-book
注意:上面的 copy ... modify 语法属于 XQuery Update Facility,不是所有处理器都支持(Saxon EE 支持,Saxon PE/HE 不支持)。
2. 真正修改原始文档(XQuery Update Facility 1.0/3.0)
只有在支持更新的数据库或处理器中才能真正改变存储的 XML。
(: 假设要修改 doc("books.xml")//book[@isbn="12345"] :)
for $b in doc("books.xml")//book[@isbn="12345"]
return (
(: 添加属性 :)
insert node attribute category {"PROGRAMMING"} into $b,
(: 添加子元素(作为最后一个子节点):)
insert node <price currency="USD">59.99</price> as last into $b,
(: 或者插入到特定位置 :)
insert node <rating>4.8</rating> before $b/price,
(: 同时添加多个节点 :)
insert nodes (
<pages>528</pages>,
<in-stock>true</in-stock>
) as last into $b
)
其他常用更新语句:
(: 替换属性值 :)
replace value of node $b/@category with "COMPUTER"
(: 删除属性 :)
delete node $b/@old-attr
(: 重命名元素 :)
rename node $b/price as "list-price"
3. 常见实际例子汇总
(: 给所有没有 category 属性的 book 元素添加 category="UNKNOWN" :)
for $b in //book[not(@category)]
return insert node attribute category {"UNKNOWN"} into $b
(: 给每本书添加一个 <updated> 元素,内容是当前时间 :)
for $b in collection("books")/book
return insert node
<updated>{current-dateTime()}</updated>
as last into $b
(: 在 <book> 下已有 <title> 后立即插入 <subtitle> :)
for $b in //book
return insert node
<subtitle>{concat($b/title, "(第2版)")}</subtitle>
after $b/title
总结
| 需求 | 推荐写法 | 是否需要 Update Facility |
|---|---|---|
| 只在查询结果中添加 | 直接/计算元素构造函数 | 不需要 |
| 拷贝原有节点后添加 | copy $x := … modify (…) | 需要(部分处理器支持) |
| 真正修改存储的 XML 文档 | insert node … into/replace/delete 等 | 必须支持 XQuery Update |
常用支持 XQuery Update 的工具:BaseX、eXist-db、MarkLogic、Saxon EE、Zorba 等。
如果你告诉我你用的是哪个 XQuery 处理器(Saxon、BaseX、eXist-db、MarkLogic 等),我可以给出最精准的写法!