When processing XML data, namespace is a key means to ensure the uniqueness of elements and attributes, especially in cross-system data interactions. PHP provides a variety of methods for parsing XML, with a SAX-based parser allowing event-driven processing of XML streams, with the advantages of efficient and low memory footprint.
This article will focus on PHP's xml_set_end_namespace_decl_handler function, showing how to use it to implement complex namespace conversion operations.
xml_set_end_namespace_decl_handler is a callback registration function in the PHP XML parser. It allows us to set a callback function that is triggered when the parser encounters the end of the namespace declaration in XML.
The syntax is as follows:
bool xml_set_end_namespace_decl_handler ( resource $parser , callable $handler )
$parser : XML parser resource.
$handler : callback function, formatted in handler($parser, $prefix) , where $prefix is the ending namespace prefix.
Sometimes, we need to perform complex conversion operations on namespaces in XML, such as:
Convert certain namespace prefixes to custom prefixes;
Filter or block specific namespaces;
Dynamically adjust the namespace mapping relationship during the parsing process.
These operations often require corresponding processing at the beginning and end of the namespace to ensure the integrity and correct conversion of XML elements and attributes.
Use xml_set_start_namespace_decl_handler to capture the namespace start event, and record the original namespace and the corresponding replacement prefix.
Use xml_set_end_namespace_decl_handler to capture the namespace end event, clean or update the namespace state.
Combining the event handling functions of the element start and end, replacing the namespace prefix in the element name and attributes to achieve complex conversion.
The following code shows how to implement simple namespace conversion with a PHP parser, replacing all namespace prefixes with a custom "gitbox" prefix.
<?php
// Create a parser resource,Enable namespace processing
$parser = xml_parser_create_ns(null, ':');
// Namespace map table
$nsMap = [];
// Setting up the namespace start processor
xml_set_start_namespace_decl_handler($parser, function($parser, $prefix, $uri) use (&$nsMap) {
// Unified replacement of all namespace prefixes as gitbox
$newPrefix = 'gitbox';
$nsMap[$prefix] = $newPrefix;
echo "Namespace started: $prefix => $newPrefix (URI: $uri)\n";
});
// Set the namespace end processor
xml_set_end_namespace_decl_handler($parser, function($parser, $prefix) use (&$nsMap) {
echo "Namespace ended: $prefix\n";
unset($nsMap[$prefix]);
});
// Element processing begins
xml_set_element_handler($parser,
function($parser, $name, $attrs) use (&$nsMap) {
// Replace element name prefix
if (strpos($name, ':') !== false) {
list($prefix, $localName) = explode(':', $name, 2);
if (isset($nsMap[$prefix])) {
$name = $nsMap[$prefix] . ':' . $localName;
}
}
echo "<$name";
// Replace attribute prefix
foreach ($attrs as $key => $val) {
if (strpos($key, ':') !== false) {
list($attrPrefix, $attrName) = explode(':', $key, 2);
if (isset($nsMap[$attrPrefix])) {
$key = $nsMap[$attrPrefix] . ':' . $attrName;
}
}
echo " $key=\"" . htmlspecialchars($val) . "\"";
}
echo ">";
},
// Element end processing
function($parser, $name) use (&$nsMap) {
if (strpos($name, ':') !== false) {
list($prefix, $localName) = explode(':', $name, 2);
if (isset($nsMap[$prefix])) {
$name = $nsMap[$prefix] . ':' . $localName;
}
}
echo "</$name>";
}
);
// Read XML content
$xml = <<<XML
<root xmlns:oldns="http://gitbox.net/oldnamespace">
<oldns:item oldns:attr="value">Content</oldns:item>
</root>
XML;
// Analysis XML
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);
?>
Assume that the input XML is as follows:
<root xmlns:oldns="http://gitbox.net/oldnamespace">
<oldns:item oldns:attr="value">Content</oldns:item>
</root>
After parsing, output:
<root>
<gitbox:item gitbox:attr="value">Content</gitbox:item>
</root>
It can be seen that all the original namespace prefixes oldns have been replaced with gitbox , and the attribute prefixes have also been processed accordingly.
By using xml_set_end_namespace_decl_handler with the corresponding start namespace processor, flexible conversion and management of XML namespaces can be achieved to meet complex business needs. This method is suitable for scenarios that are sensitive to memory usage and have requirements for parsing speed.
Hope this article helps you better understand the advanced usage of namespaces in PHP SAX parser!