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("&", "&") 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:
- remove or replace invalid XML characters
- 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.
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.
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.
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 &.
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.IsXmlCharto remove or replace illegal code points. - Use
XmlWriterfor 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.

