У меня есть строка, содержащая недопустимые символы XML. Как я могу избежать (или удалить) недопустимые символы XML перед синтаксическим анализом строки?
У меня есть строка, содержащая недопустимые символы XML. Как я могу избежать (или удалить) недопустимые символы XML перед синтаксическим анализом строки?
Ответы:
В качестве способа удаления недопустимых символов XML я предлагаю вам использовать метод XmlConvert.IsXmlChar . Он был добавлен с .NET Framework 4 и также представлен в Silverlight. Вот небольшой образец:
void Main() {
string content = "\v\f\0";
Console.WriteLine(IsValidXmlString(content)); // False
content = RemoveInvalidXmlChars(content);
Console.WriteLine(IsValidXmlString(content)); // True
}
static string RemoveInvalidXmlChars(string text) {
var validXmlChars = text.Where(ch => XmlConvert.IsXmlChar(ch)).ToArray();
return new string(validXmlChars);
}
static bool IsValidXmlString(string text) {
try {
XmlConvert.VerifyXmlChars(text);
return true;
} catch {
return false;
}
}
И как способ избежать недопустимых символов XML я предлагаю вам использовать метод XmlConvert.EncodeName . Вот небольшой образец:
void Main() {
const string content = "\v\f\0";
Console.WriteLine(IsValidXmlString(content)); // False
string encoded = XmlConvert.EncodeName(content);
Console.WriteLine(IsValidXmlString(encoded)); // True
string decoded = XmlConvert.DecodeName(encoded);
Console.WriteLine(content == decoded); // True
}
static bool IsValidXmlString(string text) {
try {
XmlConvert.VerifyXmlChars(text);
return true;
} catch {
return false;
}
}
Обновление: следует отметить, что операция кодирования создает строку с длиной, которая больше или равна длине исходной строки. Это может быть важно, когда вы храните закодированную строку в базе данных в строковом столбце с ограничением длины и проверяете длину исходной строки в вашем приложении на соответствие ограничению столбца данных.
XmlConvert.VerifyXmlChars
не генерирует исключение, если аргумент содержит недопустимые символы, он возвращает пустую строку (и возвращает аргумент, если все содержащиеся символы допустимы). Просто попробуй return XmlConvert.VerifyXmlChars (text) != null
.
Используйте SecurityElement.Escape
using System;
using System.Security;
class Sample {
static void Main() {
string text = "Escape characters : < > & \" \'";
string xmlText = SecurityElement.Escape(text);
//output:
//Escape characters : < > & " '
Console.WriteLine(xmlText);
}
}
Если вы пишете xml, просто используйте классы, предоставляемые фреймворком, для создания xml. Вам не придется беспокоиться о побеге или чем-то еще.
Console.Write(new XElement("Data", "< > &"));
Будет выводить
<Data>< > &</Data>
Если вам нужно прочитать XML-файл, который имеет неправильный формат, не используйте регулярное выражение. Вместо этого используйте Html Agility Pack .
<Data>&</Data>
?
Метод RemoveInvalidXmlChars, предоставленный Irishman, не поддерживает суррогатные символы. Чтобы проверить это, используйте следующий пример:
static void Main()
{
const string content = "\v\U00010330";
string newContent = RemoveInvalidXmlChars(content);
Console.WriteLine(newContent);
}
Это возвращает пустую строку, но этого не должно быть! Он должен вернуть «\ U00010330», потому что символ U + 10330 является допустимым символом XML.
Для поддержки суррогатных символов я предлагаю использовать следующий метод:
public static string RemoveInvalidXmlChars(string text)
{
if (string.IsNullOrEmpty(text))
return text;
int length = text.Length;
StringBuilder stringBuilder = new StringBuilder(length);
for (int i = 0; i < length; ++i)
{
if (XmlConvert.IsXmlChar(text[i]))
{
stringBuilder.Append(text[i]);
}
else if (i + 1 < length && XmlConvert.IsXmlSurrogatePair(text[i + 1], text[i]))
{
stringBuilder.Append(text[i]);
stringBuilder.Append(text[i + 1]);
++i;
}
}
return stringBuilder.ToString();
}
Вот оптимизированная версия вышеупомянутого метода RemoveInvalidXmlChars, который не создает новый массив при каждом вызове, что излишне нагружает GC:
public static string RemoveInvalidXmlChars(string text)
{
if (text == null)
return text;
if (text.Length == 0)
return text;
// a bit complicated, but avoids memory usage if not necessary
StringBuilder result = null;
for (int i = 0; i < text.Length; i++)
{
var ch = text[i];
if (XmlConvert.IsXmlChar(ch))
{
result?.Append(ch);
}
else if (result == null)
{
result = new StringBuilder();
result.Append(text.Substring(0, i));
}
}
if (result == null)
return text; // no invalid xml chars detected - return original text
else
return result.ToString();
}
?.
синтаксис? в очереди result?.Append(ch);
?
// Replace invalid characters with empty strings.
Regex.Replace(inputString, @"[^\w\.@-]", "");
Шаблон регулярного выражения [^ \ w. @ -] соответствует любому символу, который не является символом слова, точкой, знаком @ или дефисом. Символ слова - это любая буква, десятичная цифра или знак препинания, например подчеркивание. Любой символ, соответствующий этому шаблону, заменяется на String.Empty, которая является строкой, определенной шаблоном замены. Чтобы разрешить ввод дополнительных символов пользователем, добавьте эти символы в класс символов в шаблоне регулярного выражения. Например, шаблон регулярного выражения [^ \ w. @ - \%] также допускает использование символа процента и обратной косой черты во входной строке.
Regex.Replace(inputString, @"[!@#$%_]", "");
Обратитесь и к этому:
Удаление недопустимых символов из тега имени XML - RegEx C #
Вот функция для удаления символов из указанной строки XML:
using System;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
namespace XMLUtils
{
class Standards
{
/// <summary>
/// Strips non-printable ascii characters
/// Refer to http://www.w3.org/TR/xml11/#charsets for XML 1.1
/// Refer to http://www.w3.org/TR/2006/REC-xml-20060816/#charsets for XML 1.0
/// </summary>
/// <param name="content">contents</param>
/// <param name="XMLVersion">XML Specification to use. Can be 1.0 or 1.1</param>
private void StripIllegalXMLChars(string tmpContents, string XMLVersion)
{
string pattern = String.Empty;
switch (XMLVersion)
{
case "1.0":
pattern = @"#x((10?|[2-F])FFF[EF]|FDD[0-9A-F]|7F|8[0-46-9A-F]9[0-9A-F])";
break;
case "1.1":
pattern = @"#x((10?|[2-F])FFF[EF]|FDD[0-9A-F]|[19][0-9A-F]|7F|8[0-46-9A-F]|0?[1-8BCEF])";
break;
default:
throw new Exception("Error: Invalid XML Version!");
}
Regex regex = new Regex(pattern, RegexOptions.IgnoreCase);
if (regex.IsMatch(tmpContents))
{
tmpContents = regex.Replace(tmpContents, String.Empty);
}
tmpContents = string.Empty;
}
}
}
string XMLWriteStringWithoutIllegalCharacters(string UnfilteredString)
{
if (UnfilteredString == null)
return string.Empty;
return XmlConvert.EncodeName(UnfilteredString);
}
string XMLReadStringWithoutIllegalCharacters(string FilteredString)
{
if (UnfilteredString == null)
return string.Empty;
return XmlConvert.DecodeName(UnfilteredString);
}
Этот простой метод заменяет недопустимые символы тем же значением, но принимается в контексте XML.
Для записи строки используйте XMLWriteStringWithoutIllegalCharacters (строка UnfilteredString).
Для чтения строки используйте XMLReadStringWithoutIllegalCharacters (строка FilteredString).