連載

.NETで簡単XML

第3回 XML文書を読み書きするプログラムの作成

株式会社ピーデー 川俣 晶
2003/04/08

Page1 Page2 Page3 Page4 Page5

 プログラムは以上で完成である。このサンプル・プログラムに、次のようなXML文書を処理させてみる。

<?xml version="1.0" ?>
<person id="0011">
<name>山田一郎</name>
<age>17</age>
</person>
処理するXML文書

 すると、以下のような結果が出力される。

サンプルのXML文書を処理する
上のテキスト・ボックスにXML文書を書き込み、ボタンを押すと結果が下のテキスト・ボックスに表示される。

 上記のサンプルXML文書の場合、下のテキスト・ボックスは次のような内容となる。

ノードを発見: XmlDeclaration
ノードを発見: Whitespace
ノードを発見: Element
reader.Name=person
属性を発見 id=0011
ノードを発見: Whitespace
ノードを発見: Element
reader.Name=name
ノードを発見: Text
reader.Value=山田一郎
ノードを発見: EndElement
reader.Name=name
ノードを発見: Whitespace
ノードを発見: Element
reader.Name=age
ノードを発見: Text
reader.Value=17
ノードを発見: EndElement
reader.Name=age
ノードを発見: Whitespace
ノードを発見: EndElement
reader.Name=person
XML文書の処理結果

 このサンプル・プログラムの内容を説明しよう。ここでは、XmlTextReaderクラスのインスタンスを作成して利用している。このクラスのコンストラクタはXmlTextWriterクラスと同様にいくつかのバリエーションがある。ここでは、TextReaderクラス型を引数に取るものを使っている。TextReaderクラスを継承したStringReaderクラスのインスタンスを引数に指定している。

Dim reader As XmlTextReader = New XmlTextReader(New StringReader(textBoxSource.Text))

 さて、このプログラムの最大のポイントは、whileステートメントの条件式に書かれたReadメソッドである。Readメソッドは、何も引数を取らず、戻り値として、それ以上読むべき「何か」があるかどうかを示すbool値を返す。つまり、このwhileループは、それ以上読むべき「何か」がなくなったときに終了する。ここでは、その読むべき「何か」をノードと呼ぶ。さて、不思議に思った読者もいると思う。Readメソッドは読み取ったノードに関する情報を返す手段を何も用意していないのである。何かのノードを読み取ったとして、その内容はどうやって知るのだろうか? 実は、XmlTextReaderクラスのインスタンス自身が、読み取ったノードの内容を保持しているのである、そのため、このインスタンスのプロパティなどを通じて、ノードの内容を知ることができる。もちろん、その内容は次のノードを読み取った時点で消えてしまうものである。常に今読みとったばかりの最新のノードの内容だけが参照できるというわけである。

 それでは、どのようなノードの情報が得られるのだろうか。最も基本的な情報は、NodeTypeプロパティで取得されるノードの種類だろう。これはXmlNodeType列挙体の値を返すプロパティである。この列挙体は、CommentやElementといった値を持っている。このプロパティの値がElementなら現在のノードは要素(の開始位置)であることを示している。XmlDeclarationならXML宣言、Commentならコメント、Textならテキストである。このプログラムでは、読み取ったノード1つ1つについて、

writer.WriteLine("ノードを発見: {0}", reader.NodeType.ToString())

というコードでXmlNodeType列挙体の名前を出力している。出力結果を読めば、どのようなノードがどのような順番に出現したかが分かるだろう。

 上記の実行例の結果でいうと、「<?xml version="1.0" ?>」が「ノードを発見: XmlDeclaration」に対応する。次の改行が「ノードを発見: Whitespace」に対応する。その次の「<person」が「ノードを発見: Element」に対応する。

 さて、サンプル・プログラム内では、NodeTypeプロパティの値によって、3つのケースに処理を場合分けしている。もちろん、この3種類しか出現しないわけではないが、代表的なケースなので処理例を入れている。まず、XmlNodeType.Elementのケースは、要素の開始を示し、XmlTextReaderクラスのNameプロパティが要素の名前を示す。XmlNodeType.Textのケースは、テキストを示し、XmlTextReaderクラスのValueプロパティがそのテキストの内容を示す。XmlNodeType.EndElementのケースは、終了タグを示し、XmlTextReaderクラスのNameプロパティが要素の名前を示す。

 さて、ここで注意して今一度サンプル・プログラムを見ていただきたい。このプログラムには、ループの中にもう1つのループ(Do 〜 Loop)がある。開始タグ内の属性を調べる部分には、Readメソッドを使ったループとは異なるループが別に記述されているのである。MoveToNextAttributeメソッドの戻り値がfalseになるまで繰り返す内側のループはいったい何だろうか?

 これは重要なことなのだが、属性だけは扱いが異なるのである。たいていの情報は、Readメソッドを繰り返すだけで、その情報を含むノードに到達することができる。しかし、属性については、このようなシンプルな処理とは少し距離を置いた立場にある。ある意味で、属性とは開始タグの一部をなす情報であるともいえ、単にReadメソッドを繰り返すだけでは、開始タグの次に要素の内容に行ってしまう。しかし、属性にアクセスする手段がないわけではない。ここで使用しているのは、MoveToFirstAttributeメソッドとMoveToNextAttributeメソッドを用いた属性へのアクセスである。MoveToFirstAttributeメソッドは最初の属性を読みとってノードにセットする機能を持つ。MoveToNextAttributeメソッドは、現在の属性の次の属性にノードをセットする機能を持つ。それぞれ、戻り値として、これ以上属性がないときにfalseを返すbool値を返す。属性ノードが読み取れた場合は、Nameプロパティが属性の名前を、Valueプロパティが属性の値を持つ。

 最後にもう1つだけチェックしておこう。一連の処理でSystem.Xml名前空間のXmlException例外が発生した場合は、その結果を出力するようになっている。XMLの構文にはさまざまな制約があり、ちょっとした書き間違いですぐにXMLの構文違反となる可能性がある。そのような場合には、この例外が発生するので、それが起きたときにどう処理するかを意識して考えておく価値があるだろう。


 INDEX
  .NETで簡単XML
  第3回 XML文書を読み書きするプログラムの作成
    1.XML文書を読み込む
  2.XML文書を読み込むサンプル・プログラム
    3.文書の妥当性を検証するXmlValidatingReaderクラス
    4.XML文書を読み書きするサンプル
    5.XML文書を読み書きするサンプルの解説
 
インデックス・ページヘ  「連載 :.NETで簡単XML」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間