PHP XML Expat Parser
In this page:
Why Use a Streaming Parser
SimpleXML and DOM both load an entire XML document into memory as a tree before you can read anything -- fine for small files, but potentially a serious memory problem for a multi-gigabyte XML export. Expat instead streams through the document once, processing it piece by piece without ever holding the whole thing in memory.
Note: Reach for Expat specifically when working with XML files large enough that loading the whole thing into memory at once would be a real concern.
Warning: Expat's event-driven style is more complex to work with than SimpleXML for straightforward "just give me the values" tasks -- only reach for it when its memory efficiency genuinely matters.
Example: Why Use a Streaming Parser
<?php
echo "Expat streams through XML piece by piece instead of loading a full tree into memory";
?>
Login to try C/C++/Java/PHP code in the editor
Creating a Parser and Registering Handlers
xml_parser_create() creates a new parser instance, and xml_set_element_handler($parser, $startCallback, $endCallback) registers two functions: one called every time an opening tag is encountered, and another every time a closing tag is encountered.
Note: Name your start and end handler functions clearly (like startElement and endElement) so their purpose is obvious when reading the registration call.
Warning: Handler functions must match Expat's expected parameter signature exactly (parser, tag name, and attributes for the start handler) or the callback will not receive the data correctly.
Example: Creating a Parser and Registering Handlers
<?php
$parser = xml_parser_create();
xml_set_element_handler($parser, function ($parser, $name) {
echo "Start: $name\n";
}, function ($parser, $name) {
echo "End: $name\n";
});
echo "Handlers registered";
xml_parser_free($parser);
?>
Login to try C/C++/Java/PHP code in the editor
Parsing XML Data
xml_parse($parser, $data, $isFinal) feeds a chunk of XML text to the parser, triggering the registered callbacks as it processes that chunk -- passing true as the final $isFinal argument tells the parser this is the last piece of data, letting it detect an incomplete document.
Note: For data already fully available as one string, pass true for $isFinal on the single xml_parse() call, marking the entire document as complete.
Warning: xml_parse() returns 0 on a parsing error -- check its return value, especially when feeding data in multiple chunks, to catch malformed XML early.
Example: Parsing XML Data
<?php
$parser = xml_parser_create();
xml_set_element_handler($parser, function ($p, $name) { echo "<$name>\n"; }, function ($p, $name) { echo "</$name>\n"; });
xml_parse($parser, "<book><title>PHP</title></book>", true);
xml_parser_free($parser);
?>
Login to try C/C++/Java/PHP code in the editor
Building Data with Handler State
Since each Expat callback only sees the single tag or text chunk it was just given, tracking meaningful state across multiple calls (like which element is currently open, or accumulating a list of parsed records) requires using variables outside the handler functions, often global or captured by reference.
Note: Use a class with the parser state as object properties, rather than global variables, for anything beyond the simplest Expat-based parsing script.
Warning: Relying on global variables inside handler functions works but can become hard to manage and error-prone once the parsing logic grows more complex than a few tags.
Example: Building Data with Handler State
<?php
$titles = [];
$parser = xml_parser_create();
xml_set_element_handler($parser, function () {}, function () {});
xml_set_character_data_handler($parser, function ($p, $data) use (&$titles) {
if (trim($data) !== '') $titles[] = trim($data);
});
xml_parse($parser, "<book>PHP Basics</book>", true);
print_r($titles);
xml_parser_free($parser);
?>
Login to try C/C++/Java/PHP code in the editor
Freeing Parser Resources
xml_parser_free($parser) releases the parser instance's resources once parsing is complete -- important to call explicitly in scripts that create many parsers (like processing many files in a loop), though PHP also cleans it up automatically when the script ends.
Note: Call xml_parser_free() as soon as you are done with a parser, especially in any loop that creates a new one for each of several files.
Warning: Attempting to use xml_parse() on a parser instance after it has already been freed will fail, so make sure all parsing work finishes before freeing it.
Example: Freeing Parser Resources
<?php
$parser = xml_parser_create();
xml_parse($parser, "<book></book>", true);
xml_parser_free($parser);
echo "Parser resources released";
?>
Login to try C/C++/Java/PHP code in the editor
- Choosing Expat for small, everyday XML parsing tasks where SimpleXML would be far simpler and perfectly adequate -- Expat's complexity is only worth it for very large files.
- Forgetting that Expat callbacks fire in document order as parsing proceeds -- you cannot "look ahead" to data that has not been reached yet, unlike with a fully-loaded SimpleXML tree.
- Not tracking parsing state (like which element is currently open) across callback calls, since each callback only knows about the single tag or text chunk it was just given.
- xml_parser_create() creates a new Expat parser instance, and xml_set_element_handler() registers callback functions for opening and closing tags.
- xml_parse($parser, $data) feeds XML data to the parser, which processes it and triggers the registered callbacks along the way.
- Expat is a streaming, event-based parser that never holds the entire document in memory at once, making it well-suited to very large XML files.
The Expat XML parser extension has been bundled with PHP since PHP 4 and is enabled by default in most standard installations.
Chapter Quiz — Complete all 24 topics to unlock
0/24 topics done
Complete these topics first:
- PHP Date & Time
- PHP Math Functions
- PHP JSON Handling
- PHP XML Handling
- PHP cURL Introduction
- PHP REST API Basics
- PHP Composer & Packages
- PHP Autoloading
- PHP Design Patterns
- PHP MVC Architecture
- PHP Security Best Practices
- PHP Performance Optimization
- PHP 8 New Features
- PHP Type Declarations
- PHP Match Expression Advanced
- PHP Fibers
- PHP Attributes
- PHP Magic Constants
- PHP Include & Require
- PHP Iterables
- PHP SimpleXML Parser
- PHP SimpleXML Get
- PHP XML Expat Parser
- PHP DOM Parser