SimpleXML in PHP: A Comprehensive Guide
SimpleXML is a powerful tool in PHP that makes it easy to parse and manipulate XML data. This tutorial will show you how to use SimpleXML in PHP, from the
SimpleXML is a built-in PHP extension that turns an XML document into a tree of objects you can read, loop over, and modify with ordinary PHP syntax. This tutorial covers loading XML, reading elements and attributes, handling namespaces, modifying nodes, and writing the result back out — with runnable examples and the gotchas that trip people up.
Introduction to SimpleXML
SimpleXML is a PHP extension that lets you parse and manipulate XML data with very little code. It is distinct from the DOM extension, but both sit on top of the same libxml2 library, so they share its error handling. The trade-off is simple:
- SimpleXML — best for reading well-formed XML where you mostly walk down a known structure. Concise, object-like access.
- DOM — better for heavy editing, moving nodes around, or when you need full control over the document tree.
SimpleXML is enabled by default in standard PHP builds, so there is usually nothing to install.
Loading XML
There are two entry points. Use simplexml_load_file() for a file or URL, and simplexml_load_string() for XML you already have in a string (for example, an API response).
Because both functions rely on libxml2, a malformed document triggers PHP warnings and returns false. Always switch to internal error handling first with libxml_use_internal_errors() so you can inspect the errors yourself instead of leaking warnings to output:
Loading an XML file
libxml_use_internal_errors(true);
$xml = simplexml_load_file('data.xml');
if ($xml === false) {
foreach (libxml_get_errors() as $error) {
echo trim($error->message), PHP_EOL;
}
die('Failed to load XML.');
}simplexml_load_string() works identically but takes the XML text directly:
Loading XML from a string
$source = '<data><item><name>John Doe</name></item></data>';
$xml = simplexml_load_string($source);In both cases the return value is a SimpleXMLElement representing the root element of the document.
Accessing Elements
SimpleXML maps each child element to a property on the parent object, accessed with the PHP object operator -> (not dot notation — PHP has no . member access). Repeated child elements are addressed by index. Consider this XML:
XML example
<data>
<item>
<name>John Doe</name>
<age>30</age>
</item>
<item>
<name>Jane Doe</name>
<age>28</age>
</item>
</data>Read the first item, then loop over every item with foreach:
Accessing element values
// The first <item> (index 0)
$name = $xml->item[0]->name;
$age = $xml->item[0]->age;
// Iterate through all <item> elements
foreach ($xml->item as $item) {
echo $item->name . ' is ' . $item->age . ' years old.' . PHP_EOL;
}The string-cast gotcha
$item->name is not a string — it is a SimpleXMLElement. It only looks like a string when echoed because the element is automatically cast in string contexts. If you store it in an array, pass it to json_encode(), or compare it strictly, cast it explicitly first:
$name = (string) $xml->item[0]->name; // plain string
$age = (int) $xml->item[0]->age; // plain intReading Attributes
Element attributes are accessed with array syntax, not the -> operator. Given <item id="1" status="active">, read them like this:
Accessing attributes
$id = (string) $xml->item[0]['id']; // "1"
$status = (string) $xml->item[0]['status']; // "active"
// Loop over every attribute on an element
foreach ($xml->item[0]->attributes() as $key => $value) {
echo "$key = $value" . PHP_EOL;
}Working with Namespaces
XML that uses namespaces (prefixes like <atom:link>) will not resolve through plain property access — you must register the namespace with children() or use an XPath query. This is the most common reason "the element is empty" even though it is clearly in the file:
Namespaced elements
$source = '<feed xmlns:atom="http://www.w3.org/2005/Atom">'
. '<atom:title>Hello</atom:title></feed>';
$xml = simplexml_load_string($source);
$atom = $xml->children('http://www.w3.org/2005/Atom');
echo (string) $atom->title; // "Hello"Querying with XPath
For anything deeper than a direct child, xpath() returns an array of matching elements — far cleaner than nesting loops:
// Every <name> anywhere under the root
foreach ($xml->xpath('//name') as $name) {
echo (string) $name . PHP_EOL;
}Modifying and Adding Elements
You can change a value by assigning to the property, and grow the tree with addChild() / addAttribute():
Modifying and building nodes
// Change existing values
$xml->item[0]->name = 'John Smith';
$xml->item[0]->age = 32;
// Add a brand-new child element and an attribute
$new = $xml->addChild('item');
$new->addChild('name', 'New Person');
$new->addAttribute('id', '99');Assigning a value replaces the element's text content; addChild() appends a new element rather than overwriting one.
Converting Back to XML
Use the asXML() method to serialize the (possibly modified) tree back to a string, then write it with file_put_contents():
Saving changes back to XML
file_put_contents('data.xml', $xml->asXML());Called with no argument, asXML() returns the full document as a string including the <?xml version="1.0"?> declaration — exactly what you want for saving. Call it on a child element ($xml->item[0]->asXML()) to get just that fragment, without the declaration.
Conclusion
SimpleXML is the quickest way to read and lightly edit well-formed XML in PHP: load with simplexml_load_file() or simplexml_load_string(), walk the tree with -> and array indexing, read attributes with [], and serialize back with asXML(). Remember the two recurring gotchas — cast elements to strings before reuse, and register namespaces before accessing prefixed nodes. For programmatic, large-scale document editing, reach for the DOM extension instead. To go deeper, continue with PHP SimpleXML and reading data with SimpleXML get.