xml_set_element_handler()
The xml_set_element_handler() function is a PHP built-in function that sets user-defined functions as the handlers for the start and end tags of an XML element.
xml_set_element_handler() registers two callbacks on an XML parser: one that fires every time the parser meets an opening tag (<book>) and one that fires on every closing tag (</book>). It belongs to PHP's event-based Expat parser — the xml_parser_* family — not to SimpleXML or DOM. Where SimpleXML loads the whole document into a tree in memory, Expat streams through the document and calls your handlers as it goes, which makes it well suited to large files you don't want to load all at once.
This page covers the function's signature, the exact arguments your handlers receive, a complete runnable example, and the common gotchas (tag-name case folding and the object-method callback form).
Syntax
xml_set_element_handler(
XMLParser $parser,
callable $start_handler,
callable $end_handler
): bool| Parameter | Description |
|---|---|
$parser | The parser created by xml_parser_create(). |
$start_handler | Called on each opening tag. Receives ($parser, $name, $attributes). |
$end_handler | Called on each closing tag. Receives ($parser, $name). |
The function returns true on success and false on failure. A callback may be given as a function name string ("startTag"), a closure, or an object-method pair ([$object, 'method']).
What the handlers receive
- Start handler —
$nameis the tag name and$attributesis an associative array of that tag's attributes (['ID' => 'b1']). - End handler — only
$name, since closing tags carry no attributes.
By default Expat folds tag and attribute names to uppercase (
<book>arrives asBOOK). Compare names case-insensitively, or turn folding off withxml_parser_set_option($parser, XML_OPTION_CASE_FOLDING, false). Seexml_parser_set_option().
Usage Examples
Example: Printing the element tree
This complete script parses an XML string and uses the start/end handlers to print an indented outline of the document, including each tag's attributes.
<?php
$xml = '<?xml version="1.0"?>
<library>
<book id="b1">PHP Basics</book>
<book id="b2">Advanced XML</book>
</library>';
$depth = 0;
function startTag($parser, $name, $attrs) {
global $depth;
echo str_repeat(" ", $depth) . "START: $name";
foreach ($attrs as $key => $value) {
echo " ($key=\"$value\")";
}
echo "\n";
$depth++;
}
function endTag($parser, $name) {
global $depth;
$depth--;
echo str_repeat(" ", $depth) . "END: $name\n";
}
$parser = xml_parser_create();
xml_set_element_handler($parser, "startTag", "endTag");
if (!xml_parse($parser, $xml, true)) {
die(sprintf(
"XML error: %s at line %d",
xml_error_string(xml_get_error_code($parser)),
xml_get_current_line_number($parser)
));
}
xml_parser_free($parser);Output:
START: LIBRARY
START: BOOK (ID="b1")
END: BOOK
START: BOOK (ID="b2")
END: BOOK
END: LIBRARYNotice library arrives as LIBRARY and id as ID: that is the case folding mentioned above. The third argument to xml_parse() is set to true to tell the parser this is the final (and only) chunk of data. Always release the parser with xml_parser_free() when finished.
Example: Using an object method as the handler
Handlers don't have to be free functions. Passing [$object, 'method'] lets you keep parsing state on an object instead of in globals — useful when several handlers need to share data.
<?php
$xml = '<note><to>Tove</to><from>Jani</from></note>';
class TagCounter {
public int $open = 0;
public function onStart($parser, $name, $attrs) { $this->open++; }
public function onEnd($parser, $name) {}
}
$counter = new TagCounter();
$parser = xml_parser_create();
xml_set_element_handler($parser, [$counter, 'onStart'], [$counter, 'onEnd']);
xml_parse($parser, $xml, true);
xml_parser_free($parser);
echo "Opening tags seen: {$counter->open}\n";Output:
Opening tags seen: 3When to use it
Reach for the Expat handlers when you need a streaming, low-memory pass over XML — large feeds, log files, or sitemaps — or when you only care about a few tags and don't want to build a full tree. To read the text inside an element (the PHP Basics in <book>PHP Basics</book>), pair this with xml_set_character_data_handler(). If you'd rather query a small document with XPath-like access, SimpleXML is simpler. For an overview of every approach, see PHP XML Parsers.
Conclusion
xml_set_element_handler() wires start- and end-tag callbacks into PHP's event-driven Expat parser, letting you react to a document's structure as it streams past. Remember the three essentials: create the parser first, account for uppercase tag names, and free the parser when you're done.