ものがたり(旧)

atsushieno.hatenablog.com に続く

XmlWriter.WriteCData()はボミョー

小ネタに便乗するにょ。

http://d.hatena.ne.jp/ladybug/20071109#p2

僕ならWriteString()をオーバーライドしてWriteStateがAttributeでない時だけWriteCData()を呼び出す、特別なXmlWriterを作るかな。

ただ、WriteCData()とWriteString()の動作は等価ではない。僕が書いたXmlTextWriter.WriteCData()のコードはこんな感じだ:

public override void WriteCData (string text)
{
	if (text == null)
		text = String.Empty;
	ShiftStateContent ("CData", false);
	if (StringUtil.IndexOf (text, "]]>") >= 0)
		throw ArgumentError ("CDATA section must not contain ']]>'.");
	writer.Write ("<![CDATA[");
	WriteCheckedString (text);
	writer.Write ("]]>");
}

何がポイントかというと、WriteCData()の引数には "]]>" が含まれていてはいけない、ということ。そんなの文字参照でも使ってエスケープしろ、とか思うわけだが、たぶんエスケープするお決まりの方法が無く、WriteCharEntity()なんてマニアックなメソッドは正しく実装されない可能性もあるから、エラーで弾くなんて仕様になったんだろうな。

いずれにしても、そんな面倒があるので、WriteString()からWriteCData()に処理をたらい回す時は、"]]>"があるごとに、WriteCData()の呼び出しを別途行わなければならない。しかも

WriteCData ("foo");
WriteCData ("]]>bar");

としたら意味がないので、

WriteCData ("foo]]");
WriteCData (">bar");

みたいな感じになる。めんどくさいな、これ。そこまでしてCDATAセクションにこだわる必要は、まあ無いだろうから、WriteString ("]]>")って書いても良いだろうと思う。