1. 程式人生 > >資料庫應用-半結構化資料訪問-2

資料庫應用-半結構化資料訪問-2

XQuery:FLWR-expression

Syntax:

forvar1inexpression1,...,varninexpressionnletvarn+1:=expressionn+1,...,varn+m:=ausdruckn+mwhereconditionexpressionorderbyexpressionascending/descendingreturnxmlexpression
for是不是很像c裡的迴圈,其實他就是迴圈,他迴圈遍歷樹,對每個點進行判斷,滿足要求的則返回節點,不滿足的則跳過
let就是單純的宣告和定義變數
where是可選的,用來描述條件
return表示返回的結果,他的返回值必須符合XML文件的模式

例子

Query1:所有由Addison-Wesley於1991年後出版的書(year,title)

<bib>
{
for $b in document("http://www.bn.com")/bib/book
where $b/publisher = "Addison-Wesley"
    and $b/@year > 1991
return 
    <book year={$b/@year}>
    {$b/title}
    </book>
}
</bib>

問題:
1.如果其中一本書有多個title會怎麼樣??
會逐一列出
2.如果有一本書沒有標明publisher會怎麼樣??(Höhere Robustheit)
不會報錯,返回空值,不輸出
補充:
Pendant zur FROM-Klausel(??)
Umgang mit Attributen(通過變數進行操作)
Pfadausdrücke in allen Anfrage-Bestandteilen(路徑表達可以在訪問的任意地方使用)
問題擴充套件:
假如我們並不知道:
1.title的具體位置在哪?
2.哪些元素含有字串”Addison-Wesley”
可以使用:
b

//titleb/*=”Addison-Wesley”//這個有點不懂??為什麼只往下一級??
Query2:把每本書的title和autor放在result元素中輸出

<result>
{
for $b in document("http://www.bn.com")/bib/book
return 
    <result>
        {$b/title}
        {//或直接使用$b/autor
            for $a in $b/autor
            return $a
        }
    </result>
}
</result
>

問題:
1.如果有本書,含有多個title元素,會怎麼樣呢?
2.區別下面程式碼和原答案的不同:

<results>
{
for $b in 
    document("http://www.bn.com")/bib/book
        $t in $b/title,
        $a in $b/author
    return 
        <result>
            {$t}{$a}
        </result>
}
</results>

Query3:在result元素中輸出每個作者及其對應的著作的名字

<results>
{
for $a in distinct-values(document("http://www.bn.com")//author)
return
    <result>
        {$a}
        {for $b in document("http://www.bn.com")/bib/book
        where value-equals($b/autor,$a)
        return $b/title}
    </result>
}
</results>

值得注意的地方:
1.文件重組(Umstrukturierung des Dokuments)//注意啥??
2.實現了join
3.使用了內建方法
distinct-values(…)
//注意並不存在針對元素的distinct()方法
value-equals()
這個不僅要求節點的值相同還要求節點有相同的結構
**Query4:**book1中含有多少個top-level Sections?
//top level在這裡是表示什麼??直接用”//section”不行嗎??

<top_section_count>
{count(document("book1.xml")/book/section)}
</top_section_count>

值得注意的地方:
FLWR裡使可以用Aggregate方法的哦
(zählen von Dokumentbestandteilen??)
//zählen von表示什麼意思??
Query5:輸出所有的至少含有一個作者項的書的名字和作者名,如果作者的人數大於兩個,那麼只輸出前兩個,其他用et-al代替。

<bib>
{
for $b in document("www.bn.com/bib.xml")//book
where count($b/author)>0
return
    <book>
        {$b/title}
        {for $a in $b/author[position()<=2]
        return $a]
        {if(count($b/author)>2)
        then <et-al>
        else()}
    </book>
}
</bib>

值得注意的:
這回路徑表達使用了介詞
另外還有條件語句
而且這回的Aggregate方法是在where中使用
Query6:按照字母表順序輸出所有1991年後由Addison-Wesley出版的書的名字和出版年份

<bib>
{
for $b in document("www.bn.com/bib.xml")//book
where $b/publisher = "Addison-Wesley"
    and $b/@year > "1991"
order by $b/title
return
    <book>
        {$b/@year}
        {$b/title}
    </book>
}
</bib>

XMLSpy輸出的是屬性的話得到的也是屬性//好像是廢話
(XMLSpy macht aus Attributen wieder Attribute)

AttributElement:<year>string($b/@year)</year>ElementAttribut:<bookyear="string($b/year)">
所以如果要把一個屬性按照元素的方式輸出的話,那麼就要方法來生成一個元素,比如:string($n/@attib)
問題:
1.如果輸出的格式不符合XML的規定呢??
會報錯哦
2.如果有一本書,他有多個名字呢?要怎麼排序??
不知???
但比較好得做法是使用:order by \$b/title[1]
/*
“stable order by…”
-Dokument-Reihenfolge bleibt erhalten bei Elementen mit gleichem Sortier-Schlüssel
*/
另外上面連續用來兩次的\$b/title這樣的效率比價低
//會嗎??如果會的話,也就是說我前面的想法是錯的,他的語句應該是一句一句走得,for語句結束後b就應該獲得了所有的目標項,如果是這樣的話那麼上邊第二個例子應該怎麼解釋,而且這裡的輸出也應該會變成先把所有的year輸出後再輸出title啊???還是說b項相當於容器,然後return自帶遍歷功能???
總之改進的方法就是使用let:
<bib>
{
for $b in document("www.bn.com/bib.xml")//book
let $t:=$b/title
where $b/publisher = "Addison-Wesley"
        and $b/@year > "1991"
order by $t
return 
    <book>
        {$b/@year}
        {$b/t}
    </book>
}
</bib>

//也沒看出有優化啊,難道每呼叫一次$b/title他都重新遍歷一次不成??
/*這是解釋,沒看懂???
Beide Varianten leisten dasselbe.
Bei der zweiten Variante muss die Attribut-Generierung unmittelbar hinter dem Beginn-Markup kommen.
*/
Query7:一本包含有元素的書,如果他元素的tag(就是這個< Name >)是以or結尾的,那麼輸出這本書的名字和這個元素

for $b in document("www.bn.com/bib.xml")//book,
    $e in $b/*
where ends_with(local-name($e), "or")
return
    <book>
        {$b/title}
        {$e}
    </book>

//不對啊 星星只往下一層啊,不是不全面嗎???
值得一提的是:
用了一些方法哦像ends_with(),local-name()啊
打破了Schema資訊和資料資訊的界限
//其實以前不是一直都在處理Schema資訊嗎?雖然是預設的處理就是了

結構轉換

相應與資料表達時的不同形式,xml的結構也可能不同,具體見下圖:
//圖兩張
那麼他們之間要怎麼進行轉換呢???

<publication>
{
for $v in document(biblio_document.xml)/biblio/*
where $v/year > 1989
return 
    <type>{local-name($v)}</type>
    $v/title
}
</publication>

反過來:

let $step:=document("beispiel.xml")/publication/type[1]/text(),
    $x:=document("anderes.xml")/biblio/$step
return
    $x/nextStep

//第二個沒懂,哪裡跳出來的nextStep啊???

例子

繼續例子
Query8:找出每本書的最低價格,並把他放在minprice元素中輸出,minprice有一個屬性,為title

<results>
{
let $doc:=document("prices.xml")
for $t in distinct-values($doc//book/title)
let $p := $doc//book[title=$t]/price
return 
    <minprice title={$t/text()}>
        <price>{min(decimal($p/text()))}</prive>
    </minprice>
}
</results>

decimal()是必須得因為他把字串轉化為數字型別,如此才能使用min().
Query9:給book1文件建立目錄,只保留section元素和它的title
先插個圖介紹filter:
//插圖

<toc>
{
let $b := document("book1.xml");
return 
    filter($b//section|$b//section/title|$b//section/title/text())
}
</toc>

Query10:獲取第一個procedure元素下與前兩個incision元素之間的所有節點

<critical_sequence>
{
let $proc:=//procedure[1]
for $n in $proc//node()
where $n follows($proc//incision)[1]
    and $n precedes($proc//incision[2]
return 
    $n
}
</critical_sequence>

值得一提的是:
proc/node()proc//proc//*????
//插圖一張,看一下其他常見的方法
Query11:輸出所有使用者的名字,並且這些使用者應該對所有的item都有出價(Namen all User, die ein Gebot für jedes Item abgegeben haben)

<frequent_bidder>
{
for $u in doucment("user.xml")//user_tuple
where
    every $item in document("items.xml")//item_tuple
        satisfies
      some $b in document("bids.xml")//bid_tupel
          satisfies
        ($item/itemno=$b/itemno and $u/userid=$b/userid)
return 
    $u/name
}
</frequent_bidder>

值得一提的是:
every … satisfies …
some … satisfies …
//