C#
XML
Escape Characters
Invalid Characters
Programming

Escape invalid XML characters in C

Master System Design with Codemia

Enhance your system design skills with over 120 practice problems, detailed solutions, and hands-on exercises.

Introduction

Generating XML from arbitrary strings has two separate hazards: characters that are valid text but must be escaped, and code points that XML does not allow at all. Many broken implementations treat those as the same problem and try to solve both with a few string replacements. In C#, the reliable approach is to clean invalid characters first and then let an XML-aware writer handle the escaping step.

Escaping and Validation Are Different Jobs

Reserved markup characters such as &, <, >, and quotes are legal text, but they must be escaped when written into XML elements or attributes. Illegal control characters are different. XML parsers reject them even if you try to escape them.

That is why code like a sequence of Replace("&", "&amp;") calls is not enough. It can handle some markup characters and still produce an invalid document if the input contains disallowed Unicode values.

The safe sequence is:

  1. remove or replace invalid XML characters
  2. serialize with an XML writer instead of manual concatenation

Filter Invalid Characters With XmlConvert

The .NET XML APIs already know the XML character rules. XmlConvert.IsXmlChar is a straightforward way to keep only valid characters.

csharp
1using System.Linq;
2using System.Xml;
3
4public static class XmlSanitizer
5{
6    public static string RemoveInvalidXmlChars(string input)
7    {
8        if (string.IsNullOrEmpty(input))
9        {
10            return string.Empty;
11        }
12
13        return new string(input.Where(XmlConvert.IsXmlChar).ToArray());
14    }
15}

This removes disallowed code points before serialization. For many applications that is the simplest acceptable behavior, especially when the bad characters are control characters coming from copy-pasted data or corrupted input.

Replace Instead of Dropping When the Business Rule Requires It

Some systems cannot silently delete characters. In that case, replace invalid values with a visible marker so downstream consumers can tell that sanitization occurred.

csharp
1using System.Linq;
2using System.Xml;
3
4public static string ReplaceInvalidXmlChars(string input, char replacement = '?')
5{
6    if (string.IsNullOrEmpty(input))
7    {
8        return string.Empty;
9    }
10
11    return new string(
12        input.Select(ch => XmlConvert.IsXmlChar(ch) ? ch : replacement).ToArray()
13    );
14}

This is common in exports, support bundles, and audit logs where preserving string shape is more important than perfect fidelity.

Let XmlWriter Escape Reserved Characters

Once the string contains only legal XML characters, let XmlWriter escape it according to context. That avoids both under-escaping and double-escaping.

csharp
1using System.IO;
2using System.Xml;
3
4string raw = "A & B < ready";
5string cleaned = RemoveInvalidXmlChars(raw);
6
7var settings = new XmlWriterSettings { Indent = true };
8
9using var output = new StringWriter();
10using (var writer = XmlWriter.Create(output, settings))
11{
12    writer.WriteStartDocument();
13    writer.WriteStartElement("order");
14    writer.WriteElementString("note", cleaned);
15    writer.WriteEndElement();
16    writer.WriteEndDocument();
17}
18
19System.Console.WriteLine(output.ToString());

Notice that the code passes raw text to WriteElementString. The writer decides how to escape it correctly for element content. If you escape it yourself first and then send it to the writer, you risk double-escaping values such as &amp;.

Avoid Building XML With String Concatenation

String interpolation seems faster at first, but it is usually the source of subtle XML bugs. Element content and attribute content do not follow exactly the same escaping rules, and a manual builder rarely stays correct once requirements expand.

If XML is part of your application boundary, serialization should be treated as structured output, not as hand-built text formatting. Using the XML writer API makes that intent obvious and keeps the escaping rules centralized.

Test the Full Pipeline

Good tests should cover:

  • reserved XML characters
  • illegal control characters
  • already safe text
  • non-ASCII text
  • attribute and element content separately

The last point matters because teams often test element content and forget that attributes have their own escaping context. Once the string is cleaned and written through XmlWriter, both cases become much easier to trust.

Common Pitfalls

The biggest mistake is assuming reserved-character escaping also fixes illegal XML code points. Another is escaping the string manually and then handing it to XmlWriter, which can produce double-escaped output. Teams also get into trouble by sanitizing one path correctly while another path still builds XML with interpolation or concatenation.

Summary

  • Treat invalid-character cleanup and XML escaping as separate steps.
  • Use XmlConvert.IsXmlChar to remove or replace illegal code points.
  • Use XmlWriter for context-aware escaping of valid text.
  • Avoid manual XML string assembly for anything beyond trivial cases.
  • Test both attributes and element bodies with realistic input data.

Course illustration
Course illustration

All Rights Reserved.