カスタマイズされた XML ライタの作成
XmlTextWriter 実装では、以下の処理は行われません。
- XmlTextWriter は、要素名または属性名が有効であることを確認しません。
- XmlTextWriter は、0x0 ~ 0x20 の範囲内の Unicode 文字と、文字 0xFFFE および 0xFFFF を書き込みますが、これらは XML 文字ではありません。
- XmlTextWriter は重複する属性を検出しません。例外をスローせずに、重複する属性を書き込みます。
これら 3 つの項目がアプリケーションにとって重要である場合は、現在の XmlTextWriter を拡張してこれらの機能を加えたカスタム ライタを書くことができます。
XML ライタを変更して WriteString メソッドと WriteStartElement メソッドを上書きする方法を示す例を次に示します。このコード サンプルでは、有効な XML が書き込まれる保証はありません。このコードは、書き出される文字列に範囲外の文字が含まれないことと、要素名が有効であることをチェックするだけです。属性名はチェックしません。
最初の手順は、文字列内の文字が W3C 仕様に従う有効な文字であるか確認するメソッドを定義することです。このメソッドを使用して、ライタによって書き出された文字列が正しいことを確認します。文字列に対して行う固有のテストを次に示します。
- 0xFFFD より大きいまたは 0x20 より小さい 16 進数文字がないことを確認します。
- 文字が、タブ (\t)、改行 (\n)、キャリッジ リターン (\r)、または 0x20 より小さい無効な XML 文字、のいずれでもないことをチェックします。いずれかの文字があると、例外がスローされます。
このメソッドを示すコード例を次に示します。
internal void CheckUnicodeString(String value) { for (int i=0; i < value.Length; ++i) { if (value[i] > 0xFFFD) { throw new Exception("Invalid Unicode"); } else if (value[i] < 0x20 && value[i] != '\t' & value[i] != '\n' & value[i] != '\r') { throw new Exception("Invalid Xml Characters"); } }
次に、手順 1 で定義されたメソッドを使用して、XmlTextWriter 内で WriteString メソッドを上書きします。上書きされた WriteString メソッドは、文字列の文字が有効な文字範囲外である場合に例外をスローします。
public override void WriteString(String value) { CheckUnicodeString(value); base.WriteString(value); }
WriteStartElement メソッドによって書き込まれた名前が有効であることを確認するには、XmlConvert クラスの EncodeLocalName メソッドを使用します。EncodeLocalName メソッドを使用して、無効な文字すべてを有効な表現に変換することによって、名前に含まれる文字を有効にします。たとえば、Order Details
は Order_x0020_Details
に変換されます。EncodeLocalName の詳細については、「EncodeLocalName メソッド」を参照してください。
public override void WriteStartElement(string prefix, string localName, string ns)
{
base.WriteStartElement(prefix,
XmlConvert.EncodeLocalName(localName),ns);
}
EncodeLocalName メソッドを使用しなくても、XmlConvert クラスの VerifyName メソッドを使用して、要素名または属性名が有効であることを確認できます。VerifyName メソッドは、名前が有効な場合は引数の戻り値として名前を返し、名前が無効な場合は例外をスローします。このメソッドは、無効な名前によってエラーが発生したことを認識するのに役立ちます。名前が有効かどうかをチェックする場合に、VerifyName メソッドを使用して WriteStartElement メソッドを作成する方法を次の例に示します。
public override void WriteStartElement(string prefix, string localName,
string ns)
{
base.WriteStartElement(prefix,
XmlConvert.VerifyName(localName),ns);
}
メモ 他の WriteStartElement メソッドは、いずれも上のメソッドを呼び出すため、上書きする必要はありません。
準拠する Writer の完全なコード サンプル
次に示すのは、クラス定義すべてを一覧にするコード サンプルです。有効な文字が確実に書き出されるように、WriteDocType、WriteAttributeString、WriteElementString、WriteCharEntity など、追加のメソッドをオーバーライドする必要があります。これらのメソッドをオーバーライドする方法は、WriteStartElement メソッドのオーバーライドを指示するコードに似ています。
Imports System
Imports System.IO
Imports System.Text
Imports System.Xml
Imports System.Collections
Imports Microsoft.VisualBasic
'------------------------------------------------------------------
' Class derived from XmlTextWriter classs.
'
' This example only overrides the WriteString and WriteStartElement
' methods.
'------------------------------------------------------------------
namespace MyWriter.ConformWriter
public class ConformWriter : Inherits XmlTextWriter
private sub CheckUnicodeString(ByVal value as String)
Dim i as Integer
Dim iVal as Integer
for i=0 to value.Length-1
iVal = Convert.ToInt16(value.Chars(i))
if (iVal > &HFFFD)
throw new Exception("Invalid Unicode")
else
if iVal < &H20 And (iVal <> 9 And iVal <> 13 And iVal <> 10) Then
throw new Exception("Invalid Xml Characters")
end if
end if
next
end sub
public sub New(ByVal fileName as String, ByVal encoding as Encoding)
MyBase.New(fileName, encoding)
end sub
Overrides public sub WriteString(ByVal value as String)
CheckUnicodeString(value)
MyBase.WriteString(value)
end sub
Overrides Overloads public sub WriteStartElement(ByVal prefix As String, ByVal localname As String, ByVal ns As String)
MyBase.WriteStartElement(prefix, XmlConvert.EncodeLocalName(localName), ns)
end sub
end class
end namespace
[C#]
using System;
using System.IO;
using System.Text;
using System.Xml;
using System.Collections;
//------------------------------------------------------------------
// Class derived from XmlTextWriter classs.
//
// This sample only overrides the WriteString and WriteStartElement
// methods.
//------------------------------------------------------------------
namespace MyWriter.ConformWriter {
public class ConformWriter : XmlTextWriter
{
internal void CheckUnicodeString(String value) {
for (int i=0; i < value.Length; ++i) {
if (value[i] > 0xFFFD) {
throw new Exception("Invalid Unicode");
} else if (value[i] < 0x20 && value[i] != '\t' & value[i] != '\n' & value[i] != '\r') {
throw new Exception("Invalid Xml Characters");
}
}
}
public ConformWriter(String fileName, Encoding encoding):base(fileName, encoding) {}
public override void WriteString(String value) {
CheckUnicodeString(value);
base.WriteString(value);
}
public override void WriteStartElement(string prefix, string localName, string ns) {
base.WriteStartElement(prefix, XmlConvert.EncodeLocalName(localName), ns);
}
}
}