Встроенные в .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, что в соответствии с Допустимые символы XML в Википедии действительны только в определенных контекстах, которые 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
, который XmlConvert.IsXmlChar
, Википедия и спецификация помечают как действительный (хотя и не рекомендуется) символ.