System.Xml.XmlWriterSettingsクラスを用いると、XmlWriterクラスでのXML文書の出力時に使用する文字コード、インデントや改行などのフォーマットを細かく指定することができます。 また、テキストノード内の改行文字をエンティティ化して改行文字の種類を維持するかどうか、XML宣言を出力するかどうかといった出力時の動作も指定することができます。
デフォルト設定のXmlWriterでは、UTF-8を用いてXMLを出力する際にBOM(Byte Order Mark)を付与しますが、XmlWriterSettingsでBOMを出力しないEncodingを設定することによってXmlWriterにBOMなしのXMLを出力させるようにすることができます。
XmlWriterとXmlWriterSettings
XDocument.SaveメソッドやXmlDocument.Saveメソッドでは、直接ファイル名を指定して保存するほかにも、XmlWriterを用いて保存することができるようになっています。
XmlWriterSettingsで出力時のオプションを設定し、その設定に従って動作するXmlWriterをSaveメソッドに指定することで、出力時のフォーマットや動作を制御することができます。
XmlWriterの作成・出力先の指定
XmlWriterSettingsからXmlWriterを作成するにはXmlWriter.Createメソッドを使います。 第一引数には出力先となるファイル名を指定することができるほか、Stream派生クラスやStreamWriterなどのTextWriter派生クラスを出力先として指定することもできます。 第二引数には出力時のオプションが設定されたXmlWriterSettingsを指定します。
このようにMemoryStreamを用いればXMLツリーをメモリ上に展開することもできます。
XmlWriterを使ったXMLツリーの文字列化
XmlWriter.CreateメソッドでStringWriterを出力先に指定すれば、出力結果を文字列として取得することができます。 StringWriterを出力先とすることで、XMLツリーを文字列化する際にXmlWriterSettingsによって出力時のフォーマットを細かく指定することができます。
この例ではXmlWriterSettings.CloseOutputにfalse
を指定しています。 これにより、XmlWriterを閉じる際に出力先となるStringWriterを閉じないようになります。 このようにすることで、XmlWriterを使い終わったあともStringWriterを使い続けることができるようにしています。
逆にXmlWriterSettings.CloseOutputにtrue
を指定すると、XmlWriterが閉じられる際に元になったStream/TextWriterも同時に閉じるようになります。
XmlWriterSettingsで設定できる動作
ここまでで触れてきたような内容の他にも、XmlWriterSettingsでは以下のような動作を設定することができます。
XmlWriterSettingsのプロパティ | 動作 | 解説 | |
---|---|---|---|
出力フォーマットに関するプロパティ | XmlWriterSettings.Encoding | XmlWriterでの出力時に用いるエンコーディング(System.Text.Encoding)を指定する。 特に指定しなかった場合はデフォルトでUTF-8(BOM付き)が用いられる。 (どちらの場合もXDeclarationやXmlDeclarationによるエンコーディングの指定が上書きされる) |
§.エンコーディング (XmlWriterSettings.Encoding) |
XmlWriterSettings.Indent |
true を指定した場合、要素のインデントと要素間の改行を行う。インデント文字にはXmlWriterSettings.IndentCharsで指定された文字列を用いる。 改行文字にはXmlWriterSettings.NewLineCharsで指定された文字列を用いる。 false を指定した場合、インデントと改行は行われない。(デフォルトは false : インデントしない) |
§.インデント (XmlWriterSettings.Indent, IndentChars) | |
XmlWriterSettings.IndentChars | Indentがtrue の場合に要素のインデントに用いる空白文字を指定する。(デフォルトは " " : U+0020 'SPACE' 半角空白が2つ) |
||
XmlWriterSettings.NewLineChars | Indentがtrue の場合に要素間の改行に用いる改行文字を指定する。NewLineOnAttributesが true の場合は、こプロパティに指定した文字列が属性間の改行にも用いられる。(デフォルトは "\n" : U+000A 'LINE FEED' ラインフィードが1つ) |
§.要素間・属性間の改行 (XmlWriterSettings.NewLineChars, NewLineOnAttributes) | |
XmlWriterSettings.NewLineOnAttributes |
true を指定した場合(かつIndentもtrue の場合)、属性間の改行を行い、各属性が一行ごとに記述される。false を指定した場合、属性は要素と同じ行で一行に記述される。(デフォルトは false : 属性間の改行を行わない) |
||
XmlWriterSettings.NewLineHandling |
NewLineHandling.Entitize を指定した場合、テキストノードの"\r" (U+000D 'CARRIAGE RETURN')がエンティティ化(="
" )された上で出力される。NewLineHandling.Replace を指定した場合、テキストノードの"\r" および"\n" (U+000A 'LINE FEED')がNewLineCharsで設定されている改行文字に統一された上で出力される。この指定は属性値における改行文字・タブ文字にも影響する。 (デフォルトはNewLineHandling.None: そのままにする) |
§.テキストノード・属性値の改行の処理 (XmlWriterSettings.NewLineHandling) | |
XmlWriterSettings.OmitXmlDeclaration |
true を指定した場合、XML宣言の出力を省略する。false を指定した場合、XML宣言の出力を省略しない。(デフォルトは false : XML宣言を出力する) |
§.XML宣言の省略 (XmlWriterSetings.OmitXmlDeclaration) | |
XmlWriterSettings.NamespaceHandling |
NamespaceHandling.OmitDuplicatesを指定した場合、XMLツリー内に重複する名前空間宣言が存在する場合はそれを省略して出力する。 NamespaceHandling.Defaultを指定した場合、重複する名前空間宣言が存在していてもそのまま出力する。 (デフォルトは NamespaceHandling.Default : 重複する名前空間宣言を省略しない) |
§.重複する名前空間宣言の処理 (XmlWriterSettings.NamespaceHandling) | |
出力時の検証に関するプロパティ | XmlWriterSettings.CheckCharacters |
true を指定した場合、CRLFを除くC0制御文字などのXMLとして不正な文字が含まれているかチェックし、含まれている場合は例外をスローする。false を指定した場合、XMLとして不正な文字が含まれている場合はエンティティ化して出力し、例外はスローしない。(デフォルトは true : チェックする) |
§.不正な文字の処理 (XmlWriterSettings.CheckCharacters) |
XmlWriterSettings.ConformanceLevel |
ConformanceLevel.Documentを指定すれば、完全なXMLドキュメントとして適合するかどうかの検証が行われる。 ConformanceLevel.Fragmentを指定すれば、XMLフラグメント(不完全なXMLの断片)として適合するかどうかの検証が行われる。 いずれの場合も問題があればXmlExceptionがスローされる。 (デフォルトは ConformanceLevel.Document : 完全なXMLドキュメントとして検証する) |
||
XmlWriterの出力先に関するプロパティ | XmlWriterSettings.CloseOutput |
true を指定した場合、XmlWriterを閉じる際に元になったStream/TextWriterも同時に閉じる。false を指定した場合、XmlWriterを閉じても元になったStream/TextWriterは開いたままにする。 この場合、XmlWriterを使用し終わったあともStream/TextWriterを継続して用いることができる。(デフォルトは false : 元になったStream/TextWriterを開いたままにする) |
§.XmlWriterを使ったXMLツリーの文字列化 |
個々のプロパティを指定した場合の動作については以降で詳しく解説します。
エンコーディング (XmlWriterSettings.Encoding)
XmlWriterSettings.EncodingではXmlWriterで出力する際のエンコーディングを指定することができます。 デフォルトの状態ではUTF-8(BOM付き)が用いられます。 XmlWriterSettings.Encodingにnull
を指定することはできません。
XmlWriterSettings.Encodingを指定した場合、XML宣言にはそのエンコーディングが設定されます。 XMLツリーにXML宣言(XDeclarationやXmlDeclaration)が含まれていてencoding
属性でなんらかのエンコーディングを指定していても、XmlWriterSettings.Encodingの指定が優先され、XML宣言のencoding
属性が上書きされます。
BOM出力の制御
XDocument.Saveメソッドなどを用いて保存する場合、出力される内容の先頭にはBOM(Byte Order Mark)が付けられます。 また、XmlWriterSettings.EncodingにEncoding.UTF8を指定した場合や、XmlWriterSettings.Encodingをデフォルト値のままにした場合にもBOMが付けられます。
BOM無しのXMLを出力したい場合は、コンストラクタのパラメータencoderShouldEmitUTF8Identifierにfalse
を指定したUTF8Encodingを作成し、XmlWriterSettings.Encodingに指定します。
(BOM"EF-BB-BF"が先頭3バイトに出力されている)
(BOM"EF-BB-BF"が出力されていない)
UnicodeEncoding(UTF-16)やUTF32Encoding(UTF-32)の場合も同様にコンストラクタの引数byteOrderMarkによってBOMの有無を指定することができます。
System.Text.EncodingとBOMの関連や、他のクラスにおけるBOM出力の制御についてはEncodingクラスとBOMありなしの制御を参照してください。
XML宣言の省略 (XmlWriterSetings.OmitXmlDeclaration)
XmlWriterSettings.OmitXmlDeclarationにtrue
を指定すると、XML文書内にXDeclarationやXmlDeclarationが存在していてもXML宣言の出力を省略するようになります。
なお、XDocument.ToStringメソッドでは、文字列化に際してXML宣言が省略されます。
インデント (XmlWriterSettings.Indent, IndentChars)
XmlWriterSettings.Indentにtrue
を指定すると要素のインデントと要素間の改行を行った上で出力するようになります。
インデントに用いる文字はXmlWriterSettings.IndentCharsで指定します。 IndentCharsにはタブ("\t"
)や半角空白(" "
)、全角空白(" "
)、改行文字など、ホワイトスペースとして扱われる文字(Char.IsWhiteSpace = true
)からなる文字列を指定します。 それ以外の文字列を指定することもできますが、その場合は不正なXMLが出力されます。
改行文字の指定はXmlWriterSettings.NewLineCharsで行うことができます。
XmlWriterSettingsではインデント文字(空白やタブ)とインデント幅とを個別に指定することはできません。 あらかじめ目的のインデント幅を持った文字列をXmlWriterSettings.IndentCharsに指定する必要があります。
繰り返した文字列を作成する方法については文字列の加工・編集 §.乗算演算子(*, *=)・繰り返した文字列の生成を参照してください。
要素間・属性間の改行 (XmlWriterSettings.NewLineChars, NewLineOnAttributes)
XmlWriterSettings.Indentにtrue
を指定した上でXmlWriterSettings.NewLineCharsを指定すると、出力時に用いる改行文字を変更することができます。
IndentCharsと同様、NewLineCharsには改行文字以外にも空白などのホワイトスペースとして扱われる文字(Char.IsWhiteSpace = true
となる文字)からなる文字列を指定することもできます。
XmlWriterSettings.NewLineOnAttributesにtrue
を指定すると要素間だけでなく属性間にも改行を行うようにすることができます。 属性のインデントにはIndentCharsに指定されている文字列、改行にはNewLineCharsに指定されている文字列が用いられます。
属性値が長くなる場合や、要素に付与する属性の数が多数になる場合は、XmlWriterSettings.NewLineOnAttributesをtrue
にして属性間を改行することによって視認性を上げることができます。
テキストノード・属性値の改行の処理 (XmlWriterSettings.NewLineHandling)
XmlWriterSettings.NewLineHandlingプロパティではテキストノード・属性値に含まれる改行文字をどのように扱うかを指定することができます。
改行文字のエンティティ化 (NewLineHandling.Entitize)
NewLineHandling.Entitizeを指定した場合は、テキストノード内における"\r"
(U+000D 'CARRIAGE RETURN')がエンティティ化され、"
"として出力されます。 "\n"
(U+000A 'LINE FEED')はエンティティ化されません。 テキストノード内の各改行文字がそれぞれどのようにエンティティ化されるかを表にすると次のようになります。
XmlWriterSettings.NewLineHandlingの値 | テキストノード内の改行文字 | ||
---|---|---|---|
\r
|
\n
|
\r\n
|
|
NewLineHandling.None | \r | \n | \r\n |
NewLineHandling.Entitize | 
 | \n | 
\n |
NewLineHandling.Entitizeを指定して改行文字をエンティティ化しておくことには次のような利点があります。 例えば、出力したXML文書が他のXMLプロセッサによって読み込まれる際に、テキストノード・属性値内の改行文字が空白文字として扱われることによって消失したり変わってしまうことを防ぐことができます。 この指定は、テキストノード・属性値内における改行文字が重要な意味を持つ場合に特に有用です。
NewLineHandling.Entitizeを指定した場合は属性値も同様にエンティティ化されます。 属性値の場合、"\r"
と"\n"
(U+000A 'LINE FEED')の両方に加えて"\t"
(U+0009 'CHARACTER TABULATION')がエンティティ化されます。 属性値内の各制御文字がそれぞれどのようにエンティティ化されるかを表にすると次のようになります。
XmlWriterSettings.NewLineHandlingの値 | 属性値内の制御文字 | |||
---|---|---|---|---|
\r
|
\n
|
\r\n
|
\t
|
|
NewLineHandling.None | \r | \n | \r\n | \t |
NewLineHandling.Entitize | 
 | 
 | 
 | 	 |
改行文字の置換 (NewLineHandling.Replace)
NewLineHandling.Replaceを指定した場合は、テキストノード内における"\r"
(U+000D 'CARRIAGE RETURN')・"\n"
(U+000A 'LINE FEED')および"\r\n"
のシーケンスがXmlWriterSettings.NewLineCharsで設定されている値へと置換されます。 一方、属性値内における改行文字に対しては置換が行われず、NewLineHandling.Entitize
を指定した場合と同様のエンティティ化が行われます。
テキストノード内と属性値内の各改行文字がそれぞれどのように置換されるかを表にすると次のようになります。
XmlWriterSettings.NewLineHandlingの値 | テキストノード内の改行文字 | 属性値内の制御文字 | |||||
---|---|---|---|---|---|---|---|
\r
|
\n
|
\r\n
|
\r
|
\n
|
\r\n
|
\t
|
|
NewLineHandling.None | \r | \n | \r\n | \r | \n | \r\n | \t |
NewLineHandling.Replace | NewLineChars | NewLineChars | NewLineChars | 
 | 
 | 
 | 	 |
(XmlWriterSettings.NewLineCharsに置換される) | (NewLineHandling.Entitizeを指定した場合と同様にエンティティ化される) |
このように、NewLineHandling.Replace
を用いるとテキストノード内の改行文字を統一することができます。
(ここでcr = CR, nl = new line = LF)
NewLineHandling.Replace
を指定しても属性値の改行文字がNewLineCharsに置換されることはなく、NewLineHandling.Entitize
を指定した場合と同様にすべてエンティティ化されます。 改行文字だけでなく、タブ文字もエンティティ化される点に注意してください。
重複する名前空間宣言の処理 (XmlWriterSettings.NamespaceHandling)
XmlWriterSettings.NamespaceHandlingプロパティでは、XMLツリー内に重複する名前空間宣言(xmlns
属性)が存在する場合にそれらをどのように扱うかを指定することができます。
NamespaceHandling.OmitDuplicatesを指定した場合は、重複する名前空間宣言を削除し、最も上位にある名前空間宣言だけを残します。 この際、名前空間とプレフィックスの両方が一致する名前空間宣言のみが削除されます。 プレフィックスが異なる名前空間宣言は別のものとして扱われ、省略されることはありません。
NamespaceHandling.Defaultを指定した場合は、名前空間宣言が重複していてもそのままにします。
次の例のように、名前空間が同一でもプレフィックスが異なっている場合はそれぞれ個別の名前空間宣言とみなされ、NamespaceHandling.OmitDuplicatesを指定しても名前空間宣言の省略は行われません。
XDocument.Saveメソッドを用いる場合は、SaveOptions.OmitDuplicateNamespacesを使うことでもこのプロパティと同じ結果を得ることができます。
不正な文字の処理 (XmlWriterSettings.CheckCharacters)
XmlWriterSettings.CheckCharactersプロパティでは、XML内にC0制御文字(CR・LFを除く)など、XMLとして不正な文字が含まれているかをチェックするかどうかを指定することができます。
true
を指定してチェックするようにした場合、不正な文字が含まれている際には出力時に例外ArgumentExceptionをスローします。
false
を指定してチェックしないようにした場合、不正な文字が含まれている際にはそれをエンティティ化して出力します。 例外はスローしません。