グルーピング
data.xml
<movies> <movie> <title>ミケの冒険</title> <cat>ミケ</cat> <cat>トラ</cat> <cat>クロ</cat> </movie> <movie> <title>タマの冒険</title> <cat>タマ</cat> <cat>ミケ</cat> <cat>トラ</cat> </movie> </movies>
重複除去
fn:distinct-values(シーケンスのアイテム順は実装依存)を使って、バインド。
for $cat in fn:distinct-values(fn:doc("data.xml")/movies/movie/cat)
cat要素内容をテストしてtitle要素取得
fn:doc("data.xml")/movies/movie[cat=$cat]/title
クエリー式
上記のことをまとめる。
for $cat in fn:distinct-values(fn:doc("data.xml")/movies/movie/cat) return <result cat="{$cat}"> { fn:doc("data.xml")/movies/movie[cat=$cat]/title } </result>
結果XMLデータ
<result cat="ミケ"> <title>ミケの冒険</title> <title>タマの冒険</title> </result> <result cat="トラ"> <title>ミケの冒険</title> <title>タマの冒険</title> </result> <result cat="クロ"> <title>ミケの冒険</title> </result> <result cat="タマ"> <title>タマの冒険</title> </result>
cat要素内容ごとにtitle要素がグルーピングされました。めでたし。
応用
カウントしてみる。ついでにlet節も使ってみよう。
let $movie := fn:doc("movies.xml")/movies/movie for $cat in fn:distinct-values($movie/cat) return <result cat="{$cat}" count="{fn:count($movie[cat=$cat])}"> { $movie[cat=$cat]/title } </result>
<result cat="ミケ" count="2"> <title>ミケの冒険</title> <title>タマの冒険</title> </result> <result cat="トラ" count="2"> <title>ミケの冒険</title> <title>タマの冒険</title> </result> <result cat="クロ" count="1"> <title>ミケの冒険</title> </result> <result cat="タマ" count="1"> <title>タマの冒険</title> </result>
それにしても、いちいちfn:doc()から書いてるの馬鹿らしいんですけど、ループ中のコンテキストとかどうなってんのこれ。ああ、教科書から探すのだるいなあ……。
ああ、そのためにlet節があるのか。早く言ってよもう。教科書の順序おかしいだろ。確かに「F」LWOR式だけども!