Skip to content

PHP XML DOM

PHP provides built-in extensions for parsing and manipulating XML documents. The DOM (Document Object Model) extension is one powerful option that treats an XML document as a tree structure in memory.

The DOM parser loads the entire XML document into memory and represents it as a tree of objects (nodes). This allows for complex navigation, modification, and querying of the XML structure.

Consider this simple XML fragment:

<?xml version="1.0" encoding="UTF-8"?>
<message>
<from>Jani</from>
</message>

The DOM parser views this as a hierarchy:

  • Document Node
  • Element Node: <message>
  • Text Node: (Whitespace between `<message>` and `<from>`)
  • Element Node: `<from>`
  • Text Node: "Jani"
  • Text Node: (Whitespace after `</from>`)

Understanding this tree structure is key to using the DOM API effectively.

Alternative: For simpler XML reading tasks, especially with large files where memory is a concern, the SimpleXML extension often provides an easier-to-use interface. For stream-based processing of very large files, the XMLReader and XMLWriter extensions are more suitable.

The DOM extension (ext-dom) is typically compiled and enabled by default in most PHP installations. No separate installation is usually required.

We’ll use the following note.xml file for the examples:

<?xml version="1.0" encoding="UTF-8"?>
<note importance="high">
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body>Don't forget me this weekend!</body>
</note>

The core class is DOMDocument. We can load an XML file or string into it and save it back out.

<?php
// Create a new DOMDocument object
$xmlDoc = new DOMDocument();
// Load the XML file (error suppression '@' can be used, but checking return value is better)
// For better formatting and whitespace handling:
$xmlDoc->preserveWhiteSpace = false;
$xmlDoc->formatOutput = true;
if ($xmlDoc->load('note.xml')) {
// Save the loaded XML back to a string
$xmlString = $xmlDoc->saveXML();
// Output the XML (ensure proper content type if serving via web)
// header('Content-Type: application/xml; charset=utf-8');
echo htmlspecialchars($xmlString, ENT_QUOTES, 'UTF-8');
} else {
echo "Failed to load note.xml";
// Add proper error handling, e.g., using libxml_get_errors()
}
?>

This code creates a DOMDocument object, loads note.xml into it (disabling whitespace preservation and enabling output formatting for readability), and then uses saveXML() to output the document’s content as a string.

Once loaded, you can navigate the DOM tree to extract specific data.

<?php
$xmlDoc = new DOMDocument();
$xmlDoc->preserveWhiteSpace = false; // Ignore whitespace text nodes
$xmlDoc->load('note.xml');
// Get the root element (<note>)
$rootElement = $xmlDoc->documentElement;
echo "Reading elements directly under <note>:\n";
// Iterate through child nodes of the root element
foreach ($rootElement->childNodes as $item) {
// Check if it's an element node (type 1) to avoid text nodes etc.
if ($item->nodeType === XML_ELEMENT_NODE) {
// nodeName gives the tag name (e.g., 'to')
// nodeValue of an element itself is often null/empty,
// text content is in its child text node.
// textContent gets the combined text content of the node and its descendants.
echo $item->nodeName . " = " . $item->textContent . "\n";
}
}
// Accessing attributes (e.g., the 'importance' attribute of <note>)
if ($rootElement->hasAttribute('importance')) {
$importance = $rootElement->getAttribute('importance');
echo "\nImportance attribute: " . htmlspecialchars($importance, ENT_QUOTES, 'UTF-8') . "\n";
}
// Using getElementsByTagName to find specific elements
echo "\nFinding all <body> elements:\n";
$bodyElements = $xmlDoc->getElementsByTagName('body');
foreach ($bodyElements as $body) {
echo "Body content: " . $body->textContent . "\n";
}
?>

Expected Output:

Reading elements directly under <note>:
to = Tove
from = Jani
heading = Reminder
body = Don't forget me this weekend!
Importance attribute: high
Finding all <body> elements:
Body content: Don't forget me this weekend!

Explanation:

  • documentElement: Accesses the root element of the XML document.
  • childNodes: A DOMNodeList containing all direct children (including text nodes, comment nodes, etc.).
  • nodeType === XML_ELEMENT_NODE: Checks if a node is an actual element (like <to>, <from>) rather than whitespace or a comment.
  • nodeName: Returns the tag name of the element.
  • textContent: Returns the textual content of the node and all its descendants.
  • getAttribute() / hasAttribute(): Used to access element attributes.
  • getElementsByTagName(): Finds all elements with a specific tag name anywhere within the context node (or the whole document).

Common Pitfall: Be mindful of whitespace nodes between elements if preserveWhiteSpace is not set to false. They will appear in childNodes and might require explicit checks (nodeType !== XML_TEXT_NODE or checking if trim($node->nodeValue) is empty).

Tip: For more complex queries, especially on large documents, consider using DOMXPath which allows you to use XPath expressions to select nodes.

The DOM extension provides many more capabilities, including creating new nodes, modifying existing ones, deleting nodes, and working with namespaces. Consult the official PHP documentation for DOMDocument, DOMElement, DOMNode, DOMXPath, and related classes for comprehensive details.