Как удалить недопустимые шестнадцатеричные символы из источника данных на основе XML до создания XmlReader или XPathDocument, использующего эти данные?

Есть ли какой-либо простой / общий способ очистить источник данных на основе XML перед его использованием в XmlReader, чтобы я мог изящно использовать данные XML, которые не соответствуют ограничениям шестнадцатеричных символов, наложенным на XML?

Примечание:

  • Решение должно обрабатывать XML источники данных, использующие символ кодировки, отличные от UTF-8, например к указав кодировку символов в объявление XML-документа. Нет изменение кодировки символов источник при зачистке недействителен шестнадцатеричные символы были главный камень преткновения.
  • Удаление недопустимых шестнадцатеричных символов должно удалять только шестнадцатеричные закодированные значения, так как вы часто можете найти значения href в данных, которые содержат строку, которая будет совпадением строки для шестнадцатеричного символа.

Фон:

Мне нужно использовать источник данных на основе XML, который соответствует определенному формату (например, Atom или RSS-каналы), но я хочу иметь возможность использовать опубликованные источники данных, которые содержат недопустимые шестнадцатеричные символы в соответствии со спецификацией XML.

В .NET, если у вас есть Stream, представляющий источник данных XML, а затем вы пытаетесь проанализировать его с помощью XmlReader и / или XPathDocument, возникает исключение из-за включения недопустимых шестнадцатеричных символов в данные XML. Моя текущая попытка решить эту проблему - проанализировать Stream как строку и использовать регулярное выражение для удаления и / или замены недопустимых шестнадцатеричных символов, но я ищу более эффективное решение.

Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
76
0
96 612
14
Перейти к ответу Данный вопрос помечен как решенный

Ответы 14

Ответ принят как подходящий

Это может быть не идеальным (курсив добавлен, так как люди пропускают этот отказ от ответственности), но то, что я сделал в этом случае, ниже. Вы можете настроить использование с потоком.

/// <summary>
/// Removes control characters and other non-UTF-8 characters
/// </summary>
/// <param name = "inString">The string to process</param>
/// <returns>A string with no control characters or entities above 0x00FD</returns>
public static string RemoveTroublesomeCharacters(string inString)
{
    if (inString == null) return null;

    StringBuilder newString = new StringBuilder();
    char ch;

    for (int i = 0; i < inString.Length; i++)
    {

        ch = inString[i];
        // remove any characters outside the valid UTF-8 range as well as all control characters
        // except tabs and new lines
        //if ((ch < 0x00FD && ch > 0x001F) || ch == '\t' || ch == '\n' || ch == '\r')
        //if using .NET version prior to 4, use above logic
        if (XmlConvert.IsXmlChar(ch)) //this method is new in .NET 4
        {
            newString.Append(ch);
        }
    }
    return newString.ToString();

}

Он не поймал 0x3c, одно из моих приложений считает, что его шестнадцатеричный, я использую ibex

Thunder 21.09.2010 10:22

попробуйте решение dnewcome ниже.

Eugene Katz 21.09.2010 21:07

-1 этот ответ вводит в заблуждение, потому что он удаляет символы, которые действительны в XML, которые не являются управляющими символами и являются допустимыми UTF-8.

Daniel Cassidy 02.09.2011 19:43

@DanielCassidy Вы писали о том, что все это неправильно, но я не вижу вашей публикации с правильным решением. Не могли бы вы опубликовать образец кода, показывающий, как правильно обрабатывать удаление управляющих символов?

Ryan Rinaldi 21.10.2011 20:33

@RyanRinaldi У меня есть ответ получше, частично написанный, я постараюсь закончить его и опубликовать в эти выходные. А пока ответ dnewcome является лучшим, если вы готовы согласиться с тем, что он не будет работать должным образом, если ваш XML-код содержит символы из-за пределов базовой многоязычной плоскости. Поскольку Basic Multilingual Plane включает в себя все символы, необходимые для каждого современного естественного языка, это, вероятно, не проблема для вас, хотя в реальных случаях требуются символы за пределами этого диапазона (например, некоторые математические).

Daniel Cassidy 21.10.2011 20:55

Если вы хотите обновить ответ, добавив в него лучший набор фильтров, не стесняйтесь. Как говорится в моем ответе, он может быть не идеальным, но он удовлетворил мои потребности.

Eugene Katz 21.10.2011 22:52

Я использовал XmlConvert.IsXmlChar (ch) для своего фильтра.

Brad J 25.02.2015 19:27

@BradJ, очень хорошее замечание. Похоже, что этот метод был добавлен в .NET 4, поэтому переключил код на его использование в примере. Спасибо!

Eugene Katz 25.02.2015 23:21

Мне нравится концепция белых списков Юджина. Мне нужно было сделать то же самое, что и исходный плакат, но мне нужно было поддерживать все символы Unicode, а не только до 0x00FD. Спецификация XML:

Char = # x9 | #xA | #xD | [# x20- # xD7FF] | [# xE000- # xFFFD] | [# x10000- # x10FFFF]

В .NET внутреннее представление символов Unicode составляет всего 16 бит, поэтому мы не можем явно `разрешить '0x10000-0x10FFFF. Спецификация XML явно запрещает суррогатных кодовых точек, начинающихся с 0xD800, с момента появления. Однако возможно, что, если мы позволим эти суррогатные кодовые точки в нашем белом списке, кодировка utf-8 нашей строки может привести к получению допустимого XML в конце, если правильная кодировка utf-8 была произведена из суррогатных пар символов utf-16 в Строка .NET. Я не исследовал это, поэтому я сделал более безопасную ставку и не разрешил суррогаты в моем белом списке.

Комментарии в решении Юджина вводят в заблуждение, проблема в том, что символы, которые мы исключаем, недействительны в XML ... они являются совершенно допустимыми кодовыми точками Unicode. Мы не удаляем символы, отличные от UTF-8. Мы удаляем символы utf-8, которые могут не отображаться в правильно сформированных XML-документах.

public static string XmlCharacterWhitelist( string in_string ) {
    if ( in_string == null ) return null;

    StringBuilder sbOutput = new StringBuilder();
    char ch;

    for( int i = 0; i < in_string.Length; i++ ) {
        ch = in_string[i];
        if ( ( ch >= 0x0020 && ch <= 0xD7FF ) || 
            ( ch >= 0xE000 && ch <= 0xFFFD ) ||
            ch == 0x0009 ||
            ch == 0x000A || 
            ch == 0x000D ) {
            sbOutput.Append( ch );
        }
    }
    return sbOutput.ToString();
}

он добавит &, и это заставит doc = XDocument.Load(@strXMLPath); выдать исключение

CODError 18.02.2014 13:07

привет, как вы думаете, XmlConvert.IsXmlChar () будет более точным? Ответ Евгения изменился с момента вашего последнего комментария. Благодарность

DaFi4 07.04.2017 12:53

private static String removeNonUtf8CompliantCharacters( final String inString ) {
    if (null == inString ) return null;
    byte[] byteArr = inString.getBytes();
    for ( int i=0; i < byteArr.length; i++ ) {
        byte ch= byteArr[i]; 
        // remove any characters outside the valid UTF-8 range as well as all control characters
        // except tabs and new lines
        if ( !( (ch > 31 && ch < 253 ) || ch == '\t' || ch == '\n' || ch == '\r') ) {
            byteArr[i]=' ';
        }
    }
    return new String( byteArr );
}

-1 Этот ответ вводит в заблуждение и неверен, потому что он удаляет символы, действительные как в Unicode, так и в XML.

Daniel Cassidy 02.09.2011 19:52

Попробуйте это для PHP!

$goodUTF8 = iconv("utf-8", "utf-8//IGNORE", $badUTF8);

Вышеупомянутые решения, похоже, предназначены для удаления недопустимых символов перед преобразованием в XML.

Используйте этот код, чтобы удалить недопустимые символы XML из строки XML. например. & x1A;

    public static string CleanInvalidXmlChars( string Xml, 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( Xml ) )
            Xml = regex.Replace( Xml, String.Empty );
        return Xml;
    }

http://balajiramesh.wordpress.com/2008/05/30/strip-illegal-xml-characters-based-on-w3c-standard/

-1 Этот ответ не отвечает на заданный вопрос и в любом случае неверен и вводит в заблуждение, потому что он удаляет только недопустимые ссылки на символы XML, но не недопустимые символы XML.

Daniel Cassidy 02.09.2011 19:53

Вы можете передавать символы, отличные от UTF, с помощью следующего:

string sFinalString  = "";
string hex = "";
foreach (char ch in UTFCHAR)
{
    int tmp = ch;
   if ((ch < 0x00FD && ch > 0x001F) || ch == '\t' || ch == '\n' || ch == '\r')
    {
    sFinalString  += ch;
    }
    else
    {  
      sFinalString  += "&#" + tmp+";";
    }
}

-1 Этот ответ неверен, потому что он генерирует недопустимые ссылки на символьные сущности XML (например, &#1; не является допустимой ссылкой на символьные сущности XML). Кроме того, он вводит в заблуждение, поскольку удаляет символы, действительные как в Юникоде, так и в XML.

Daniel Cassidy 02.09.2011 19:50

да, это правда, но приведенное выше решение предназначено для того, если вы хотите передать недопустимый xml в файл xml, чем он будет работать, или вы не можете передать недопустимый символ xml в документе xml

Murari Kumar 06.01.2012 17:29

Вы не можете передавать недопустимые символы XML в документ XML, что бы вы ни делали. Например, символ U+0001 START OF HEADING не разрешен в правильно сформированном XML-документе, и даже если вы попытаетесь экранировать его как &#1;, это все равно не разрешено в правильно сформированном XML-документе.

Daniel Cassidy 10.01.2012 18:38

Модернизируя ответ dnewcombe's, вы могли бы использовать немного более простой подход

public static string RemoveInvalidXmlChars(string input)
{
    var isValid = new Predicate<char>(value =>
        (value >= 0x0020 && value <= 0xD7FF) ||
        (value >= 0xE000 && value <= 0xFFFD) ||
        value == 0x0009 ||
        value == 0x000A ||
        value == 0x000D);

    return new string(Array.FindAll(input.ToCharArray(), isValid));
}

или с Linq

public static string RemoveInvalidXmlChars(string input)
{
    return new string(input.Where(value =>
        (value >= 0x0020 && value <= 0xD7FF) ||
        (value >= 0xE000 && value <= 0xFFFD) ||
        value == 0x0009 ||
        value == 0x000A ||
        value == 0x000D).ToArray());
}

Мне было бы интересно узнать, как сравнивается производительность этих методов и как все они сравниваются с подходом черного списка с использованием Buffer.BlockCopy.

У меня возникла проблема с тем, что метод Linq выдает исключение System.OutOfMemoryException, когда строка XML в больших файлах XML.

Brad J 25.02.2015 19:11

@BradJ предположительно, в этих случаях переданная строка очень длинная?

Jodrell 25.02.2015 19:14

@BradJ, в конечном счете, лучше было бы какое-то преобразование потока, вы могли бы передать его непосредственно в XmlReader.Create, вместо того, чтобы загружать весь файл в строку в памяти.

Jodrell 25.02.2015 19:41

просто провел тест скорости по сравнению с ответом dnewcombe, и оба ваших решения примерно в 3-4 раза быстрее, причем версия Linq лишь немного медленнее, чем ваша версия без linq. Я не ожидал такой разницы. использовали длинные строки и 100k итераций с секундомером для определения времени.

Seer 14.05.2015 06:49

@Seer Я использую потоки символов длиной ~ 60 тыс., И это решение работает немного медленнее, чем метод StringBuilder, не уверен, что я сделал по-другому.

adotout 08.07.2016 18:36

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

Подход на основе регулярных выражений

public static string StripInvalidXmlCharacters(string str)
{
    var invalidXmlCharactersRegex = new Regex("[^\u0009\u000a\u000d\u0020-\ud7ff\ue000-\ufffd]|([\ud800-\udbff](?![\udc00-\udfff]))|((?<![\ud800-\udbff])[\udc00-\udfff])");
    return invalidXmlCharactersRegex.Replace(str, "");

}

Смотрите мой Сообщение блога для более подробной информации

Это примерно в 50 раз медленнее, чем решение dnewcome на моей машине.

adotout 08.07.2016 18:30

Вот ответ dnewcome в настраиваемом StreamReader. Он просто обертывает настоящий читатель потока и заменяет символы по мере их чтения.

Я реализовал только несколько методов, чтобы сэкономить время. Я использовал это в сочетании с XDocument.Load и файловым потоком, и был вызван только метод Read (char [] buffer, int index, int count), поэтому он работал следующим образом. Вам может потребоваться реализовать дополнительные методы, чтобы заставить это работать в вашем приложении. Я использовал этот подход, потому что он кажется более эффективным, чем другие ответы. Я также реализовал только один из конструкторов, вы, очевидно, могли бы реализовать любой из конструкторов StreamReader, который вам нужен, поскольку это просто проход.

Я решил заменить символы, а не удалять их, потому что это значительно упрощает решение. Таким образом, длина текста остается неизменной, поэтому нет необходимости отслеживать отдельный индекс.

public class InvalidXmlCharacterReplacingStreamReader : TextReader
{
    private StreamReader implementingStreamReader;
    private char replacementCharacter;

    public InvalidXmlCharacterReplacingStreamReader(Stream stream, char replacementCharacter)
    {
        implementingStreamReader = new StreamReader(stream);
        this.replacementCharacter = replacementCharacter;
    }

    public override void Close()
    {
        implementingStreamReader.Close();
    }

    public override ObjRef CreateObjRef(Type requestedType)
    {
        return implementingStreamReader.CreateObjRef(requestedType);
    }

    public void Dispose()
    {
        implementingStreamReader.Dispose();
    }

    public override bool Equals(object obj)
    {
        return implementingStreamReader.Equals(obj);
    }

    public override int GetHashCode()
    {
        return implementingStreamReader.GetHashCode();
    }

    public override object InitializeLifetimeService()
    {
        return implementingStreamReader.InitializeLifetimeService();
    }

    public override int Peek()
    {
        int ch = implementingStreamReader.Peek();
        if (ch != -1)
        {
            if (
                (ch < 0x0020 || ch > 0xD7FF) &&
                (ch < 0xE000 || ch > 0xFFFD) &&
                ch != 0x0009 &&
                ch != 0x000A &&
                ch != 0x000D
                )
            {
                return replacementCharacter;
            }
        }
        return ch;
    }

    public override int Read()
    {
        int ch = implementingStreamReader.Read();
        if (ch != -1)
        {
            if (
                (ch < 0x0020 || ch > 0xD7FF) &&
                (ch < 0xE000 || ch > 0xFFFD) &&
                ch != 0x0009 &&
                ch != 0x000A &&
                ch != 0x000D
                )
            {
                return replacementCharacter;
            }
        }
        return ch;
    }

    public override int Read(char[] buffer, int index, int count)
    {
        int readCount = implementingStreamReader.Read(buffer, index, count);
        for (int i = index; i < readCount+index; i++)
        {
            char ch = buffer[i];
            if (
                (ch < 0x0020 || ch > 0xD7FF) &&
                (ch < 0xE000 || ch > 0xFFFD) &&
                ch != 0x0009 &&
                ch != 0x000A &&
                ch != 0x000D
                )
            {
                buffer[i] = replacementCharacter;
            }
        }
        return readCount;
    }

    public override Task<int> ReadAsync(char[] buffer, int index, int count)
    {
        throw new NotImplementedException();
    }

    public override int ReadBlock(char[] buffer, int index, int count)
    {
        throw new NotImplementedException();
    }

    public override Task<int> ReadBlockAsync(char[] buffer, int index, int count)
    {
        throw new NotImplementedException();
    }

    public override string ReadLine()
    {
        throw new NotImplementedException();
    }

    public override Task<string> ReadLineAsync()
    {
        throw new NotImplementedException();
    }

    public override string ReadToEnd()
    {
        throw new NotImplementedException();
    }

    public override Task<string> ReadToEndAsync()
    {
        throw new NotImplementedException();
    }

    public override string ToString()
    {
        return implementingStreamReader.ToString();
    }
}

В конечном счете, это правильная идея, но ваша реализация может быть DRYer.

Jodrell 25.02.2015 19:42

@Jodrell: Добавлена ​​СУХАЯ версия здесь.

Neolisk 20.05.2015 16:37

@Neolisk: Спасибо! Я, наверное, должен был очистить это, прежде чем публиковать :)

Ryan Adams 29.01.2016 01:38

DRY реализация решения этот ответ (с использованием другого конструктора - не стесняйтесь использовать тот, который вам нужен в своем приложении):

public class InvalidXmlCharacterReplacingStreamReader : StreamReader
{
    private readonly char _replacementCharacter;

    public InvalidXmlCharacterReplacingStreamReader(string fileName, char replacementCharacter) : base(fileName)
    {
        this._replacementCharacter = replacementCharacter;
    }

    public override int Peek()
    {
        int ch = base.Peek();
        if (ch != -1 && IsInvalidChar(ch))
        {
            return this._replacementCharacter;
        }
        return ch;
    }

    public override int Read()
    {
        int ch = base.Read();
        if (ch != -1 && IsInvalidChar(ch))
        {
            return this._replacementCharacter;
        }
        return ch;
    }

    public override int Read(char[] buffer, int index, int count)
    {
        int readCount = base.Read(buffer, index, count);
        for (int i = index; i < readCount + index; i++)
        {
            char ch = buffer[i];
            if (IsInvalidChar(ch))
            {
                buffer[i] = this._replacementCharacter;
            }
        }
        return readCount;
    }

    private static bool IsInvalidChar(int ch)
    {
        return (ch < 0x0020 || ch > 0xD7FF) &&
               (ch < 0xE000 || ch > 0xFFFD) &&
                ch != 0x0009 &&
                ch != 0x000A &&
                ch != 0x000D;
    }
}

может быть, лучше использовать XmlConvert.IsXmlChar () для проверки диапазона ch? Как вы думаете?

DaFi4 07.04.2017 12:51

@montewhizdoh: IsXmlChar является новым в .NET 4. Если это доступно вам, не стесняйтесь использовать. Это решение .NET 2.0+.

Neolisk 07.04.2017 14:29

Тот же подход, который я реализовал для себя, но унаследовал от Stream, что было не такой уж хорошей идеей, потому что Stream.Read () работал с массивом байтов, а не с символами, и было не так элегантно проверять символы. Ваше решение, унаследованное от StreamReader, лучше, спасибо!

Mar 07.09.2017 09:36

+1 Потому что это позволяет читать ДЕЙСТВИТЕЛЬНО большие файлы XML (успешно протестировано с файлами размером 100 МБ). Решения, которые загружали все в строку перед фильтрацией плохих символов, завершались ошибками с исключениями OutOfMemory.

Brad Oestreicher 03.11.2017 00:11

Используйте эту функцию для удаления недопустимых символов xml.

public static string CleanInvalidXmlChars(string text)   
{   
       string re = @"[^\x09\x0A\x0D\x20-\xD7FF\xE000-\xFFFD\x10000-x10FFFF]";   
       return Regex.Replace(text, re, "");   
} 

Измененный ответ или оригинальный ответ Неолиск выше.
Изменения: передан символ \ 0, производится удаление, а не замена. также использовался метод XmlConvert.IsXmlChar (char)

    /// <summary>
    /// Replaces invalid Xml characters from input file, NOTE: if replacement character is \0, then invalid Xml character is removed, instead of 1-for-1 replacement
    /// </summary>
    public class InvalidXmlCharacterReplacingStreamReader : StreamReader
    {
        private readonly char _replacementCharacter;

        public InvalidXmlCharacterReplacingStreamReader(string fileName, char replacementCharacter)
            : base(fileName)
        {
            _replacementCharacter = replacementCharacter;
        }

        public override int Peek()
        {
            int ch = base.Peek();
            if (ch != -1 && IsInvalidChar(ch))
            {
                if ('\0' == _replacementCharacter)
                    return Peek(); // peek at the next one

                return _replacementCharacter;
            }
            return ch;
        }

        public override int Read()
        {
            int ch = base.Read();
            if (ch != -1 && IsInvalidChar(ch))
            {
                if ('\0' == _replacementCharacter)
                    return Read(); // read next one

                return _replacementCharacter;
            }
            return ch;
        }

        public override int Read(char[] buffer, int index, int count)
        {
            int readCount= 0, ch;

            for (int i = 0; i < count && (ch = Read()) != -1; i++)
            {
                readCount++;
                buffer[index + i] = (char)ch;
            }

            return readCount;
        }


        private static bool IsInvalidChar(int ch)
        {
            return !XmlConvert.IsXmlChar((char)ch);
        }
    }

Я создал немного обновленная версия из @ Ответ Неолиска, который поддерживает функции *Async и использует функцию .Net 4.0 XmlConvert.IsXmlChar.

public class InvalidXmlCharacterReplacingStreamReader : StreamReader
{
    private readonly char _replacementCharacter;

    public InvalidXmlCharacterReplacingStreamReader(string fileName, char replacementCharacter) : base(fileName)
    {
        _replacementCharacter = replacementCharacter;
    }

    public InvalidXmlCharacterReplacingStreamReader(Stream stream, char replacementCharacter) : base(stream)
    {
        _replacementCharacter = replacementCharacter;
    }

    public override int Peek()
    {
        var ch = base.Peek();
        if (ch != -1 && IsInvalidChar(ch))
        {
            return _replacementCharacter;
        }
        return ch;
    }

    public override int Read()
    {
        var ch = base.Read();
        if (ch != -1 && IsInvalidChar(ch))
        {
            return _replacementCharacter;
        }
        return ch;
    }

    public override int Read(char[] buffer, int index, int count)
    {
        var readCount = base.Read(buffer, index, count);
        ReplaceInBuffer(buffer, index, readCount);
        return readCount;
    }

    public override async Task<int> ReadAsync(char[] buffer, int index, int count)
    {
        var readCount = await base.ReadAsync(buffer, index, count).ConfigureAwait(false);
        ReplaceInBuffer(buffer, index, readCount);
        return readCount;
    }

    private void ReplaceInBuffer(char[] buffer, int index, int readCount)
    {
        for (var i = index; i < readCount + index; i++)
        {
            var ch = buffer[i];
            if (IsInvalidChar(ch))
            {
                buffer[i] = _replacementCharacter;
            }
        }
    }

    private static bool IsInvalidChar(int ch)
    {
        return IsInvalidChar((char)ch);
    }

    private static bool IsInvalidChar(char ch)
    {
        return !XmlConvert.IsXmlChar(ch);
    }
}

Другие вопросы по теме