連載

.NETで簡単XML

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

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

Page1 Page2 Page3 Page4 Page5

XmlValidatingReaderクラスとXmlTextReaderクラス

 XmlTextReaderクラスは便利なのだが、実はXML文書を処理するという観点からは問題がある。例えば、以下のサンプル・プログラムを見ていただきたい。Windowsアプリケーションのテンプレートでプロジェクト作成後に次のようなコードを書き加えたものである。

 以下は追加するImportsステートメント(C#ではusingディレクティブ)である。

Imports System.IO
Imports System.Xml
VB.NET版のサンプルに必要なImportsステートメント
C#版のサンプルに必要なusingディレクティブ

 以下は書き加える文字列定数とフォームのLoadメソッドの内容である。

Private Const target As String = "<?xml version='1.0' ?>" _
  & "<!DOCTYPE a [ <!ENTITY ent 'ok'> ]>" _
  & "<a>&ent;</a>"

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
  Dim reader As XmlTextReader = New XmlTextReader(New StringReader(target))
  While reader.Read()
    Trace.WriteLine("ノードを発見: " + reader.NodeType.ToString())
    If reader.NodeType = XmlNodeType.Text Then
      Trace.WriteLine(reader.Value)
    End If
    If reader.NodeType = XmlNodeType.EntityReference Then
      Trace.WriteLine(reader.Name)
    End If
  End While
End Sub
追加する文字列定数とフォームのLoadメソッドの内容(VB.NET版)
追加する文字列定数とフォームのLoadメソッドの内容(C#版)

 これを実行すると、Visual Studio .NETの出力ウィンドウに以下のような内容が出力される。

ノードを発見: XmlDeclaration
ノードを発見: DocumentType
ノードを発見: Element
ノードを発見: EntityReference
ent
ノードを発見: EndElement
出力ウィンドウに表示される内容

 プログラムの内容を簡単にいえば、文字列定数targetの内容をXML文書としてXmlTextReaderクラスで読み込む機能を記述している。ここでは、第1回目では説明していないXMLの機能である「実体(entity)」を使用している。これは一種のマクロであり、あらかじめ定義しておいた文字列と文書中の文字列を置き換える機能を持っている。つまり、「ent」という名前の実体は「ok」という文字列であると定義しておき、「&ent;」と記述したら、それは「ok」という文字列に置き換えて利用するというものである。しかし、出力を見ると分かる通り、「EntityReference」つまり実体を参照するノードを発見しただけで、「ok」という文字列は発見できていない。これでは使い勝手がよくない。

 これを解決するために、XmlTextReaderクラスとは別に用意されているXmlValidatingReaderクラスを使用することができる。XmlValidatingReaderクラスは、XmlTextReaderクラスと同じくXmlReaderクラスを継承している。そのため、XmlValidatingReaderクラスとXmlTextReaderクラスは多くのメソッドやプロパティが共通していて、同じように使用できる。しかし、同じような目的のクラスというわけではなく、XmlValidatingReaderクラスには、スキーマを用いて文書の妥当性を検証するという明確な役割が存在する。つまり、妥当性を検証しながらXML文書を読み取るのが主要な用途であるといえる。では逆に、妥当性を検証しないでXML文書を読み取るのがXmlTextReaderクラスの役割なのかというと、そうでもない。XML1.0勧告では、妥当性を検証しない場合でも、内部実体を展開することを要求している。これを満たすには、XmlValidatingReaderクラスを妥当性検証抜きのモードで使う必要がある。

 具体的にこれを実現するには、以下のようにソース・コードを書き換える。以下は、フォームのLoadイベントの内容を書き換えたものである。

Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
  Dim reader As XmlValidatingReader = New XmlValidatingReader( _
    New XmlTextReader(New StringReader(target)))
  reader.ValidationType = ValidationType.None
  While reader.Read()
    Trace.WriteLine("ノードを発見: " + reader.NodeType.ToString())
    If reader.NodeType = XmlNodeType.Text Then
      Trace.WriteLine(reader.Value)
    End If
    If reader.NodeType = XmlNodeType.EntityReference Then
      Trace.WriteLine(reader.Name)
    End If
  End While

End Sub
XmlValidatingReaderクラスを使用するサンプル(VB.NET版)
XmlValidatingReaderクラスを使用するサンプル(C#版)

 これを実行すると以下のような結果になる。

ノードを発見: XmlDeclaration
ノードを発見: DocumentType
ノードを発見: Element
ノードを発見: Text
ok
ノードを発見: EndElement
出力ウィンドウに表示される内容

 このように、「EntityReference」つまり実体を参照するノードを発見することはなくなり、その代わりに「Text」つまりテキストを参照するノードを発見している。その内容も、実体を展開した内容となっている。

 なお、.NET Frameworkのドキュメントによると、OASIS(Organization for the Advancement of Structured Information Standards)が提供するXMLの適合テストにパスする形で利用するには、XmlTextReaderおよびXmlValidatingReaderの設定を、次の例外を除いて既定(デフォルト)の設定にする必要があるとしている。

  • XmlTextReaderでNormalizationプロパティをtrueに設定する(既定値はfalse)。
  • XmlValidatingReaderでValidationCallbackハンドラを割り当る(既定では例外をスローする)。
  • XmlValidatingReaderのValidationTypeプロパティをValidationType.DTDに設定する(既定はValidationType Auto)。

 完全にXML1.0勧告を満たす形でXmlReaderを使うには、以上のような情報にも注意を払う必要がある。


 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 記事ランキング

本日 月間