またもやインデクサ
どんな語彙でも良いが2階層以上の階層構造を持ちname属性が必ず必要なXMLがあったとする。
test.xml
.NETでこのようなXMLの全ての要素とname属性をパースするには何通りかの書き方が出来るんだけどせっかくだからC#2.0からXmlReaderクラスに追加された、現在のカレントノードを基点にして状態がリセットされた新たなXmlReaderのインスタンスを返すメソッドを使ってみることにした。
C# XmlReader.ReadSubtree メソッド
public virtual XmlReader ReadSubtree();
実際にこのメソッドを使ってサンプルのXMLをパースするアプリケーションを書いてみる。
using System; using System.Diagnostics; using System.Collections.Generic; using System.Text; using System.Xml; namespace ReadSubTreeTest { class Program { static void Main(string[] args) { using ( XmlReader reader = XmlReader.Create(@"test.xml")) { reader.ReadStartElement("foo"); ParseBar(reader); }; } static void ParseBar(XmlReader reader) { while (reader.Read()) { if (reader.NodeType == XmlNodeType.Element) { switch (reader.LocalName) { case "bar": { Console.WriteLine("bar name= " + reader["name"]); break; } case "barContainer": { Console.WriteLine("barContainer name= " + reader["name"]); XmlReader subReader = reader.ReadSubtree(); subReader.ReadStartElement("barContainer"); ParseBar(subReader); break; } } } } } } }※例のごとく実際に使っているアプリケーションに比べて極端に処理をはしょっています
このようなパースのプログラミングが正しいかどうかは別にしてこのアプリケーションは例外も吐かずにXmlReaderのインデクサを参照している行で異常終了してしまう。(コード -2147023895 (0x800703e9))
どうもreader.ReadSubtree()で取得した新たなXmlReaderのインスタンスでインデクサを利用してXML属性を取得しようとすると駄目みたい。しかし、この行
Console.WriteLine("bar name= " + reader["name"]);
を以下のようにメソッドで属性を取得するようにすれば問題無くアプリケーションは終了する。
Console.WriteLine("bar name= " + reader.GetAttribute("name"));
reader.ReadSubtree()で取得したXmlReader(デバッガではXmlSuntreeReaderと表示される)がインデクサを実装していない事は充分考えられるがそうなのであればなんらかの例外を出しても良さそうだがVisualStudio2005(β2)を使用する限り例外はスローされない。不思議。