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

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

Заметка:

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

Задний план:

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

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

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

///  /// Removes control characters and other non-UTF-8 characters ///  /// The string to process /// A string with no control characters or entities above 0x00FD 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(); } 

Мне нравится концепция белого списка Юджина. Мне нужно было сделать то же самое, что и оригинальный плакат, но мне нужно было поддерживать все символы 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(); } 

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

Модернизировав ответ dnewcombe , вы можете сделать несколько более простой подход

 public static string RemoveInvalidXmlChars(string input) { var isValid = new Predicate(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 .

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

Я только реализовал несколько методов, чтобы сэкономить время. Я использовал это в сочетании с XDocument.Load и streamом файлов, и был вызван только метод 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 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 ReadBlockAsync(char[] buffer, int index, int count) { throw new NotImplementedException(); } public override string ReadLine() { throw new NotImplementedException(); } public override Task ReadLineAsync() { throw new NotImplementedException(); } public override string ReadToEnd() { throw new NotImplementedException(); } public override Task ReadToEndAsync() { throw new NotImplementedException(); } public override string ToString() { return implementingStreamReader.ToString(); } } 

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

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

}

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

Вышеупомянутые решения, похоже, предназначены для удаления недопустимых символов до преобразования в 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/

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

  ///  /// 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 ///  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); } } 

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

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

Вы можете передавать символы без 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+";"; } } 

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

 $goodUTF8 = iconv("utf-8", "utf-8//IGNORE", $badUTF8); 
  • Разрешить анонимную проверку подлинности для одной папки в web.config?
  • Как остановить Chrome от пожелтения полей ввода моего сайта?
  • Проверьте, имеет ли браузер встроенную проверку HTML5?
  • Добавление базового HTTP-аутентификации в службу WCF REST
  • Как установить атрибут maxlength на h: inputTextarea
  • JSF не поддерживает проверку кросс-поля, есть ли обходной путь?
  • Как проверить правильность данной строки JSON в Java
  • Использовать проверку ASP.NET MVC с помощью jquery ajax?
  • Проверка адреса электронной почты в Android на EditText
  • Как я могу изменить или удалить сообщения об ошибках в форме HTML5 по умолчанию?
  • Использование DataAnnotations с платформой Entity Framework
  • Interesting Posts

    Android – ListView для загрузки большего количества предметов по достижении конца

    Удаленный доступ к SSH не работает, когда клиент OpenVPN включен в DD-WRT

    Использование свойств DateTime в Code-First Entity Framework и SQL Server

    mylib.so имеет текстовые перестановки. Это напрасно тратит память и представляет угрозу безопасности. Пожалуйста исправьте

    Как печатать двойной с двумя десятичными знаками в Android?

    Любой способ сообщить, какая версия Windows 7 сгорела на моем DVD?

    Почему генераторы не поддерживают map ()?

    Как запускать несколько команд DOS параллельно?

    Android – Использование пользовательского шрифта

    Подключитесь к базе heroku с помощью pgadmin

    Как я могу использовать Web.debug.config на встроенном сервере отладки визуальной студии?

    Самые полезные атрибуты

    Пользовательский серализатор Gson для одной переменной (из многих) в объекте с использованием TypeAdapter

    Gson – конвертировать из Json в типизированный ArrayList

    Как создать разделитель между вкладками Sandwich Ice Cream?

    Давайте будем гением компьютера.