組み込みの.NETエスケープ機能もSecurityElement.Escape
、適切にエスケープ/ストリップしません。
- アプリケーションがファイルと対話する唯一のアプリケーションである場合は、ライターとリーダーの両方に
CheckCharacters
設定できます。false
ただし、結果のXMLファイルは技術的には無効です。
見る:
XmlWriterSettings xmlWriterSettings = new XmlWriterSettings();
xmlWriterSettings.Encoding = new UTF8Encoding(false);
xmlWriterSettings.CheckCharacters = false;
var sb = new StringBuilder();
var w = XmlWriter.Create(sb, xmlWriterSettings);
w.WriteStartDocument();
w.WriteStartElement("Test");
w.WriteString("hello \xb world");
w.WriteEndElement();
w.WriteEndDocument();
w.Close();
var xml = sb.ToString();
- (デフォルトでは)に設定
CheckCharacters
するtrue
のが少し厳しすぎる場合は、単に例外をスローするため、無効なXML文字に対してより寛容な代替アプローチは、それらを削除することです。
少しグーグルするとホワイトリストXmlTextEncoderが生成されましたが、ウィキペディアの有効なXML文字によると、特定のコンテキストでのみ有効であるDEL
U + 007F–U + 0084、U + 0086–U+009Fの範囲のその他の文字も削除されます。 RFCは、推奨されていないがまだ有効な文字として言及しています。
public static class XmlTextExtentions
{
private static readonly Dictionary<char, string> textEntities = new Dictionary<char, string> {
{ '&', "&"}, { '<', "<" }, { '>', ">" },
{ '"', """ }, { '\'', "'" }
};
public static string ToValidXmlString(this string str)
{
var stripped = str
.Select((c,i) => new
{
c1 = c,
c2 = i + 1 < str.Length ? str[i+1]: default(char),
v = XmlConvert.IsXmlChar(c),
p = i + 1 < str.Length ? XmlConvert.IsXmlSurrogatePair(str[i + 1], c) : false,
pp = i > 0 ? XmlConvert.IsXmlSurrogatePair(c, str[i - 1]) : false
})
.Aggregate("", (s, c) => {
if (c.pp)
return s;
if (textEntities.ContainsKey(c.c1))
s += textEntities[c.c1];
else if (c.v)
s += c.c1.ToString();
else if (c.p)
s += c.c1.ToString() + c.c2.ToString();
return s;
});
return stripped;
}
}
DEL
これは、すべてのXmlTextEncoderテストに合格します。ただしXmlConvert.IsXmlChar
、ウィキペディアとスペックマークを有効な(推奨されない)文字として削除することを期待するテストを除きます。