XQuery:FLWR-expression
Syntax:
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//title
b/*=”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)
所以如果要把一个属性按照元素的方式输出的话,那么就要方法来生成一个元素,比如: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 …
//这个例子的开头,课件里还写着“基本的DTD”这样的字样,不知是啥意思???
(zugrundeliegende DTD)
Query12:又是变形课,看一下如何重第一张图变成第二张吧
//我是图片1S47
//我是图片2S48
define function one_level(element $p) returns element
{
<part partid={$p/@partid} name={$p/@name}>
{
for $s in doucment("data/parts-data.xml")//part
where $s/@partof=$p/@partid
return one_level($s)
}
</part>
}
<parttree>
{
for $p in document("data/parts-data.xml")//part[empty(@partof)]
return one_level($p)
}
</parttree>
值得一提的是:
1.用了递归哦
2.定义了方法one_level(element $p)
3.empty()
认真看看,上面的结果和要求的还是有一点区别的,当不含有子元素的时候,我们希望能过用简化的tag
define function one_level(element $p) returns element
{
if(count(document("data/partsdata.xml")//part[@partof=$p/@partid>0)
then
<part partid={$p/@partid} name={$p/@name}>
{
for $s in document("data/parts-data.xml")//part
where $s/@partof = $p/@partid
return one_level($s)
}
</part>
else
<part partid={$p/@partie} name={$p/@name}/>
}
或者可以这样:
define function one_level(element $p) returns element
{
if (empty(document("data/partsdata.xml")//part[@partof=$p/@partid])
then
<part partid={$p/@parted} name={$p/@name}/>
else
<part partid={$p/@partid} name{$p/@name}>
{
for $s in document("data/parts-data.xml")//part
where $s/@partof = $p/@partid
return one_level($s)
}
</part>
}
Query13:返回Magda的丈夫
基本的DTD:
<!DOCTYPE CENSUS[
<!ELEMENT person(person*)>
<!ATTLIST person name ID #REQUIRED
spouse IDREF #IMPLIED
job CDATA #IMPLIED>
]>
<result>
{
for $m in document("census.xml")//person[@name="Magda"]
return
shallow($m/@spouse => person)
}
</result>
值得一提的是:
shallow表示只返回目标节点,所有的孩子都不被包括
还有就是箭头了
补充一些特殊的情况:
1.for和let可以多次出现
2.Variablenbindungen können dann aufeinander aufbauen.//??
3.for可以不要
4.let也可以不要
5.where还是可以不要
6.order by依然可以不要
7.geschachtelte Anfragen:
überall,wo Ausdruck erwartet wird