views:

1571

answers:

4

I'm using DOMDocument to generate a new XML file and I would like for the output of the file to be indented nicely so that it's easy to follow for a human reader.

For example, when DOMDocument outputs this data:

<?xml version="1.0"?>
<this attr="that"><foo>lkjalksjdlakjdlkasd</foo><foo>lkjlkasjlkajklajslk</foo></this>

I want the XML file to be:

<?xml version="1.0"?>
<this attr="that">
    <foo>lkjalksjdlakjdlkasd</foo>
    <foo>lkjlkasjlkajklajslk</foo>
</this>

I've been searching around looking for answers, and everything that I've found seems to say to try to control the white space this way:

$foo = new DOMDocument();
$foo->preserveWhiteSpace = false;
$foo->formatOutput = true;

But this does not seem to do anything. Perhaps this only works when reading XML? Keep in mind I'm trying to write new documents.

Is there anything built-in to DOMDocument to do this? Or a function that can accomplish this easily?

Many thanks!

A: 

I have tried running the code below setting formatOutput and preserveWhiteSpace in different ways, and the only member that has any effect on the output is formatOutput. Can you run the script below and see if it works?

<?php
    echo "<pre>";
    $foo = new DOMDocument();
    //$foo->preserveWhiteSpace = false;
    $foo->formatOutput = true;
    $root = $foo->createElement("root");
    $root->setAttribute("attr", "that");
    $bar = $foo->createElement("bar", "some text in bar");
    $baz = $foo->createElement("baz", "some text in baz");
    $foo->appendChild($root);
    $root->appendChild($bar);
    $root->appendChild($baz);
    echo htmlspecialchars($foo->saveXML());
    echo "</pre>";
?>
John Rasch
Your code works fine, but it doesn't work for me with the way I've set it up. I have a class xml and inside that class I create a variable $this->xml which holds an instance of DOMDocument, and it doesn't seem to work with that setup.I would also prefer to have real tabs instead of just spaces.
Josh Leitzel
This seems like a special case then. I created a simple class with "xml" as a member, and it still worked. There are too many factors and without your exact code (or a simplified version that still fails for you) it's going to be impossible to reproduce.
John Rasch
Thanks for your help John. I've written a basic indentation function that will hopefully fix my problem (about to post it as an answer if you want to take a look).
Josh Leitzel
+1  A: 

After some help from John and playing around with this on my own, it seems that even DOMDocument's inherent support for formatting didn't meet my needs. So, I decided to write my own indentation function.

This is a pretty crude function that I just threw together quickly, so if anyone has any optimization tips or anything to say about it in general, I'd be glad to hear it!

function indent($text)
{
    // Create new lines where necessary
    $find = array('>', '</', "\n\n");
    $replace = array(">\n", "\n</", "\n");
    $text = str_replace($find, $replace, $text);
    $text = trim($text); // for the \n that was added after the final tag

    $text_array = explode("\n", $text);
    $open_tags = 0;
    foreach ($text_array AS $key => $line)
    {
     if (($key == 0) || ($key == 1)) // The first line shouldn't affect the indentation
      $tabs = '';
     else
     {
      for ($i = 1; $i <= $open_tags; $i++)
       $tabs .= "\t";
     }

     if ($key != 0)
     {
      if ((strpos($line, '</') === false) && (strpos($line, '>') !== false))
       $open_tags++;
      else if ($open_tags > 0)
       $open_tags--;
     }

     $new_array[] = $tabs . $line;

     unset($tabs);
    }
    $indented_text = implode("\n", $new_array);

    return $indented_text;
}
Josh Leitzel
A quick remark: There is str_repeat() for the creating the tabs. The rest of the function seems quite okay to me. You could set up a small performance comparison to the one I've found. As an alternative idea, you can use strtok() to tokenize the input iteratively (instead of replace/explode).
Tomalak
Thanks! I actually like the function you found better than my own, as I've discovered it does the formatting badly the deeper you go.And I never knew about either str_repeat() or strtok(), so thanks for that as well!
Josh Leitzel
+3  A: 

There is a nice straightforward function (based on regular expressions) here: Format XML with PHP

Tomalak
A: 

header("content-type:text/xml");

$str = ""; $str .= ""; $str .= ""; $str .= ""; $str .= ""; $str .= ""; echo $str .= "";

if you are using other than .xml eextension than first set header content type text/xml