|
前回は,LINQ to XMLの概要について説明した。今回から,実際にLINQクエリーのサンプル・コードを取り上げて解説していく。
XMLデータ処理で避けて通れないのは,処理対象ノードの選択である。W3C仕様でいえば,XPathのロケーションパスの指定方法にあたるものだ。ロケーションパスが,DOM,XSLT,XQueryの中で用いられていることを考えれば,その必要性は自明である。
本連載では,Visual Studio(VS)2005以降のユーザーに対し,XMLそのものについての基本知識はあるものとして解説を進めていく。したがって,VSの基本操作手順や,ノードや要素や属性といった最低限の用語は把握しておく必要がある。ただし,XML関連仕様(DOM,XPath,XSLT,XQueryなど)についてなじみのない読者は,その仕様についての解説部分はとばして読んでも差し支えない。XMLおよびXML関連仕様と実務での利用方法については,他の拙著を参照してほしい。『XML完全マスター』(発行 メディア・テック出版),『XML MASTERテキスト XMLマスター(ベーシック)』(共著,発行 ソフトバンクパブリッシング)など。 |
今回の開発に使った筆者の環境は,Visual Studio Team System 2008である。本稿で取り上げるのはASP.NETプログラムで,開発言語はVisual Basic。ASP.NETでLINQを試すなら,無料で公開されているVisual Web Developer 2008 Express Editionが,マイクロソフトのWebサイトからダウンロードできる。 なお,本記事で紹介するサンプル・プログラムのソース・ファイル(zipアーカイブ)は,下記からダウンロードできる。 02LINQtoXML.zip |
XML文書の読み込み
まず,処理対象とするXML文書が必要なので,既存のXMLファイルを読み込んでおこう。作成したASP.NETプロジェクトの,ソリューションエクスプローラから,App_Dataフォルダ内に,リスト1のXMLファイル(udons_sampleData.xml)を追加する。文字コードはUTF-8だ。本稿で使用するXMLファイルはすべて,App_Dataフォルダ内に読み込んでおく必要がある。
<?xml version="1.0"?>
<商品情報>
<商品>
<品番>udon_01</品番>
<品名>天ぷらうどん</品名>
<セット内容>うどん、かけつゆ、えび天ぷら、あげ巻き</セット内容>
<価格>3500</価格>
</商品>
<商品>
<品番>udon_02</品番>
<品名>かきあげうどん</品名>
<セット内容>うどん、かけつゆ、季節のかきあげ、かまぼこ</セット内容>
<価格>2800</価格>
</商品>
<商品>
<品番>udon_03</品番>
<品名>きつねうどん</品名>
<セット内容>うどん、かけつゆ、味付け油あげ、かまぼこ</セット内容>
<価格>1500</価格>
</商品>
<商品>~</商品>繰り返し
<商品>
<品番>udon_10</品番>
<品名>カレーうどん</品名>
<セット内容>うどん、かけつゆ、粉末カレー、きじ肉、野菜</セット内容>
<価格>3000</価格>
</商品>
</商品情報>
1.XDocumentとXElement
最初に,XDocumentやXElementクラスのLoadメソッドを使い,XMLファイル名を指定して読み込む。それから,読み込んだ文書のルートノードを起点として,任意の要素や属性といった選択対象までの道のりを,パスで指定していく。
その際,LINQ to XML軸の起点となるルートノードの扱い方が,XPathとは異なるので注意する必要がある(XSLTに詳しい人は,XSLTのdocument関数での参照先指定をイメージしてほしい)。System.Xml.Linq名前空間には,XDocumentとXElementという二つのクラスがあり,この二つのどちらを使うか,つまり「どのようにしてXML文書を読み込むか」によって,起点が異なるのである。
XDocumentクラスは,その名の通り,XMLドキュメントを表す。XDocument.Loadで読み込んだ場合は,読み込んだXML文書のルート要素ノードは「ルートノードの子扱いになる」。ルートノードの子孫といえば,読み込んだXML文書のルート要素以下を指す。
一方,XElementクラスは,XML要素を表す。XElement.Loadで読み込んだ場合は,読み込んだXML文書のルート要素ノードが「ルートノード扱いになる」。ルートノードの子孫とは,読み込んだXML文書のルート要素の子孫を指す。つまり,ルート要素自身は含まれない。
起点が異なると,クエリーの記述方法も異なる。XMLデータの処理ではルート要素の子孫を処理するケースが多いので,XElementクラスを使うのが基本である。本稿でも基本的にXElement.Loadで読み込んでいる。
XML文書(ファイル)を読み込む構文は,次の通りだ。
Dim returnValue As XDocument= XDocument.Load(XMLファイルのURI)
Dim returnValue As XElement= XElement.Load(XMLファイルのURI)
先のリスト1を,それぞれの方法で読み込むと,結果は図1のようになる。上図がXDocument.Loadで読み込んで子要素のコレクションを取得した場合,下図がXElement.Loadで読み込んで子要素のコレクションを取得した場合だ。
| |
図1●XDocumentクラスとXElementクラスを使ってリスト1を読み込んだ結果 [画像のクリックで拡大表示] |
このように,XDocumentクラスを使った場合,ルートノードの子要素のコレクションとは,ルート要素である<商品情報>以下になる。
一方,XElementクラスを使った場合は,ルート要素<商品情報>がルート扱いになるので,子要素のコレクションとは<商品>要素以下となる。
LINQクエリーのコードは,リスト2のように記述する。
| |
リスト2●XDocumentクラスやXElementクラスを使ってリスト1を読み込むコード [画像のクリックで拡大表示] |
(1)ImportsメソッドでSystem.LinqとSystem.Xml.Linq名前空間を読み込む。System.Linq名前空間は,LINQを使用するクエリーをサポートするクラスとインターフェイスを提供する。System.Xml.Linq名前空間は,LINQ to XMLでXMLを処理するクラスが含まれている。
(2)Server.MapPathでサーバー上の物理パスを指定する。
(3)次にApp_Dataフォルダ内に読み込んでおいた,udons_sampleData.xmlを読み込む。ここでは,XDocumentクラスのLoadメソッドを使用している。
(4)IEnumerable (Of T)ジェネリック・インタフェースを使い,指定した型のコレクションに対する単純な反復処理を実行する。構文は,次の通りだ。
IEnumerable(Of 列挙するオブジェクトの型)
xmldoc.Elementsクエリーで,読み込んだXML文書の要素を選択している。Elementsメソッドは,ドキュメントの子要素のコレクションをドキュメント順に返す。ここでは,XDocumentクラスで読み込んだXMLの要素に対してクエリーを発行しているので,ルート要素(<商品情報>)が含まれて選択される。なお,Elements(要素名)と記述した場合は,指定した要素のコレクションをドキュメント順に返す。この場合はXElement.LoadでXMLを読み込む。
(5)クエリーを作成しただけでは,クエリーは実行されない。クエリー変数queryDoc内にクエリーの定義が格納されるだけだ。そこで,For Each~Inステートメントを使用してクエリーを実行し,TextBox1コントロール内にXML文書を表示している。このような処理を「遅延実行」という。構文は,次の通りだ。
For Each 反復変数 In オブジェクトコレクションまたは配列の名前
ステートメント
Next
「遅延実行」以外に,クエリーを定義するのと同時に実行される「即時実行」がある。これは,単一の値を返す標準クエリー演算子の使用によって強制的に行われる。詳しくは第4回で取り上げる。
XSLTユーザーなら,For Each~Inステートメントは,<xsl:for each select=”処理対象ノード”></xsl:for-each>をイメージすればわかりやすいだろう。
(6)TextBox2内に表示されるXML文書は,XElement.Loadメソッドで読み込んでいるため,ルート要素(<商品情報>)の子である<商品>要素以下となる。