更新XQuery XQuery有了一些新特性
內容包括從原子化到跟蹤文件結構
在
你所不了解的XQuery
(Oracle雜志
年
/
月刊)一文中
我介紹了XQuery
它是一項由萬維網聯盟(W
C)開發的技術
設計用來查詢和操縱XML數據或任何能以XML形式出現的數據
如關系型數據庫
那篇引文討論了
年
月發布的XQuery草案規范
年
月
W
C發布了新的XQuery草案規范
本文追蹤報道了
月份發布的草案規范中最令人感興趣的變化和新增加的特性
其中包括庫模塊
序(prolog)變量
外部函數以及用於調試
錯誤處理和格式化的新函數
變化 月草案增加了大量新特性
但是我首先討論對現有特性所做的更改
有些更改是表面上的
例如
document()輸入函數(該函數使用給定的統一資源標識符[URI]返回一個文檔)被改為一個新的更短的名字doc()
另外
曾經被寫成{
comment
}的注釋現在改用新的笑臉符號(: comment :)
是的
現在每個注釋都成了一個笑話
有些更改則是更根本的
也許最重大的改動就是distinct
values()函數不再返回節點(節點是XML結構
如元素
文檔
注釋以及文本節點)
它只返回原子值(如整數或字符串)
盡管該函數仍然接受節點和原子值
但只返回原子值
任何進入該函數的節點都會被
原子化
並被當作原子值
然後以原子形式返回
原子化的規則很復雜
這裡給出一些基本的
由模式定義為布爾型的元素將被原子化為true/false布爾值
定義為整型的元素將被原子化為一個整數
沒有被模式定義的元素將被原子化為節點的XPath字符串值(文本節點遞歸地連接在一起)
為了說明 distinct
values(<item>apple</item>
<item>banana</item>
grape
)
返回值(
apple
banana
grape
)
假設在模式中沒有聲明
在下面的例子中
如果我們假設 被模式定義為布爾型
那麼下面的語句
distinct
values(<status>
</status>
<status>false</status>)
返回false()
因為它是兩個元素的原子值
記住false()是XQuery常量
表示
假
現在你也許會想
當我想返回節點時
可以使用distinct
nodes()函數
是的
但該函數只能根據節點標識刪除重復節點(那些完全相同的節點
類似於Java中引用的等效節點)
沒有能刪除等效節點的函數
這會使查詢變得復雜
因為沒有辦法能輕松地刪除等效節點
回過頭來看我以前的那篇文章
你所不了解的XQuery
你將發現有些示例會受到這一改動的影響
在那篇文章中
下面的查詢返回了藝術家名字的惟一列表
其中每一個名字前後都帶有 標記
distinct
values(document(
itunes
xml
)
/itunes/Tracks/Track/Artist)
示例輸出類似於
<Artist>Marc Cohn</Artist>
<Artist>Pink Floyd</Artist>
現在
執行同樣的查詢則返回原子值
Marc Cohn
Pink Floyd
由於distinct
values()去掉了 標記(這是原子化過程的一部分)
所以你必須在完成distinct
values()調用後添加標記
如下所示
let $artists :=
distinct
values(doc(
itunes
xml
)
/itunes/Tracks/Track/Artist)
for $a in $artists
return <Artist>{ $a }</Artist>
不是每種情況都是這麼輕松地得到處理
看一下W
C 使用案例文檔中的示例
在
年
月版與
年
月版中是如何變化的
該示例返回每位作者的著作列表
它使用了distinct
values()
根據
年
月的規范
它的代碼如下
<results>
{
for $a in distinct
values(
document(
)
//author)
return
<result>
{ $a }
{
for $b in document(
)
/bib/book
where some $ba in $b/author
satisfies deep
equal($ba
$a)
; return $b/title
}
</result>
}
</results>
根據查詢結果你不能直接分辨出姓和名
但每個 元素都由一個 和 名組成
distinct
values()調用返回具有惟一名字的 元素列表
對於
年
月的規范
現在查詢必須在姓和名上單獨運行distinct
values()
而且在嵌套的FLWOR表達式中也沒有將$a指定為惟一的作者
<results>
{
let $a :=
doc(
)
//author
for $last in distinct
values($a/last)
$first in distinct
values(
$a[last=$last]/first)
return
<result>
{ $last
$first }
{
for $b in
doc(
)
/bib/book
where some $ba in $b/author
satisfies ($ba/last = $last and
$ba/first=$first)
return $b/title
}
</result>
}
</results>
除了編寫用戶定義的distinct
deep
equal()外
沒有更好的方法來完成這件事了
而該方法在純XQuery中不能執行
(注
FLWOR(發音為
flower
)表達式是XQuery的構建模塊
這個名字來源於組成表達式的關鍵詞For
Let
Where
Order by和Return}
新函數 年
月的XQuery規范草案增加了三個新函數
它們肯定會非常有用
第一個是
trace($value as item()*
$label as xs:string) as item()*
trace()函數允許在查詢的中間進行printf風格的調試
該函數有兩個參數
要顯示的值(可以是任意多個項的序列)以及要顯示的這個值的字符串標簽
為方便起見
函數返回$value傳遞的值
trace()輸出的位置由你的引擎來決定
該函數使你能夠詳細查看查詢的內部過程
例如
下面的查詢根據文檔名返回在XQuery引擎中存儲的所有文檔的URI
通過增加一個trace()調用
我能夠在排序前查看返回的每個URI
define function uris() as xs:string* {
for $n in input()
return trace(
xs:string(document
uri($n))
base:
)
}
for $u in uris() order by $u return $u
輸出結果可能如下
:
:
base: census
xml
:
:
base: ipo
xml
當使用trace()和其他類似的函數時
記住在XQuery中每項內容都是一個表達式
沒有語句!為了能夠完成類似語句的操作
你可以采用在表達式之間加逗號的方法來創建一個序列
然後
單獨計算每個表達式的值
在最終的結果序列中忽略所有返回空值的表達式
例如
下面是兩個不影響結果的trace()調用
trace(()
starting query
)
let $time := current
dateTime()
let $ignored := trace($time
Got time
)
return
<html>
<head></head>
<body>Current time is { $time }</body>
</html>
請注意第一個trace()調用後面的逗號
它使查詢返回一個具有兩個項的序列
第一個trace()調用的結果為空
因而被忽略
一般人不了解這一情況
但高級查詢實際上就是返回一個序列
因此在這種特殊情況下兩端的括號不是必需的
查詢
是完全正確的
此外
在這個示例中你會看到
當編寫一個FLWOR表達式時
你可以執行let子句右側的任意代碼
並且忽略該值
月份的草案還增加了error()函數
error($srcval as item()?)
這個函數使用戶能夠報告一個錯誤
類似於拋出一個異常
$srcval被定義為item()?
意味著它可以是一個XML結構或原子
並且加上問號標記表示這是可選的
下面是一些示例應用
error()
error(
Missing source document
)
error(<span>A <i>beautifully</i>
formatted error</span>)
error()調用就像發生異常時那樣展開堆棧
遺憾的是
XQuery仍沒有try/catch功能
因此
盡管你能拋出錯誤
但卻不能從中恢復
在
月份的草案中最後一個引人注目的新增函數有一個奇怪的名字
round
half
to
even()
它有兩種形式
round
half
to
even($srcval as numeric?)
as numeric?
round
half
to
even($srcval as numeric?
$precision as xs:integer) as numeric?
在有一個參數的情況下
它的行為類似於round()函數
只是當一個數恰好落在其他兩個數的中間時
它將參數取整為最接近的偶數值
數字理論家們會告訴你從統計學上講這是一個更精確的取整算法
舉例說明
round
half
to
even(
) =
round
half
to
even(
) =
round
half
to
even(
) =
有第二個參數的情況使函數變得很有趣
第二個參數表示精確級
並允許將函數用於格式化小數值
例如
round
half
to
even(
) =
round
half
to
even(
) =
round
half
to
even(
div
) =
在聲明中使用的數字數據類型是xs:decimal
xs:integer
xs:float
xs:double以及任何根據限制由它們導出的類型的一種簡單表示
它用於XQuery規范中
但你不能在自己的查詢中使用它
<
From:http://tw.wingwit.com/Article/program/Oracle/201311/18764.html