Getting Started
XML Document Structure
XML documents start with an XML declaration. Elements must be properly nested and closed. Attributes provide additional metadata. xmlns declares XML namespaces to avoid naming conflicts.
<?xml version="1.0" encoding="UTF-8"?>
<!-- This is a comment -->
<bookstore xmlns="https://example.com/books">
<book id="b1" category="fiction">
<title lang="en">The Great Gatsby</title>
<author>F. Scott Fitzgerald</author>
<price currency="USD">12.99</price>
</book>
<book id="b2" category="programming">
<title lang="en">XML Guide</title>
<author>John Doe</author>
<price currency="USD">29.99</price>
</book>
</bookstore>XML Declaration
The XML declaration is the prolog's first line. 'version' is required (1.0 or 1.1). 'encoding' defaults to UTF-8. 'standalone' tells parsers whether external DTD declarations are needed.
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<!-- version is required; encoding and standalone are optional -->
<!-- encoding defaults to UTF-8 -->
<!-- standalone="yes" means no external markup declarations -->
<root>
<child>text</child>
</root>Comments & Processing Instructions
Comments use <!-- --> and cannot nest or contain '--' inside. Processing Instructions (PIs) like xml-stylesheet pass app-specific info to the parser. PIs use <?target data?>.
<?xml version="1.0"?>
<!-- a comment: ignored by the parser, cannot contain -- -->
<?xml-stylesheet type="text/xsl" href="style.xsl"?>
<root>
<!-- comments can span
multiple lines -->
<item>data</item>
</root>Well-formed XML
Well-formed means: one root element, proper nesting, all tags closed, attributes quoted, no duplicate attributes. A document MUST be well-formed to be parseable; validity (against a DTD/Schema) is optional.
<!-- WELL-FORMED: single root, properly nested, closed -->
<root>
<a>
<b>text</b>
</a>
</root>
<!-- NOT well-formed: two roots, overlapping tags -->
<!-- <a><b></a></b> -->
<!-- <x></x><y></y> (no single root) -->
<!-- All attributes must be quoted -->
<item id='1' type="x"/>XML Prolog & Whitespace
The prolog includes the XML declaration and optional DOCTYPE. xml:space='preserve' tells parsers to keep whitespace; 'default' allows normal handling. Whitespace between elements is generally insignificant.
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE root SYSTEM "root.dtd">
<root xml:space="preserve">
<item> spaced text </item>
<item xml:space="default"> trimmed </item>
</root>CDATA Overview
CDATA sections mark text that the parser should not interpret as markup. Inside CDATA, characters like <, >, and & need no escaping. CDATA cannot be nested and cannot contain the literal ']]>'.
<?xml version="1.0"?>
<root>
<code><![CDATA[
if (a < b && c > d) {
console.log("no escaping needed: < > & ");
}
]]></code>
</root>Elements & Attributes
Elements vs Attributes
Attributes suit metadata (ids, types, flags); elements suit data with structure or repeated values. An attribute appears once per element and cannot hold nested structure. There is no strict rule—consistency matters most.
<!-- Attributes: metadata/identifiers; Elements: data -->
<person id="p1">
<name>Alice</name>
<age>30</age>
</person>
<!-- vs. putting everything in attributes -->
<person id="p1" name="Alice" age="30"/>
<!-- Rule of thumb: use elements for data you display,
attributes for IDs, types, and metadata -->Empty Elements
An empty element has no content. The self-closing form <tag/> is shorthand for <tag></tag>. The space before '/>' is a style convention for readability and XHTML compatibility.
<!-- Three equivalent empty-element forms -->
<br></br>
<br/>
<br />
<!-- empty element with attributes -->
<img src="logo.png" alt="Logo" width="200" height="100"/>
<!-- self-closing with namespace -->
<xlink:link xmlns:xlink="http://www.w3.org/1999/xlink" href="#sec1"/>Nested Elements
Elements nest hierarchically and must close in reverse order—they cannot overlap. Nesting expresses structure. Deeply nested trees are valid but can hurt readability and parsing performance.
<library>
<section name="fiction">
<book>
<title>Book A</title>
<authors>
<author>Author 1</author>
<author>Author 2</author>
</authors>
</book>
</section>
</library>
<!-- WRONG: tags must not overlap -->
<!-- <a><b></a></b> -->Attribute Values & Quotes
Attribute values must be quoted with single or double quotes. Double quotes inside double-quoted values must be escaped as ". An attribute may appear only once per element—use child elements for repeated values.
<!-- Both single and double quotes are allowed -->
<item id="q1" name='quick'/>
<msg text="He said "hi""/>
<msg text='She said 'hi''/>
<!-- attribute values MUST be quoted -->
<!-- <item id=q1/> is NOT well-formed -->
<!-- an attribute can appear at most once per element -->
<point x="1" y="2" z="3"/>Default & Fixed Attributes
DTD attribute declarations support #REQUIRED (must appear), #IMPLIED (optional), #FIXED (constant value), and a literal default. A #FIXED attribute must always equal its declared value or the document is invalid.
<!-- In a DTD, attributes can have defaults -->
<!ATTLIST item
type CDATA "standard"
status CDATA #REQUIRED
version CDATA #FIXED "1.0"
note CDATA #IMPLIED>
<item status="active"/>
<!-- 'type' defaults to "standard", 'version' is fixed,
'note' is optional (#IMPLIED) -->Element Naming Rules
Element names must start with a letter or underscore and may contain letters, digits, hyphens, underscores, and dots. Names cannot start with 'xml' (any case). XML is case-sensitive, so <Tag> and <tag> differ.
<!-- Names: start with a letter or underscore,
continue with letters, digits, hyphens, underscores, dots -->
<my-element>ok</my-element>
<my.element>ok</my.element>
<my_element>ok</my_element>
<_private>ok</_private>
<x-1>ok</x-1>
<!-- NOT allowed: starting with a digit or 'xml', containing spaces -->
<!-- <2way/> -->
<!-- <my element/> -->
<!-- <XmlTag/> (names are case-sensitive; 'xml' prefix is reserved) -->Namespaces
Default Namespace
A default namespace (xmlns=URI) applies to the element where it is declared and all unprefixed descendants. Child elements inherit it unless overridden. Attributes never use the default namespace.
<?xml version="1.0"?>
<table xmlns="http://www.w3.org/1999/xhtml">
<tr>
<td>Cell content</td>
<td>More content</td>
</tr>
</table>
<!-- All elements without a prefix use the default namespace -->Namespace Prefix
A namespace prefix is declared with xmlns:prefix=URI and used as prefix:element. The prefix is just an alias—only the URI matters for identity. Prefixes are case-sensitive.
<?xml version="1.0"?>
<root xmlns:bk="https://example.com/books"
xmlns:au="https://example.com/authors">
<bk:book bk:id="b1">
<au:author au:name="Jane Doe"/>
<bk:title>XML Guide</bk:title>
</bk:book>
</root>Multiple Namespaces
A single document can mix many namespaces. Declare each prefix once (usually on the root) and reuse it. Declaring a namespace on an element applies to that element and its descendants.
<?xml version="1.0"?>
<soap:Envelope
xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<m:GetPrice xsi:type="xsd:string"
xmlns:m="https://example.com/pricing">
<m:Item>Apples</m:Item>
</m:GetPrice>
</soap:Body>
</soap:Envelope>Namespace Scope
Namespace declarations are scoped to the element they appear on and its descendants. A redeclaration inside a child overrides the parent's prefix mapping for that subtree. The original mapping is restored after the child closes.
<?xml version="1.0"?>
<root xmlns:a="http://a.example">
<a:item>A</a:item>
<child xmlns:a="http://b.example">
<!-- here 'a' is REBOUND to the b.example URI -->
<a:item>B</a:item>
</child>
<!-- outside child, 'a' is back to a.example -->
<a:item>A again</a:item>
</root>Common Namespaces
These URIs are well-known identifiers, not URLs that must be fetched. The xsi namespace provides schema-instance attributes (type, nil, schemaLocation). XSD, XSL, SVG, SOAP, Atom, and Dublin Core (dc) each have standard URIs.
<!-- Frequently used namespace URIs -->
xmlns:xsi = "http://www.w3.org/2001/XMLSchema-instance"
xmlns:xsd = "http://www.w3.org/2001/XMLSchema"
xmlns:xsl = "http://www.w3.org/1999/XSL/Transform"
xmlns:svg = "http://www.w3.org/2000/svg"
xmlns:html = "http://www.w3.org/1999/xhtml"
xmlns:soap = "http://schemas.xmlsoap.org/soap/envelope/"
xmlns:atom = "http://www.w3.org/2005/Atom"
xmlns:dc = "http://purl.org/dc/elements/1.1/"Target Namespace in XSD
A schema's targetNamespace is the namespace of the elements it defines. elementFormDefault='qualified' means locally declared elements are in the target namespace. The tns prefix is a convention for 'this namespace'.
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="https://example.com/orders"
xmlns:tns="https://example.com/orders"
elementFormDefault="qualified">
<xs:element name="order" type="tns:OrderType"/>
<xs:complexType name="OrderType">
<xs:sequence>
<xs:element name="item" type="xs:string"/>
</xs:sequence>
</xs:complexType>
</xs:schema>CDATA & Entities
Predefined Entities
XML predefines five entities: < (<), > (>), & (&), ' ('), " ("). & must ALWAYS be escaped (even in CDATA-free text); < must be escaped except as a tag start; quotes matter mainly in attributes.
<?xml version="1.0"?>
<root>
<lt>less than: <</lt>
<gt>greater than: ></gt>
<amp>ampersand: &</amp>
<apos>apostrophe: '</apos>
<quot>quote: "</quot>
<!-- < > & ' " are the 5 built-in entities -->
</root>Character References
Character references use a Unicode code point: © (decimal) or © (hex) for ©. They work in element text and attribute values and are not affected by encoding. They can represent any Unicode character.
<?xml version="1.0" encoding="UTF-8"?>
<root>
<decimal>© 2024 Company</decimal>
<hex>© 2024 Company</hex>
<euro>Price: €10</euro>
<emoji>Smile: 😀</emoji>
</root>
<!-- &#NNN; decimal code point -->
<!-- &#xHHH; hexadecimal code point -->CDATA Sections
CDATA sections let you include <, >, and & without escaping—useful for code and markup. CDATA cannot contain ']]>' literally; to embed it, split the section as shown. CDATA is character data, not parsed as elements.
<?xml version="1.0"?>
<root>
<script><![CDATA[
function check(a, b) {
if (a < b && b > 0) {
return a & b;
}
}
]]></script>
<!-- to include ]]> inside CDATA, split it -->
<data><![CDATA[foo]]]]><![CDATA[>bar]]></data>
</root>Custom Entities (DTD)
Internal entities are declared in a DTD and expanded wherever referenced. They act like text macros and can reference other entities. Useful for repeated boilerplate. Beware: external/general entities can be an XXE security risk.
<?xml version="1.0"?>
<!DOCTYPE root [
<!ENTITY company "Acme Corp.">
<!ENTITY version "2.0">
<!ENTITY copyright "Copyright © 2024 &company;">
]>
<root>
<product>&company; Toolkit v&version;</product>
<footer>©right;</footer>
</root>
<!-- Entities are expanded during parsing -->Escaping in Attributes
Inside attribute values you must escape & as &, and escape the quote character used to delimit the value (" or '). < should also be escaped. Newlines and tabs in attributes are normalized to spaces by the parser.
<?xml version="1.0"?>
<root>
<link url="https://example.com?a=1&b=2"/>
<msg text="Say "hello" & smile"/>
<path value='C:\Users\name'/>
<data value="<tagged>"/>
</root>Parameter Entities
Parameter entities (declared with %) are used only inside DTDs to build reusable content models. They are referenced as %name; (with a semicolon). General entities (&name;) are used in document content.
<?xml version="1.0"?>
<!DOCTYPE root [
<!ENTITY % inline " (#PCDATA | em | strong)* ">
<!ELEMENT p %inline;>
<!ELEMENT em %inline;>
<!ELEMENT strong %inline;>
<!ELEMENT root (p)*>
]>
<root>
<p>Hello <em>world</em> and <strong>XML</strong>.</p>
</root>DTD (Document Type Definition)
Internal DTD
An internal DTD is declared inline in the DOCTYPE within square brackets. It defines the structure: which elements exist, their content models, and attributes. Internal DTDs are self-contained but only apply to that one document.
<?xml version="1.0"?>
<!DOCTYPE note [
<!ELEMENT note (to, from, heading, body)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT heading (#PCDATA)>
<!ELEMENT body (#PCDATA)>
]>
<note>
<to>Alice</to>
<from>Bob</from>
<heading>Reminder</heading>
<body>Don't forget the meeting</body>
</note>External DTD
An external DTD lives in a separate .dtd file referenced by SYSTEM (private) or PUBLIC (public identifier + URI). External DTDs let many documents share one definition. SYSTEM 'file.dtd' is the most common form.
<!-- File: note.dtd -->
<!ELEMENT note (to, from, body)>
<!ELEMENT to (#PCDATA)>
<!ELEMENT from (#PCDATA)>
<!ELEMENT body (#PCDATA)>
<!-- File: note.xml -->
<?xml version="1.0"?>
<!DOCTYPE note SYSTEM "note.dtd">
<note>
<to>Alice</to>
<from>Bob</from>
<body>Hello</body>
</note>Element Declarations
Content models use , (sequence), | (choice), ? (0-1), * (0+), + (1+). #PCDATA is text; mixed content allows text interleaved with elements. EMPTY means no content; ANY disables checking (avoid in production).
<!ELEMENT root (child1, child2*)>
<!-- content model operators -->
<!ELEMENT list (item+)> <!-- one or more item -->
<!ELEMENT opt (item?)> <!-- zero or one item -->
<!ELEMENT any (item1 | item2)*> <!-- choice, any number -->
<!ELEMENT text (#PCDATA)> <!-- parsed character data -->
<!ELEMENT mixed (#PCDATA | em)*> <!-- mixed content -->
<!ELEMENT empty EMPTY> <!-- no content -->
<!ELEMENT any ANY> <!-- any content -->Attribute Declarations
ATTLIST declares an attribute's type and default. ID is a unique identifier; IDREF/IDREFS reference IDs (for cross-links). NMTOKEN is a name token. Enumerated types list allowed values. Defaults: #REQUIRED, #IMPLIED, #FIXED, or a literal.
<!ATTLIST book
id ID #REQUIRED
category CDATA #IMPLIED
lang NMTOKEN "en"
status (draft|final) "draft"
version CDATA #FIXED "1.0">
<!-- Types: CDATA, ID, IDREF, IDREFS, NMTOKEN, NMTOKENS,
NOTATION, enumerated (a|b|c) -->
<!ATTLIST link ref IDREF #REQUIRED>Entity Declarations
General entities (&name;) expand in content; parameter entities (%name;) expand in the DTD. External parsed entities include other XML; unparsed entities (with NDATA) point to non-XML data referenced via NOTATION. External entities can cause XXE injection.
<!DOCTYPE root [
<!-- internal general entity -->
<!ENTITY name "Alice">
<!-- external parsed entity -->
<!ENTITY chap1 SYSTEM "chapter1.xml">
<!-- unparsed entity (binary, e.g. image) -->
<!ENTITY logo SYSTEM "logo.png" NDATA image>
<!-- notation declaration for unparsed entities -->
<!NOTATION image SYSTEM "image/png">
<!-- parameter entity (DTD-only) -->
<!ENTITY % block "(p | list)+">
]>
<root>&name;</root>DTD Validation
Validation checks that a document matches its DTD (element order, allowed attributes, ID uniqueness). Standard DOM parsers like minidom do NOT validate by default—use lxml (Python), xmllint (command line), or a validating parser.
<?xml version="1.0"?>
<!DOCTYPE root SYSTEM "schema.dtd">
<root>
<item id="x1">valid</item>
</root>
<!-- Validate with Python: -->
<!-- import xml.dom.minidom as m
dom = m.parse("file.xml")
# minidom does NOT validate; use lxml: -->
<!-- from lxml import etree
dtd = etree.DTD("schema.dtd")
tree = etree.parse("file.xml")
print(dtd.validate(tree)) -->XML Schema (XSD)
Schema Structure
An XSD is itself an XML document. The root <schema> declares the XSD namespace and a target namespace for the elements it defines. elementFormDefault='qualified' puts local elements in the target namespace.
<?xml version="1.0"?>
<xs:schema xmlns:xs="http://www.w3.org/2001/XMLSchema"
targetNamespace="https://example.com/order"
xmlns:tns="https://example.com/order"
elementFormDefault="qualified">
<xs:element name="order" type="tns:OrderType"/>
<xs:complexType name="OrderType">
<xs:sequence>
<xs:element name="customer" type="xs:string"/>
<xs:element name="total" type="xs:decimal"/>
</xs:sequence>
<xs:attribute name="id" type="xs:ID" use="required"/>
</xs:complexType>
</xs:schema>Simple Types
A simpleType restricts a base type with facets (pattern, minInclusive, enumeration, length, etc.). Simple types have only text content and attributes—no child elements. They are reusable across the schema.
<xs:simpleType name="emailType">
<xs:restriction base="xs:string">
<xs:pattern value="[^@]+@[^@]+.[^@]+"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="ageType">
<xs:restriction base="xs:integer">
<xs:minInclusive value="0"/>
<xs:maxInclusive value="120"/>
</xs:restriction>
</xs:simpleType>
<xs:element name="email" type="tns:emailType"/>
<xs:element name="age" type="tns:ageType"/>Complex Types
A complexType can hold child elements and attributes. sequence enforces order; choice allows one of several; all allows any order (each at most once). Compositors can nest to express rich structures.
<xs:complexType name="AddressType">
<xs:sequence>
<xs:element name="street" type="xs:string"/>
<xs:element name="city" type="xs:string"/>
<xs:element name="zip" type="xs:string"/>
</xs:sequence>
<xs:attribute name="country" type="xs:string" default="US"/>
</xs:complexType>
<!-- Content model indicators: sequence, choice, all -->
<xs:complexType name="ContactType">
<xs:choice>
<xs:element name="phone" type="xs:string"/>
<xs:element name="email" type="xs:string"/>
</xs:choice>
</xs:complexType>Built-in Types
XSD provides a rich type hierarchy: strings, numbers (integer, decimal, float), dates/times, boolean, anyURI, ID/IDREF, and QName. Each supports facets like length, pattern, and enumeration for further restriction.
<!-- Common XSD built-in types -->
<xs:element name="count" type="xs:integer"/>
<xs:element name="price" type="xs:decimal"/>
<xs:element name="flag" type="xs:boolean"/>
<xs:element name="name" type="xs:string"/>
<xs:element name="date" type="xs:date"/> <!-- 2024-01-15 -->
<xs:element name="time" type="xs:time"/> <!-- 13:45:00 -->
<xs:element name="dt" type="xs:dateTime"/> <!-- 2024-01-15T13:45:00 -->
<xs:element name="id" type="xs:ID"/>
<xs:element name="ref" type="xs:IDREF"/>
<xs:element name="uri" type="xs:anyURI"/>Restrictions (Facets)
Facets constrain simple types: enumeration (allowed values), pattern (regex), length/minLength/maxLength, min/maxInclusive/Exclusive, totalDigits, fractionDigits, and whiteSpace (preserve/replace/collapse).
<xs:simpleType name="ColorType">
<xs:restriction base="xs:string">
<xs:enumeration value="red"/>
<xs:enumeration value="green"/>
<xs:enumeration value="blue"/>
</xs:restriction>
</xs:simpleType>
<xs:simpleType name="PasswordType">
<xs:restriction base="xs:string">
<xs:minLength value="8"/>
<xs:maxLength value="32"/>
<xs:pattern value="[A-Za-z0-9!@#]+"/>
</xs:restriction>
</xs:simpleType>Elements & Attributes in XSD
minOccurs/maxOccurs control cardinality (default 1); maxOccurs='unbounded' allows any number. Attribute 'use' is required/optional/prohibited, with an optional default or fixed value. Anonymous complex types inline the definition.
<xs:element name="product">
<xs:complexType>
<xs:sequence>
<xs:element name="name" type="xs:string"
minOccurs="1" maxOccurs="1"/>
<xs:element name="tag" type="xs:string"
minOccurs="0" maxOccurs="unbounded"/>
</xs:sequence>
<xs:attribute name="sku" type="xs:string" use="required"/>
<xs:attribute name="weight" type="xs:decimal" use="optional"
default="0.0"/>
</xs:complexType>
</xs:element>XPath
Path Expressions
XPath uses path-like expressions. '/' selects from the root; '//' selects descendants at any depth. '*' is a wildcard for any element; '@' selects attributes. An expression starting with '/' is absolute.
<!-- Sample: <bookstore><book><title>..</title></book></bookstore> -->
/bookstore/book/title <!-- absolute path -->
bookstore/book/title <!-- relative path -->
//title <!-- any title, anywhere -->
/bookstore//title <!-- title anywhere under bookstore -->
bookstore/* <!-- all children of bookstore -->
//@lang <!-- all lang attributes -->
//@* <!-- all attributes -->Predicates
Predicates in [ ] filter a node set. Indexing is 1-based. last() and position() refer to the node's position in its context. Predicates can test element text, attributes (@name), or computed values.
//book[1] <!-- first book -->
//book[last()] <!-- last book -->
//book[position() <= 3] <!-- first three books -->
//book[price > 25] <!-- books with price > 25 -->
//book[@category='web'] <!-- books in the web category -->
//book[author='Smith'] <!-- books authored by Smith -->
//book[@lang][2] <!-- 2nd book that has a lang attr -->Axes
Axes define navigation directions: child (default), descendant, parent (..), ancestor, following-sibling, preceding-sibling, attribute (@), self (.), descendant-or-self (//). Most have shorthand forms used in practice.
child::book <!-- default axis: children named book -->
descendant::title <!-- all title descendants -->
parent::* <!-- the parent element (shorthand: ..) -->
ancestor::section <!-- all section ancestors -->
following-sibling::p <!-- p elements after this one -->
preceding::item <!-- items before this in document order -->
attribute::id <!-- the id attribute (shorthand: @id) -->
self::node() <!-- the current node (shorthand: .) -->Functions
XPath 1.0 has built-in functions: count, sum, string-length, contains, starts-with, normalize-space, name, concat, substring, round, and more. XPath 2.0+ vastly expands the function library and adds typing.
count(//book) <!-- number of book elements -->
string-length(//title) <!-- length of first title's text -->
contains(//name, 'Ali') <!-- true if name contains 'Ali' -->
starts-with(@id, 'b') <!-- true if id starts with 'b' -->
normalize-space(//summary) <!-- collapse whitespace -->
name(//*[1]) <!-- name of the first element -->
concat(/a, /b) <!-- concatenate strings -->
sum(//price) <!-- sum of all price values -->Operators
XPath uses = for equality (single =, not ==), and the operators 'and'/'or' for logic (not && / ||). 'div' is division and 'mod' is modulo, since '/' is reserved for paths. '|' computes the union of node sets.