I thought I'd share the function in case others have need of something similar in the future; it took a while to get it settled, and it might need tweaking for your circumstances.
Code: Select all
<?php
/**
* Pretty an XML string typically returned from DOMDocument->saveXML()
*
* Ignores ?xml !DOCTYPE !-- tags (adjust regular expressions and pad/indent logic to change this)
*
* @param string $xml the xml text to format
* @param boolean $debug set to get debug-prints of RegExp matches
* @returns string formatted XML
* @copyright TJ 2005
* @license GNU Lesser General Public Licence version 2
* @link kml.tjworld.net
*/
function prettyXML($xml, $debug=false) {
// add marker linefeeds to aid the pretty-tokeniser
// adds a linefeed between all tag-end boundaries
$xml = preg_replace('/(>)(<)(\/*)/', "$1\n$2$3", $xml);
// now pretty it up (indent the tags)
$tok = strtok($xml, "\n");
$formatted = ''; // holds pretty version as it is built
$pad = 0; // initial indent
$matches = array(); // returns from preg_matches()
/* pre- and post- adjustments to the padding indent are made, so changes can be applied to
* the current line or subsequent lines, or both
*/
while($tok !== false) { // scan each line and adjust indent based on opening/closing tags
// test for the various tag states
if (preg_match('/.+<\/\w[^>]*>$/', $tok, $matches)) { // open and closing tags on same line
if($debug) echo " =$tok= ";
$indent=0; // no change
}
else if (preg_match('/^<\/\w/', $tok, $matches)) { // closing tag
if($debug) echo " -$tok- ";
$pad--; // outdent now
}
else if (preg_match('/^<\w[^>]*[^\/]>.*$/', $tok, $matches)) { // opening tag
if($debug) echo " +$tok+ ";
$indent=1; // don't pad this one, only subsequent tags
}
else {
if($debug) echo " !$tok! ";
$indent = 0; // no indentation needed
}
// pad the line with the required number of leading spaces
$prettyLine = str_pad($tok, strlen($tok)+$pad, ' ', STR_PAD_LEFT);
$formatted .= $prettyLine . "\n"; // add to the cumulative result, with linefeed
$tok = strtok("\n"); // get the next token
$pad += $indent; // update the pad size for subsequent lines
}
return $formatted; // pretty format
}
echo "\r\n" . prettyXML("<root><this><is>a</is><test /></this></root>", true);
?>