PHP XML DOM
Learn how to use the PHP DOM extension to load, create, modify, query (with XPath) and save XML documents, with runnable examples.
What the DOM extension is for
The DOM (Document Object Model) extension represents an XML document as a tree of nodes in memory. Every element, attribute, text fragment and comment is a node object you can read, move, add or delete. Because the whole document is loaded into RAM, the DOM is the right tool when you need to modify XML, build a document from scratch, or run XPath queries that jump around the tree.
This page covers loading, creating, modifying, querying and saving XML with DOMDocument. The trade-offs versus the lighter alternatives are:
- Use the SimpleXML extension when you only need to read well-formed XML quickly with minimal code.
- Use the XML Parser (Expat) for event-based streaming of very large files that should not be held fully in memory.
- Reach for the DOM (this page) when you need full read/write control and XPath.
The DOM and libxml share an error system; see PHP libxml for managing parse errors.
Enabling the extension
The DOM extension ships with PHP and is enabled by default in most builds (it is part of the php-xml package on Debian/Ubuntu). You can confirm it is available:
<?php
var_dump(extension_loaded('dom')); // bool(true)If it is missing, install the php-xml package for your platform, or enable extension=dom in php.ini, then restart your web server.
Loading an XML document
Create a DOMDocument and load XML from a string with loadXML() or from a file with load(). Turn on libxml_use_internal_errors(true) first so malformed markup does not spray warnings — you collect the errors yourself instead.
<?php
$xml = <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<books>
<book id="1"><title>PHP for Beginners</title></book>
<book id="2"><title>Advanced XML</title></book>
</books>
XML;
libxml_use_internal_errors(true);
$doc = new DOMDocument();
if (!$doc->loadXML($xml)) {
foreach (libxml_get_errors() as $error) {
echo trim($error->message) . "\n";
}
libxml_clear_errors();
exit;
}
$root = $doc->documentElement;
echo "Root element: {$root->nodeName}\n";
foreach ($root->getElementsByTagName('title') as $title) {
echo "Title: {$title->nodeValue}\n";
}Output:
Root element: books
Title: PHP for Beginners
Title: Advanced XMLgetElementsByTagName() returns a live DOMNodeList you can foreach over directly — it is usually clearer than walking childNodes, which also includes the whitespace text nodes between elements.
Creating an XML document from scratch
Build a document by creating nodes on the DOMDocument and appending them into a parent. Set formatOutput = true to get indented, human-readable output from saveXML().
<?php
$doc = new DOMDocument('1.0', 'UTF-8');
$doc->formatOutput = true;
$root = $doc->createElement('books');
$doc->appendChild($root);
$book = $doc->createElement('book');
$book->setAttribute('id', '1');
$root->appendChild($book);
$title = $doc->createElement('title', 'PHP for Beginners');
$book->appendChild($title);
echo $doc->saveXML();Output:
<?xml version="1.0" encoding="UTF-8"?>
<books>
<book id="1">
<title>PHP for Beginners</title>
</book>
</books>Key methods used here:
createElement($name, $value)— make an element, optionally with text content.setAttribute($name, $value)— add or overwrite an attribute on an element.appendChild($node)— attach a node as the last child of its parent.
Gotcha: passing text directly to
createElement('title', $userInput)does not escape&,<or>reliably. For untrusted text, append a text node instead:$el->appendChild($doc->createTextNode($userInput)), which always escapes special characters.
Modifying and deleting nodes
Because the whole tree is in memory, you can change text, update attributes and remove elements before saving. A clean way to locate the right node is XPath (covered next), but here we use it inline:
<?php
$xml = <<<XML
<books>
<book id="1"><title>PHP for Beginners</title></book>
<book id="2"><title>Advanced XML</title></book>
</books>
XML;
$doc = new DOMDocument();
$doc->formatOutput = true;
$doc->loadXML($xml);
$xpath = new DOMXPath($doc);
// Rename the first title
$first = $xpath->query('//book[@id="1"]/title')->item(0);
$first->nodeValue = 'PHP Essentials';
// Remove the second book
$second = $xpath->query('//book[@id="2"]')->item(0);
$second->parentNode->removeChild($second);
echo $doc->saveXML();Output:
<?xml version="1.0"?>
<books>
<book id="1"><title>PHP Essentials</title></book>
</books>To delete a node you call removeChild() on its parent, which is why $second->parentNode->removeChild($second) is the idiom. Assigning to nodeValue replaces an element's text content.
Querying with XPath
DOMXPath lets you select nodes with path expressions instead of manually walking the tree — far more concise than nested loops.
<?php
$xml = <<<XML
<books>
<book id="1"><title>PHP for Beginners</title></book>
<book id="2"><title>Advanced XML</title></book>
</books>
XML;
$doc = new DOMDocument();
$doc->loadXML($xml);
$xpath = new DOMXPath($doc);
// Every <title> anywhere in the document
foreach ($xpath->query('//title') as $node) {
echo $node->nodeValue . "\n";
}
// The title of the book whose id is "2"
$result = $xpath->query('//book[@id="2"]/title');
echo "Book 2: " . $result->item(0)->nodeValue . "\n";Output:
PHP for Beginners
Advanced XML
Book 2: Advanced XMLCommon XPath patterns:
| Expression | Selects |
|---|---|
//title | All <title> elements at any depth |
/books/book | <book> children directly under the root <books> |
//book[@id="2"] | <book> elements with attribute id="2" |
//book/@id | The id attribute nodes of every <book> |
//book[1] | The first <book> (XPath indexes start at 1) |
Saving to a file
Persist the in-memory tree with save(), which returns false on failure (for example, an unwritable directory).
<?php
$doc = new DOMDocument('1.0', 'UTF-8');
$doc->formatOutput = true;
$root = $doc->createElement('config');
$doc->appendChild($root);
$root->appendChild($doc->createElement('debug', 'false'));
if ($doc->save(__DIR__ . '/output.xml')) {
echo 'Saved successfully.';
} else {
echo 'Failed to save — check directory permissions.';
}Use saveXML() (no arguments) when you want the XML as a string instead — handy for returning it from an API or echoing it in a response.
Summary
DOMDocumentloads an entire XML document into a mutable tree of nodes.- Use
loadXML()/load()to read,createElement()andappendChild()to build, andremoveChild()to delete. DOMXPath::query()selects nodes with concise path expressions.save()writes to a file;saveXML()returns the document as a string.- Choose the DOM when you need to write or query XML; choose SimpleXML for quick reads and the XML Parser for streaming huge files.