Подтвердить что ты не робот

Исключить недопустимые символы XML в С#

У меня есть строка, содержащая недопустимые символы XML. Как я могу избежать (или удалить) недопустимых символов XML перед тем, как я разобрал строку?

4b9b3361

Ответ 1

В качестве способа удаления недопустимых символов 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;
    }
}

Обновление: следует отметить, что операция кодирования создает строку с длиной, которая больше или равна длине исходной строки. Это может быть важно, когда вы храните закодированную строку в базе данных в столбце строк с ограничением длины и проверяете длину строки источника в своем приложении, чтобы соответствовать ограничению столбца данных.

Ответ 2

Используйте SecurityElement.Escape

using System;
using System.Security;

class Sample {
  static void Main() {
    string text = "Escape characters : < > & \" \'";
    string xmlText = SecurityElement.Escape(text);
//output:
//Escape characters : &lt; &gt; &amp; &quot; &apos;
    Console.WriteLine(xmlText);
  }
}

Ответ 3

Если вы пишете xml, просто используйте классы, предоставленные фреймворком, для создания xml. Вам не придется беспокоиться о побеге или чем-то еще.

Console.Write(new XElement("Data", "< > &"));

Выведет

<Data>&lt; &gt; &amp;</Data>

Если вам нужно прочитать XML файл с неверным выражением, не использовать регулярное выражение. Вместо этого используйте Html Agility Pack.

Ответ 4

Метод 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();
}

Ответ 5

Вот оптимизированная версия вышеупомянутого метода 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();

}

Ответ 6

// Replace invalid characters with empty strings.
   Regex.Replace(inputString, @"[^\w\[email protected]]", ""); 

Шаблон регулярного выражения [^\w. @-] соответствует любому символу, который не является символом слова, периодом, символом @или дефисом. Символом слова является любая буква, десятичная цифра или знак пунктуации, такой как символ подчеркивания. Любой символ, соответствующий этому шаблону, заменяется на String.Empty, который является строкой, определяемой шаблоном замены. Чтобы добавить дополнительные символы в пользовательский ввод, добавьте эти символы в класс символов в шаблоне регулярных выражений. Например, шаблон регулярного выражения [^\w. @- \%] также допускает процентный символ и обратную косую черту во входной строке.

Regex.Replace(inputString, @"[[email protected]#$%_]", "");

См. также:

Удаление недопустимых символов из тега имени XML - RegEx С#

Вот функция для удаления символов из указанной строки 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;
        }
    }
}

Ответ 7

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).