XML Pretty Printer in PHP5
by Will Bond - March 15, 2007 / 1:12pm View more articles
Today I was working with debugging some XML, and needed a way to make the XML more readable. The following is a little function that should do the job for some simple XML, and you can probably tweak it to your needs. It uses PHP5's SimpleXMLElement object to parse and return the XML, then indents it in a logical way.
Comments have been turned off on this blog.
Read something more recent.
8 Comments
I got it just right to my job.
Cheers.
1. Replace the explode's separator with '><'
2. Replace the join's separator with ">
<"
Good start, but nothing seems to get indented like that. Maybe this is a better fix...
Replace line 16 (the line beginning with "$xml_lines") with the following:
$xml_lines = explode("
", str_replace("><", ">
<", $xml_obj->asXML()));
That's it =)
This makes your function work well against the results of SoapClient::__getLastResponse and SoapClient::__getLastRequest
This will save me a lot of time being able to directly read debug output from
__getLastResponse
and
__getLastRequest
May this help the next googler.
function xml_pretty_printer($xml, $html_output=FALSE)
{
$xml_obj = new SimpleXMLElement($xml);
$xml_lines = explode("\n", str_replace("><",">\n<",$xml_obj->asXML()));
$indent_level = 0;
$new_xml_lines = array();
foreach ($xml_lines as $xml_line) {
if (preg_match('#^(<[a-z0-9_:-]+((s+[a-z0-9_:-]+="[^"]+")*)?>.*<s*/s*[^>]+>)|(<[a-z0-9_:-]+((s+[a-z0-9_:-]+="[^"]+")*)?s*/s*>)#i', ltrim($xml_line))) {
$new_line = str_pad('', $indent_level*4) . ltrim($xml_line);
$new_xml_lines[] = $new_line;
} elseif (preg_match('#^<[a-z0-9_:-]+((s+[a-z0-9_:-]+="[^"]+")*)?>#i', ltrim($xml_line))) {
$new_line = str_pad('', $indent_level*4) . ltrim($xml_line);
$indent_level++;
$new_xml_lines[] = $new_line;
} elseif (preg_match('#<s*/s*[^>/]+>#i', $xml_line)) {
$indent_level--;
if (trim($new_xml_lines[sizeof($new_xml_lines)-1]) == trim(str_replace("/", "", $xml_line))) {
$new_xml_lines[sizeof($new_xml_lines)-1] .= $xml_line;
} else {
$new_line = str_pad('', $indent_level*4) . $xml_line;
$new_xml_lines[] = $new_line;
}
} else {
$new_line = str_pad('', $indent_level*4) . $xml_line;
$new_xml_lines[] = $new_line;
}
}
$xml = join("\n", $new_xml_lines);
return ($html_output) ? '<pre>' . $this->xmlspecialchars($xml) . '</pre>' : $xml;
}
function xmlspecialchars($text) {
return str_replace(''', ''', htmlspecialchars($text, ENT_QUOTES, 'UTF-8',false));
}
In your last example, the whitespace tokens in the regexes are missing backslashes, resulting in indenting errors where entities have attributes. Replace 's' with 's' in those, and it's all good. :-)