Skip to content
Buy me a coffee
String Escaper & Utilities

XML Escape / Unescape

Escapes or unescapes an XML string, replacing the five reserved characters with their corresponding XML entities.

XML only defines five predefined entities (& < > " '), so there are no options: every reserved character is replaced and every other character is kept as is. Unescaping also decodes numeric references (é, é).

Ctrl + Enter

XML escaping explained

Why escape XML?

An XML parser treats < as the start of a tag and & as the start of an entity reference. If those characters appear literally inside element content or attribute values, the document is no longer well-formed and every conforming parser must reject it, there is no "lenient mode" in XML. Escaping replaces the offending characters with entity references so the parser reads them as plain text.

The five predefined entities

CharacterEntityMust be escaped in…
' (apostrophe)&apos;Attribute values delimited by single quotes
" (double quote)&quot;Attribute values delimited by double quotes
& (ampersand)&amp;Everywhere (text and attributes)
< (less than)&lt;Everywhere (text and attributes)
> (greater than)&gt;Only required in the sequence ]]>, but escaping it always is the safe habit

Unlike HTML, XML has no named entities for accented letters or symbols: &eacute; is not valid in an XML document unless a DTD declares it. Non-ASCII characters are written literally (the document is usually UTF-8) or with numeric character references such as &#233; (decimal) or &#xE9; (hexadecimal).

Before / after

InputEscaped output
<b>Tom & Jerry</b>&lt;b&gt;Tom &amp; Jerry&lt;/b&gt;
a < b && c > da &lt; b &amp;&amp; c &gt; d
He said "it's fine"He said &quot;it&apos;s fine&quot;
Café — 10 €Café — 10 € (unchanged)

CDATA sections

When a text node contains a lot of markup-like characters (an embedded HTML snippet, a script, a regular expression), wrapping it in a CDATA section is often more readable than escaping every character: <script><![CDATA[ if (a < b && c > d) … ]]></script>. The only sequence forbidden inside CDATA is ]]>, which is usually split as ]]]]><![CDATA[>.

In code

// Java (Apache Commons Text)
StringEscapeUtils.escapeXml11(s);

// C#
System.Security.SecurityElement.Escape(s);

// PHP
htmlspecialchars($s, ENT_XML1 | ENT_QUOTES, 'UTF-8');

// Python
from xml.sax.saxutils import escape; escape(s, {'"': '&quot;', "'": '&apos;'})