PROJECT KySS(プロジェクト・キッス)
四国のSOHO。薬師寺 国安(フリーWebプログラマ)と,薬師寺 聖(デザイナ,個人事業所自営,http://www.SeinDesign.net/)によるコラボレーション・ユニット。XMLに関する記事や著書多数。両名とも,Microsoft MVP for Windows Server System - XML (Oct 2003-Sep 2008) http://www.PROJECTKySS.NET

 LINQ to XMLの基礎編は,今回が最終回だ。これまでの4回で,処理対象の選択,クエリーの取得,XMLツリーの生成や変更,演算子,関数と見てきた。最後に,ソートや検索,データの結合について解説する。

 これで最低限必要なコードは一通り網羅することになる。XML文書の扱いに慣れていない人は戸惑ったかもしれないが,自分で2~3回書いてデバッグしてみれば,コツがつかめてくるだろう。

 今回の開発に使った筆者の環境は,Visual Studio Team System 2008である。本稿で取り上げるのはASP.NETプログラムで,開発言語はVisual Basic。ASP.NETでLINQを試すなら,無料で公開されているVisual Web Developer 2008 Express Editionが,マイクロソフトのWebサイトからダウンロードできる。

 なお,本記事で紹介するサンプル・プログラムのソース・ファイル(zipアーカイブ)は,下記からダウンロードできる。

 05LINQtoXML.zip

ソート

 本連載第3回の「インメモリーのオブジェクトからXMLを生成する処理(リスト19)」で少し触れたが,LINQクエリーの結果はソートすることができる。構文は次の通りだ。

■昇順
Dim query As IEnumerable(Of XElement) = From 範囲変数(反復変数) In 対象コレクション Order By クエリー結果に含まれる一つ以上の要素 Ascending(デフォルトで省略可)

■降順
Dim query As IEnumerable(Of XElement) = From 範囲変数(反復変数) In 対象コレクション Order By クエリー結果に含まれる一つ以上の要素 Descending

ソートして件数を表示

 ここでは,リスト1のようなXML文書のデータを,図1のように<価格>の降順にソートし,さらに,データ件数を取得して表示してみよう。

<?xml version="1.0"?>
<商品情報>
    <商品 品番="udon_01">
        <品名>天ぷらうどん</品名>
        <セット内容>うどん、かけつゆ、えび天ぷら、あげ巻き</セット内容>
        <価格>3500</価格>
    </商品>
    <商品 品番="udon_02">
        <品名>かきあげうどん</品名>
        <セット内容>うどん、かけつゆ、季節のかきあげ、かまぼこ</セット内容>
        <価格>2800</価格>
    </商品>
    <商品>~</商品>繰り返し,略
</商品情報>
リスト1●サンプルのXML文書

図1●<価格>の降順にソートし,データ件数を取得/表示している
図1●<価格>の降順にソートし,データ件数を取得/表示している
[画像のクリックで拡大表示]

 処理のコードはリスト2の通りである。

Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    Dim filePath As String = Server.MapPath("./")
    Dim xmldoc As XElement = XElement.Load(filePath & "App_Data/udons_2008_hinban_attribute.xml")
    Dim query As IEnumerable(Of XElement) = From c In xmldoc.Elements("商品") Order By Integer.Parse(c.<価格>.Value) Descending
    Label1.Text = query.Count & "件のデータ"
    For Each result In query
        TextBox1.Text &= result.ToString & vbCrLf
    Next
End Sub
リスト2●処理のコードの一部

 Order By句に,Integer.Parseメソッドで数値に変換した<価格>要素の値(c.<価格>.Value)を指定し,その値をDescending(降順)でソートしている。範囲変数cは<商品>要素のコレクションを参照している。

部分一致検索

 今度は,実務で用途の多い検索処理について見ていこう。まず,指定した文字列をデータとして含む要素を抽出してみよう。

1.指定文字列を含む特定要素の抽出

 XPathやXQueryに,contains関数が用意されているように,LINQでは,Containsメソッドが用意されている。このメソッドを使うと,指定した文字列が含まれていればTrue,含まれていなければFalseが返される。構文は次の通りだ。

String.Contains(Stringに含まれる文字列)

 リスト1のXML文書から,<セット内容>要素に「かまぼこ」が含まれる<商品>を抽出するには,リスト3のように記述する。

 Where句以降に,Containsメソッドを使って,<セット内容>要素内に「かまぼこ」の含まれるすべての<商品>要素を取り出す条件を記述している。結果は図2の通りだ。

Dim query As IEnumerable(Of XElement) = From c In xmldoc.Elements("商品") Where c.<セット内容>.Value.Contains("かまぼこ") Select c 
For Each result In query
    TextBox1.Text &= result.ToString & vbCrLf
Next
リスト3●指定した文字列が含まれる要素を抽出する処理(一部)

図2●<セット内容>に「かまぼこ」が含まれる<商品>を検索した結果
図2●<セット内容>に「かまぼこ」が含まれる<商品>を検索した結果
[画像のクリックで拡大表示]