<p>Is there any easy/general way to clean an XML based data source prior to using it in an XmlReader so that I can gracefully consume XML data that is non-conformant to the hexadecimal character restrictions placed on XML?</p>

<p>Note: </p>

<ul>
<li>The solution needs to handle XML
data sources that use character
encodings other than UTF-8, e.g. by
specifying the character encoding at
the XML document declaration. Not
mangling the character encoding of
the source while stripping invalid
hexadecimal characters has been a
major sticking point.</li>
<li>The removal of invalid hexadecimal characters should only remove hexadecimal encoded values, as you can often find href values in data that happens to contains a string that would be a string match for a hexadecimal character.</li>
</ul>

<p><em>Background:</em></p>

<p>I need to consume an XML-based data source that conforms to a specific format (think Atom or RSS feeds), but want to be able to consume data sources that have been published which contain invalid hexadecimal characters per the XML specification.</p>

<p>In .NET if you have a Stream that represents the XML data source, and then attempt to parse it using an XmlReader and/or XPathDocument, an exception is raised due to the inclusion of invalid hexadecimal characters in the XML data. My current attempt to resolve this issue is to parse the Stream as a string and use a regular expression to remove and/or replace the invalid hexadecimal characters, but I am looking for a more performant solution.</p>

[{'answer_id': 20777, 'author': 'Eugene Katz', 'author_id': 1533, 'author_profile': 'https://Stackoverflow.com/users/1533', 'pm_score': 7, 'selected': True, 'text': '<p>It <strong>may not be perfect</strong> (emphasis added since people missing this disclaimer), but what I\'ve done in that case is below. You can adjust to use with a stream.</p>\n\n<pre><code>/// &lt;summary&gt;\n/// Removes control characters and other non-UTF-8 characters\n/// &lt;/summary&gt;\n/// &lt;param name="inString"&gt;The string to process&lt;/param&gt;\n/// &lt;returns&gt;A string with no control characters or entities above 0x00FD&lt;/returns&gt;\npublic static string RemoveTroublesomeCharacters(string inString)\n{\n    if (inString == null) return null;\n\n    StringBuilder newString = new StringBuilder();\n    char ch;\n\n    for (int i = 0; i &lt; inString.Length; i++)\n    {\n\n        ch = inString[i];\n        // remove any characters outside the valid UTF-8 range as well as all control characters\n        // except tabs and new lines\n        //if ((ch &lt; 0x00FD &amp;&amp; ch &gt; 0x001F) || ch == \'\\t\' || ch == \'\\n\' || ch == \'\\r\')\n        //if using .NET version prior to 4, use above logic\n        if (XmlConvert.IsXmlChar(ch)) //this method is new in .NET 4\n        {\n            newString.Append(ch);\n        }\n    }\n    return newString.ToString();\n\n}\n</code></pre>\n'}, {'answer_id': 641632, 'author': 'dnewcome', 'author_id': 35311, 'author_profile': 'https://Stackoverflow.com/users/35311', 'pm_score': 6, 'selected': False, 'text': "<p>I like Eugene's whitelist concept. I needed to do a similar thing as the original poster, but I needed to support all Unicode characters, not just up to 0x00FD.  The XML spec is:</p>\n\n<p>Char = #x9 | #xA | #xD | [#x20-#xD7FF] | [#xE000-#xFFFD] | [#x10000-#x10FFFF]</p>\n\n<p>In .NET, the internal representation of Unicode characters is only 16 bits, so we can't `allow' 0x10000-0x10FFFF explicitly.  The XML spec explicitly <em>disallows</em> the surrogate code points starting at 0xD800 from appearing. However it is possible that if we allowed these surrogate code points in our whitelist, utf-8 encoding our string might produce valid XML in the end as long as proper utf-8 encoding was produced from the surrogate pairs of utf-16 characters in the .NET string.  I haven't explored this though, so I went with the safer bet and didn't allow the surrogates in my whitelist.</p>\n\n<p>The comments in Eugene's solution are misleading though, the problem is that the characters we are excluding are not valid in <em>XML</em> ... they are perfectly valid Unicode code points.  We are not removing `non-utf-8 characters'.  We are removing utf-8 characters that may not appear in well-formed XML documents.</p>\n\n<pre><code>public static string XmlCharacterWhitelist( string in_string ) {\n    if( in_string == null ) return null;\n\n    StringBuilder sbOutput = new StringBuilder();\n    char ch;\n\n    for( int i = 0; i &lt; in_string.Length; i++ ) {\n        ch = in_string[i];\n        if( ( ch &gt;= 0x0020 &amp;&amp; ch &lt;= 0xD7FF ) || \n            ( ch &gt;= 0xE000 &amp;&amp; ch &lt;= 0xFFFD ) ||\n            ch == 0x0009 ||\n            ch == 0x000A || \n            ch == 0x000D ) {\n            sbOutput.Append( ch );\n        }\n    }\n    return sbOutput.ToString();\n}\n</code></pre>\n"}, {'answer_id': 2293111, 'author': 'savio', 'author_id': 276570, 'author_profile': 'https://Stackoverflow.com/users/276570', 'pm_score': -1, 'selected': False, 'text': "<pre><code>private static String removeNonUtf8CompliantCharacters( final String inString ) {\n    if (null == inString ) return null;\n    byte[] byteArr = inString.getBytes();\n    for ( int i=0; i &lt; byteArr.length; i++ ) {\n        byte ch= byteArr[i]; \n        // remove any characters outside the valid UTF-8 range as well as all control characters\n        // except tabs and new lines\n        if ( !( (ch &gt; 31 &amp;&amp; ch &lt; 253 ) || ch == '\\t' || ch == '\\n' || ch == '\\r') ) {\n            byteArr[i]=' ';\n        }\n    }\n    return new String( byteArr );\n}\n</code></pre>\n"}, {'answer_id': 3503958, 'author': 'Kesavan', 'author_id': 422998, 'author_profile': 'https://Stackoverflow.com/users/422998', 'pm_score': -1, 'selected': False, 'text': '<p>Try this for PHP!</p>\n\n<pre><code>$goodUTF8 = iconv("utf-8", "utf-8//IGNORE", $badUTF8);\n</code></pre>\n'}, {'answer_id': 5239529, 'author': 'Nathan G', 'author_id': 423508, 'author_profile': 'https://Stackoverflow.com/users/423508', 'pm_score': 2, 'selected': False, 'text': '<p>The above solutions seem to be for removing invalid characters prior to converting to XML.</p>\n\n<p>Use this code to remove invalid XML characters from an XML string. eg. &x1A;</p>\n\n<pre><code>    public static string CleanInvalidXmlChars( string Xml, string XMLVersion )\n    {\n        string pattern = String.Empty;\n        switch( XMLVersion )\n        {\n            case "1.0":\n                pattern = @"&amp;#x((10?|[2-F])FFF[EF]|FDD[0-9A-F]|7F|8[0-46-9A-F]9[0-9A-F]);";\n                break;\n            case "1.1":\n                pattern = @"&amp;#x((10?|[2-F])FFF[EF]|FDD[0-9A-F]|[19][0-9A-F]|7F|8[0-46-9A-F]|0?[1-8BCEF]);";\n                break;\n            default:\n                throw new Exception( "Error: Invalid XML Version!" );\n        }\n\n        Regex regex = new Regex( pattern, RegexOptions.IgnoreCase );\n        if( regex.IsMatch( Xml ) )\n            Xml = regex.Replace( Xml, String.Empty );\n        return Xml;\n    }\n</code></pre>\n\n<p><a href="http://balajiramesh.wordpress.com/2008/05/30/strip-illegal-xml-characters-based-on-w3c-standard/" rel="nofollow">http://balajiramesh.wordpress.com/2008/05/30/strip-illegal-xml-characters-based-on-w3c-standard/</a></p>\n'}, {'answer_id': 5936162, 'author': 'Murari Kumar', 'author_id': 430608, 'author_profile': 'https://Stackoverflow.com/users/430608', 'pm_score': -1, 'selected': False, 'text': '<p>You can pass non-UTF characters with the following:</p>\n\n<pre><code>string sFinalString  = "";\nstring hex = "";\nforeach (char ch in UTFCHAR)\n{\n    int tmp = ch;\n   if ((ch &lt; 0x00FD &amp;&amp; ch &gt; 0x001F) || ch == \'\\t\' || ch == \'\\n\' || ch == \'\\r\')\n    {\n    sFinalString  += ch;\n    }\n    else\n    {  \n      sFinalString  += "&amp;#" + tmp+";";\n    }\n}\n</code></pre>\n'}, {'answer_id': 10244306, 'author': 'Jodrell', 'author_id': 659190, 'author_profile': 'https://Stackoverflow.com/users/659190', 'pm_score': 3, 'selected': False, 'text': '<p>Modernising <a href="https://stackoverflow.com/a/641632/659190">dnewcombe\'s</a> answer, you could take a slightly simpler approach</p>\n\n<pre><code>public static string RemoveInvalidXmlChars(string input)\n{\n    var isValid = new Predicate&lt;char&gt;(value =&gt;\n        (value &gt;= 0x0020 &amp;&amp; value &lt;= 0xD7FF) ||\n        (value &gt;= 0xE000 &amp;&amp; value &lt;= 0xFFFD) ||\n        value == 0x0009 ||\n        value == 0x000A ||\n        value == 0x000D);\n\n    return new string(Array.FindAll(input.ToCharArray(), isValid));\n}\n</code></pre>\n\n<p>or, with Linq</p>\n\n<pre><code>public static string RemoveInvalidXmlChars(string input)\n{\n    return new string(input.Where(value =&gt;\n        (value &gt;= 0x0020 &amp;&amp; value &lt;= 0xD7FF) ||\n        (value &gt;= 0xE000 &amp;&amp; value &lt;= 0xFFFD) ||\n        value == 0x0009 ||\n        value == 0x000A ||\n        value == 0x000D).ToArray());\n}\n</code></pre>\n\n<p>I\'d be interested to know how the performance of these methods compares and how they all compare to a black list approach using <code>Buffer.BlockCopy</code>.</p>\n'}, {'answer_id': 14912930, 'author': 'Igor Kustov', 'author_id': 1244353, 'author_profile': 'https://Stackoverflow.com/users/1244353', 'pm_score': 5, 'selected': False, 'text': '<p>As the way to remove invalid XML characters I suggest you to use <a href="http://msdn.microsoft.com/en-us/library/system.xml.xmlconvert.isxmlchar%28v=vs.100%29.aspx" rel="noreferrer">XmlConvert.IsXmlChar</a> method. It was added since .NET Framework 4 and is presented in Silverlight too. Here is the small sample:</p>\n\n<pre><code>void Main() {\n    string content = "\\v\\f\\0";\n    Console.WriteLine(IsValidXmlString(content)); // False\n\n    content = RemoveInvalidXmlChars(content);\n    Console.WriteLine(IsValidXmlString(content)); // True\n}\n\nstatic string RemoveInvalidXmlChars(string text) {\n    char[] validXmlChars = text.Where(ch =&gt; XmlConvert.IsXmlChar(ch)).ToArray();\n    return new string(validXmlChars);\n}\n\nstatic bool IsValidXmlString(string text) {\n    try {\n        XmlConvert.VerifyXmlChars(text);\n        return true;\n    } catch {\n        return false;\n    }\n}\n</code></pre>\n'}, {'answer_id': 24225671, 'author': 'mnaoumov', 'author_id': 1074455, 'author_profile': 'https://Stackoverflow.com/users/1074455', 'pm_score': 2, 'selected': False, 'text': '<p>Regex based approach</p>\n\n<pre><code>public static string StripInvalidXmlCharacters(string str)\n{\n    var invalidXmlCharactersRegex = new Regex("[^\\u0009\\u000a\\u000d\\u0020-\\ud7ff\\ue000-\\ufffd]|([\\ud800-\\udbff](?![\\udc00-\\udfff]))|((?&lt;![\\ud800-\\udbff])[\\udc00-\\udfff])");\n    return invalidXmlCharactersRegex.Replace(str, "");\n</code></pre>\n\n<p>}</p>\n\n<p>See my <a href="http://mnaoumov.wordpress.com/2014/06/15/escaping-invalid-xml-unicode-characters/" rel="nofollow">blogpost</a> for more details</p>\n'}, {'answer_id': 27239510, 'author': 'Ryan Adams', 'author_id': 4313632, 'author_profile': 'https://Stackoverflow.com/users/4313632', 'pm_score': 3, 'selected': False, 'text': '<p>Here is <a href="https://stackoverflow.com/a/641632/4313632">dnewcome</a>\'s answer in a custom StreamReader. It simply wraps a real stream reader and replaces the characters as they are read. </p>\n\n<p>I only implemented a few methods to save myself time. I used this in conjunction with XDocument.Load and a file stream and only the Read(char[] buffer, int index, int count) method was called, so it worked like this. You may need to implement additional methods to get this to work for your application. I used this approach because it seems more efficient than the other answers. I also only implemented one of the constructors, you could obviously implement any of the StreamReader constructors that you need, since it is just a pass through. </p>\n\n<p>I chose to replace the characters rather than removing them because it greatly simplifies the solution. In this way the length of the text stays the same, so there is no need to keep track of a separate index.</p>\n\n<pre><code>public class InvalidXmlCharacterReplacingStreamReader : TextReader\n{\n    private StreamReader implementingStreamReader;\n    private char replacementCharacter;\n\n    public InvalidXmlCharacterReplacingStreamReader(Stream stream, char replacementCharacter)\n    {\n        implementingStreamReader = new StreamReader(stream);\n        this.replacementCharacter = replacementCharacter;\n    }\n\n    public override void Close()\n    {\n        implementingStreamReader.Close();\n    }\n\n    public override ObjRef CreateObjRef(Type requestedType)\n    {\n        return implementingStreamReader.CreateObjRef(requestedType);\n    }\n\n    public void Dispose()\n    {\n        implementingStreamReader.Dispose();\n    }\n\n    public override bool Equals(object obj)\n    {\n        return implementingStreamReader.Equals(obj);\n    }\n\n    public override int GetHashCode()\n    {\n        return implementingStreamReader.GetHashCode();\n    }\n\n    public override object InitializeLifetimeService()\n    {\n        return implementingStreamReader.InitializeLifetimeService();\n    }\n\n    public override int Peek()\n    {\n        int ch = implementingStreamReader.Peek();\n        if (ch != -1)\n        {\n            if (\n                (ch &lt; 0x0020 || ch &gt; 0xD7FF) &amp;&amp;\n                (ch &lt; 0xE000 || ch &gt; 0xFFFD) &amp;&amp;\n                ch != 0x0009 &amp;&amp;\n                ch != 0x000A &amp;&amp;\n                ch != 0x000D\n                )\n            {\n                return replacementCharacter;\n            }\n        }\n        return ch;\n    }\n\n    public override int Read()\n    {\n        int ch = implementingStreamReader.Read();\n        if (ch != -1)\n        {\n            if (\n                (ch &lt; 0x0020 || ch &gt; 0xD7FF) &amp;&amp;\n                (ch &lt; 0xE000 || ch &gt; 0xFFFD) &amp;&amp;\n                ch != 0x0009 &amp;&amp;\n                ch != 0x000A &amp;&amp;\n                ch != 0x000D\n                )\n            {\n                return replacementCharacter;\n            }\n        }\n        return ch;\n    }\n\n    public override int Read(char[] buffer, int index, int count)\n    {\n        int readCount = implementingStreamReader.Read(buffer, index, count);\n        for (int i = index; i &lt; readCount+index; i++)\n        {\n            char ch = buffer[i];\n            if (\n                (ch &lt; 0x0020 || ch &gt; 0xD7FF) &amp;&amp;\n                (ch &lt; 0xE000 || ch &gt; 0xFFFD) &amp;&amp;\n                ch != 0x0009 &amp;&amp;\n                ch != 0x000A &amp;&amp;\n                ch != 0x000D\n                )\n            {\n                buffer[i] = replacementCharacter;\n            }\n        }\n        return readCount;\n    }\n\n    public override Task&lt;int&gt; ReadAsync(char[] buffer, int index, int count)\n    {\n        throw new NotImplementedException();\n    }\n\n    public override int ReadBlock(char[] buffer, int index, int count)\n    {\n        throw new NotImplementedException();\n    }\n\n    public override Task&lt;int&gt; ReadBlockAsync(char[] buffer, int index, int count)\n    {\n        throw new NotImplementedException();\n    }\n\n    public override string ReadLine()\n    {\n        throw new NotImplementedException();\n    }\n\n    public override Task&lt;string&gt; ReadLineAsync()\n    {\n        throw new NotImplementedException();\n    }\n\n    public override string ReadToEnd()\n    {\n        throw new NotImplementedException();\n    }\n\n    public override Task&lt;string&gt; ReadToEndAsync()\n    {\n        throw new NotImplementedException();\n    }\n\n    public override string ToString()\n    {\n        return implementingStreamReader.ToString();\n    }\n}\n</code></pre>\n'}, {'answer_id': 30351313, 'author': 'Victor Zakharov', 'author_id': 897326, 'author_profile': 'https://Stackoverflow.com/users/897326', 'pm_score': 4, 'selected': False, 'text': '<p>DRY implementation of <a href="https://stackoverflow.com/a/27239510/897326">this answer</a>\'s solution (using a different constructor - feel free to use the one you need in your application):</p>\n\n<pre><code>public class InvalidXmlCharacterReplacingStreamReader : StreamReader\n{\n    private readonly char _replacementCharacter;\n\n    public InvalidXmlCharacterReplacingStreamReader(string fileName, char replacementCharacter) : base(fileName)\n    {\n        this._replacementCharacter = replacementCharacter;\n    }\n\n    public override int Peek()\n    {\n        int ch = base.Peek();\n        if (ch != -1 &amp;&amp; IsInvalidChar(ch))\n        {\n            return this._replacementCharacter;\n        }\n        return ch;\n    }\n\n    public override int Read()\n    {\n        int ch = base.Read();\n        if (ch != -1 &amp;&amp; IsInvalidChar(ch))\n        {\n            return this._replacementCharacter;\n        }\n        return ch;\n    }\n\n    public override int Read(char[] buffer, int index, int count)\n    {\n        int readCount = base.Read(buffer, index, count);\n        for (int i = index; i &lt; readCount + index; i++)\n        {\n            char ch = buffer[i];\n            if (IsInvalidChar(ch))\n            {\n                buffer[i] = this._replacementCharacter;\n            }\n        }\n        return readCount;\n    }\n\n    private static bool IsInvalidChar(int ch)\n    {\n        return (ch &lt; 0x0020 || ch &gt; 0xD7FF) &amp;&amp;\n               (ch &lt; 0xE000 || ch &gt; 0xFFFD) &amp;&amp;\n                ch != 0x0009 &amp;&amp;\n                ch != 0x000A &amp;&amp;\n                ch != 0x000D;\n    }\n}\n</code></pre>\n'}, {'answer_id': 40720009, 'author': 'Munavvar', 'author_id': 3261852, 'author_profile': 'https://Stackoverflow.com/users/3261852', 'pm_score': 0, 'selected': False, 'text': '<p>Use this function to remove invalid xml characters.</p>\n\n<pre><code>public static string CleanInvalidXmlChars(string text)   \n{   \n       string re = @"[^\\x09\\x0A\\x0D\\x20-\\xD7FF\\xE000-\\xFFFD\\x10000-x10FFFF]";   \n       return Regex.Replace(text, re, "");   \n} \n</code></pre>\n'}, {'answer_id': 44189911, 'author': 'BogdanRB', 'author_id': 1295946, 'author_profile': 'https://Stackoverflow.com/users/1295946', 'pm_score': 1, 'selected': False, 'text': '<p>Modified answer or original answer by <a href="https://stackoverflow.com/a/30351313/1295946">Neolisk above</a>.\n<br/>Changes: of \\0 character is passed, removal is done, rather than a replacement. also, made use of XmlConvert.IsXmlChar(char) method</p>\n\n<pre><code>    /// &lt;summary&gt;\n    /// 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\n    /// &lt;/summary&gt;\n    public class InvalidXmlCharacterReplacingStreamReader : StreamReader\n    {\n        private readonly char _replacementCharacter;\n\n        public InvalidXmlCharacterReplacingStreamReader(string fileName, char replacementCharacter)\n            : base(fileName)\n        {\n            _replacementCharacter = replacementCharacter;\n        }\n\n        public override int Peek()\n        {\n            int ch = base.Peek();\n            if (ch != -1 &amp;&amp; IsInvalidChar(ch))\n            {\n                if (\'\\0\' == _replacementCharacter)\n                    return Peek(); // peek at the next one\n\n                return _replacementCharacter;\n            }\n            return ch;\n        }\n\n        public override int Read()\n        {\n            int ch = base.Read();\n            if (ch != -1 &amp;&amp; IsInvalidChar(ch))\n            {\n                if (\'\\0\' == _replacementCharacter)\n                    return Read(); // read next one\n\n                return _replacementCharacter;\n            }\n            return ch;\n        }\n\n        public override int Read(char[] buffer, int index, int count)\n        {\n            int readCount= 0, ch;\n\n            for (int i = 0; i &lt; count &amp;&amp; (ch = Read()) != -1; i++)\n            {\n                readCount++;\n                buffer[index + i] = (char)ch;\n            }\n\n            return readCount;\n        }\n\n\n        private static bool IsInvalidChar(int ch)\n        {\n            return !XmlConvert.IsXmlChar((char)ch);\n        }\n    }\n</code></pre>\n'}, {'answer_id': 54390234, 'author': 'Georg Jung', 'author_id': 1200847, 'author_profile': 'https://Stackoverflow.com/users/1200847', 'pm_score': 2, 'selected': False, 'text': '<p>I created <a href="https://gist.github.com/georg-jung/6ab5b05ea0ea362c705362b098bc584b#file-invalidxmlcharacterreplacingstreamreader-cs" rel="nofollow noreferrer">a slightly updated version</a> of <a href="https://stackoverflow.com/a/30351313/1200847">@Neolisk\'s answer</a>, which supports the <code>*Async</code> functions and uses the .Net 4.0 <code>XmlConvert.IsXmlChar</code> function.</p>\n\n<pre><code>public class InvalidXmlCharacterReplacingStreamReader : StreamReader\n{\n    private readonly char _replacementCharacter;\n\n    public InvalidXmlCharacterReplacingStreamReader(string fileName, char replacementCharacter) : base(fileName)\n    {\n        _replacementCharacter = replacementCharacter;\n    }\n\n    public InvalidXmlCharacterReplacingStreamReader(Stream stream, char replacementCharacter) : base(stream)\n    {\n        _replacementCharacter = replacementCharacter;\n    }\n\n    public override int Peek()\n    {\n        var ch = base.Peek();\n        if (ch != -1 &amp;&amp; IsInvalidChar(ch))\n        {\n            return _replacementCharacter;\n        }\n        return ch;\n    }\n\n    public override int Read()\n    {\n        var ch = base.Read();\n        if (ch != -1 &amp;&amp; IsInvalidChar(ch))\n        {\n            return _replacementCharacter;\n        }\n        return ch;\n    }\n\n    public override int Read(char[] buffer, int index, int count)\n    {\n        var readCount = base.Read(buffer, index, count);\n        ReplaceInBuffer(buffer, index, readCount);\n        return readCount;\n    }\n\n    public override async Task&lt;int&gt; ReadAsync(char[] buffer, int index, int count)\n    {\n        var readCount = await base.ReadAsync(buffer, index, count).ConfigureAwait(false);\n        ReplaceInBuffer(buffer, index, readCount);\n        return readCount;\n    }\n\n    private void ReplaceInBuffer(char[] buffer, int index, int readCount)\n    {\n        for (var i = index; i &lt; readCount + index; i++)\n        {\n            var ch = buffer[i];\n            if (IsInvalidChar(ch))\n            {\n                buffer[i] = _replacementCharacter;\n            }\n        }\n    }\n\n    private static bool IsInvalidChar(int ch)\n    {\n        return IsInvalidChar((char)ch);\n    }\n\n    private static bool IsInvalidChar(char ch)\n    {\n        return !XmlConvert.IsXmlChar(ch);\n    }\n}\n</code></pre>\n'}]
['https://Stackoverflow.com/questions/20762', 'https://Stackoverflow.com', 'https://Stackoverflow.com/users/2029/']