内置 .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但是它也会删除DEL
和范围 U+007F–U+0084、U+0086–U+009F 中的其他内容,根据维基百科上的Valid XML Characters仅在某些上下文中有效,并且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;
}
}
这通过了所有 XmlTextEncoder 测试,除了期望它剥离DEL
which XmlConvert.IsXmlChar
、 Wikipedia 和规范标记为有效(尽管不鼓励)字符的测试。