数据库应用-半结构化数据访问-2

XQuery:FLWR-expression

Syntax:

for var1 in expression1,...,varn in expressionnlet varn+1:=expressionn+1,...,varn+m:=ausdruckn+mwhere condition expressionorder by expression ascending/descendingreturn xmlexpression

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)

AttributElement:<year>string($b/@year)</year>ElementAttribut:<book year="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 …
//这个例子的开头,课件里还写着“基本的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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值