DOM の拡張
Microsoft .NET Framework は、XML ドキュメント オブジェクト モデル (DOM) の実装を提供するクラスの基本セットを備えています。 XmlNode およびその派生クラスのメソッドとプロパティを利用して、XML ドキュメントの内容および構造の中で移動し、それらに対してクエリを実行し、それらを変更することができます。
DOM を使用して XML コンテンツをメモリに読み込むと、作成されたノードには、ノード名やノード型などの情報が格納されます。 場合によっては、基本クラスによっては提供されない特定のノード情報が必要になることもあります。 たとえば、ノードの行番号と位置が必要な場合です。 このような場合は、既存の DOM クラスから新しいクラスを派生させ、追加機能を持たせることができます。
新しいクラスを派生させるときの一般的なガイドラインは、次の 2 つです。
XmlNode クラスからはクラスを派生させないことをお勧めします。 その代わりに、目的とするノード型に対応するクラスからクラスを派生させることをお勧めします。 たとえば、属性ノードの追加情報を返すようにする場合は、XmlAttribute クラスからクラスを派生させます。
ノード作成メソッド以外の関数をオーバーライドするときは、常にその関数の基本バージョンを呼び出してから、他の処理を追加することをお勧めします。
独自のノード インスタンスの作成
XmlDocument クラスは、ノード作成メソッドを持っています。 XML ファイルが読み込まれると、ノード作成メソッドが呼び出され、ノードが作成されます。 これらのメソッドをオーバーライドすると、ドキュメントが読み込まれるときに独自のノード インスタンスを作成できます。 たとえば、XmlElement クラスを拡張すると、XmlDocument クラスが継承され、CreateElement メソッドがオーバーライドされます。
CreateElement メソッドをオーバーライドし、XmlElement クラスの独自の実装を返す方法を次の例に示します。
Class LineInfoDocument
Inherits XmlDocument
Public Overrides Function CreateElement(prefix As String, localname As String, nsURI As String) As XmlElement
Dim elem As New LineInfoElement(prefix, localname, nsURI, Me)
Return elem
End Function 'CreateElement
End Class 'LineInfoDocument
class LineInfoDocument : XmlDocument
{
public override XmlElement CreateElement(string prefix, string localname, string nsURI)
{
LineInfoElement elem = new LineInfoElement(prefix, localname, nsURI, this);
return elem;
}
}
クラスの拡張
クラスを拡張するには、既存の DOM クラスの 1 つから独自のクラスを派生させます。 その後、基本クラスの仮想メソッドやプロパティをオーバーライドしたり、独自のメソッドやプロパティを追加します。
次の例では、XmlElement クラスと IXmlLineInfo インターフェイスを実装する新しいクラスを作成しています。 行番号を収集できるようにする追加のメソッドとプロパティが定義されます。
Class LineInfoElement
Inherits XmlElement
Implements IXmlLineInfo
Private lineNumber As Integer = 0
Private linePosition As Integer = 0
Friend Sub New(prefix As String, localname As String, nsURI As String, doc As XmlDocument)
MyBase.New(prefix, localname, nsURI, doc)
CType(doc, LineInfoDocument).IncrementElementCount()
End Sub
Public Sub SetLineInfo(linenum As Integer, linepos As Integer)
lineNumber = linenum
linePosition = linepos
End Sub
Public ReadOnly Property LineNumber() As Integer
Get
Return lineNumber
End Get
End Property
Public ReadOnly Property LinePosition() As Integer
Get
Return linePosition
End Get
End Property
Public Function HasLineInfo() As Boolean
Return True
End Function
End Class ' End LineInfoElement class.
class LineInfoElement : XmlElement, IXmlLineInfo {
int lineNumber = 0;
int linePosition = 0;
internal LineInfoElement( string prefix, string localname, string nsURI, XmlDocument doc ) : base( prefix, localname, nsURI, doc ) {
( (LineInfoDocument)doc ).IncrementElementCount();
}
public void SetLineInfo( int linenum, int linepos ) {
lineNumber = linenum;
linePosition = linepos;
}
public int LineNumber {
get {
return lineNumber;
}
}
public int LinePosition {
get {
return linePosition;
}
}
public bool HasLineInfo() {
return true;
}
} // End LineInfoElement class.
例
XML ドキュメントの要素数を数える例を次に示します。
Imports System.Xml
Imports System.IO
Class LineInfoDocument
Inherits XmlDocument
Private elementCount As Integer
Friend Sub New()
elementCount = 0
End Sub
Public Overrides Function CreateElement(prefix As String, localname As String, nsURI As String) As XmlElement
Dim elem As New LineInfoElement(prefix, localname, nsURI, Me)
Return elem
End Function
Public Sub IncrementElementCount()
elementCount += 1
End Sub
Public Function GetCount() As Integer
Return elementCount
End Function
End Class 'End LineInfoDocument class.
Class LineInfoElement
Inherits XmlElement
Friend Sub New(prefix As String, localname As String, nsURI As String, doc As XmlDocument)
MyBase.New(prefix, localname, nsURI, doc)
CType(doc, LineInfoDocument).IncrementElementCount()
End Sub 'New
End Class 'LineInfoElement
_ 'End LineInfoElement class.
Public Class Test
Private filename As [String] = "book.xml"
Public Shared Sub Main()
Dim doc As New LineInfoDocument()
doc.Load(filename)
Console.WriteLine("Number of elements in {0}: {1}", filename, doc.GetCount())
End Sub
End Class
using System;
using System.Xml;
using System.IO;
class LineInfoDocument : XmlDocument {
int elementCount;
internal LineInfoDocument():base() {
elementCount = 0;
}
public override XmlElement CreateElement( string prefix, string localname, string nsURI) {
LineInfoElement elem = new LineInfoElement(prefix, localname, nsURI, this );
return elem;
}
public void IncrementElementCount() {
elementCount++;
}
public int GetCount() {
return elementCount;
}
} // End LineInfoDocument class.
class LineInfoElement:XmlElement {
internal LineInfoElement( string prefix, string localname, string nsURI, XmlDocument doc ):base( prefix,localname,nsURI, doc ){
((LineInfoDocument)doc).IncrementElementCount();
}
} // End LineInfoElement class.
public class Test {
const String filename = "book.xml";
public static void Main() {
LineInfoDocument doc =new LineInfoDocument();
doc.Load(filename);
Console.WriteLine("Number of elements in {0}: {1}", filename, doc.GetCount());
}
}
入力
book.xml
<!--sample XML fragment-->
<book genre='novel' ISBN='1-861001-57-5' misc='sale-item'>
<title>The Handmaid's Tale</title>
<price>14.95</price>
</book>
Output
Number of elements in book.xml: 3
ノード イベント ハンドラー
.NET Framework による DOM の実装には、XML ドキュメントのノードが変更されたときにイベントを受け取って処理できるようにする、イベント システムも含まれています。 XmlNodeChangedEventHandler クラスと XmlNodeChangedEventArgs クラスを使用して、NodeChanged
イベント、NodeChanging
イベント、NodeInserted
イベント、NodeInserting
イベント、NodeRemoved
イベント、および NodeRemoving
イベントをキャプチャできます。
イベント処理プロセスは、派生クラスでも、元の DOM クラスとまったく同じように動作します。
ノード イベント処理については、「イベント」と「XmlNodeChangedEventHandler」を参照してください。
既定の属性と CreateElement メソッド
派生クラスの CreateElement メソッドをオーバーライドした場合は、ドキュメントの編集中に新しい要素を作成しても、既定の属性は追加されません。 これは編集中だけの問題です。 CreateElement メソッドが既定の属性を XmlDocument に追加する機能を実行するため、この機能は CreateElement メソッドにコーディングする必要があります。 既定の属性が含まれた XmlDocument を読み込めば、既定の属性が正しく処理されます。 既定の属性の詳細については、「DOM の要素に対する新しい属性の作成」を参照してください。
関連項目
.NET