Here much simpler way how to output pretty XML string instead of one, hard to understand single line. The solution was found on the page: http://302-found.blogspot.com/2007/11/simple-simplexml.html
<?php
$doc = new DOMDocument('1.0');
$doc->preserveWhiteSpace = false;
$doc->loadXML($rss2->asXML());
$doc->formatOutput = true;
echo $doc->saveXML();
?>
The previous suggestions on that page do not work for me (since they miss $doc->preserveWhiteSpace = false; line). I hope that code will save somebody’s time ;)
Good luck in your project and have a nice coding
Owner of http://proxy-list.org
SimpleXMLElement->asXML
(No version information available, might be only in CVS)
SimpleXMLElement->asXML — Devuelve una cadena XML basada en el objeto SimpleXML
Descripción
El método asXML da formato a los datos del objeto al que pertenece en XML versión 1.0.
Lista de parámetros
- nombre_archivo
-
Si se especifica, la función escribe la cadena en el fichero indicado en vez de devolverla.
Valores retornados
Si no se especifica el parámetro nombre_archivo , la función devuelve una string si tuvo éxito y FALSE si hubo algún error. Si se especifica el parámetro, devuelve TRUE si se escribió el fichero correctamente y FALSE en caso contrario.
Ejemplos
Example #1 Obtener un XML
<?php
$string = <<<XML
<a>
<b>
<c>text</c>
<c>stuff</c>
</b>
<d>
<c>code</c>
</d>
</a>
XML;
$xml = simplexml_load_string($string);
echo $xml->asXML(); // <?xml ... <a><b><c>text</c><c>stuff</c> ...
?>
asXML también funciona con resultados Xpath:
Example #2 Usando asXML() en resultados Xpath
<?php
// Continuado a partir del ejemplo XML de arriba.
/* Buscando <a><b><c> */
$result = $xml->xpath('/a/b/c');
while(list( , $node) = each($result)) {
echo $node->asXML(); // <c>text</c> and <c>stuff</c>
}
?>
SimpleXMLElement->asXML
30-Nov-2008 06:48
03-Sep-2008 07:38
Warning: str_repeat() [function.str-repeat]: Second argument has to be greater than or equal to 0
If you're having above error using Awf_Xml change all
$pretty[] = str_repeat(' ', $indent) . $el;
to
$pretty[] = str_repeat(' ', ($indent<0)?0:$indent) . $el;
26-Aug-2008 03:50
DomDocument can do indentation on saveXML, so another way would be:
<?php
$simpleXml = new SimpleXmlElement('...');
// ... do your simple xml construction
$dom = dom_import_simplexml($simpleXml)->ownerDocument;
$dom->formatOutput = true;
echo $dom->saveXML();
?>
not especially better, and probably not faster, but an alternative.
15-Aug-2008 10:19
Another little improvement on Gary Malcolm's original asPrettyXML() and mjijackson's version:
<?php
class Awf_Xml extends SimpleXMLElement {
public function asXml($file=null,$level=4){
// get an array containing each XML element
$xml = explode("\n", preg_replace('/>\s*</', ">\n<", parent::asXML()));
// hold current indentation level
$indent = 0;
// hold the XML segments
$pretty = array();
// shift off opening XML tag if present
if (count($xml) && preg_match('/^<\?\s*xml/', $xml[0])) {
$pretty[] = array_shift($xml);
}
foreach ($xml as $el) {
$line = str_replace(' ','',trim($el));
if(empty($line)){
// There is nothing on this line, so we can skip it;)
continue;
}
if (preg_match('/^<([\w])+[^>\/]*>$/U', $el)) {
// opening tag, increase indent
$pretty[] = str_repeat(' ', $indent) . $el;
$indent += $level;
} else {
if (preg_match('/^<\/.+>$/', $el)) {
// closing tag, decrease indent
$indent -= $level;
$pretty[] = str_repeat(' ', $indent) . $el;
}elseif(preg_match('/^<([\w])+[^>\/]*>.*<\/.+>$/',$el)){
// Open and close on the same line
$pretty[] = str_repeat(' ', $indent) . $el;
}else{
// There is no tag at this line, so we don't want to mess with it's content!
$pretty[] = $el;
}
}
}
$xml = implode("\n", $pretty);
if(!empty($file)){
return (bool)file_put_contents($file,$xml);
}else{
return $xml;
}
}
}
?>
27-May-2008 01:04
A small improvement on Gary Malcolm's original asPrettyXML() method:
<?php
class XMLElement extends SimpleXMLElement
{
/**
* Outputs this element as pretty XML to increase readability.
*
* @param int $level (optional) The number of spaces to use for
* indentation, defaults to 4
* @return string The XML output
* @access public
*/
public function asPrettyXML($level = 4)
{
// get an array containing each XML element
$xml = explode("\n", preg_replace('/>\s*</', ">\n<", $this->asXML()));
// hold current indentation level
$indent = 0;
// hold the XML segments
$pretty = array();
// shift off opening XML tag if present
if (count($xml) && preg_match('/^<\?\s*xml/', $xml[0])) {
$pretty[] = array_shift($xml);
}
foreach ($xml as $el) {
if (preg_match('/^<([\w])+[^>\/]*>$/U', $el)) {
// opening tag, increase indent
$pretty[] = str_repeat(' ', $indent) . $el;
$indent += $level;
} else {
if (preg_match('/^<\/.+>$/', $el)) {
// closing tag, decrease indent
$indent -= $level;
}
$pretty[] = str_repeat(' ', $indent) . $el;
}
}
return implode("\n", $pretty);
}
}
?>
This method will make sure there is an opening XML tag before automatically shifting the first element off the array, thus preserving the correct indentation level when printing child elements instead of entire documents from the root node. It also allows you to pass the indentation level in as a parameter instead of setting the class variable.
27-Nov-2007 10:35
You habe to use utf8_encode() to insert your data into the XML-Object
<?php
$objXMLFile = simplexml_load_string('<users></users>');
$objUser = $objXMLFile->addChild('user');
$objUser->addAttribute('name', utf8_encode('Günther'));
echo $objXMLFile->asXML();
?>
20-Nov-2007 06:15
I think there is a bug while creating files. When I use the UTF-8 charset and use chars like ä,ö,ü the written file is not valid.
So
$xml->asXML("datei.xml");
and
file_put_contents("datei.xml",$xml->asXML());
deliver different results. The second is valid and correct.
Sorry for my english.
13-Sep-2007 07:15
I extended SimpleXml and added this code to give me pleasant source code XML. I'm sure it's ugly so if you can do it better go ahead...
<?php
public function asPrettyXML()
{
$string = $this->asXML();
/**
* put each element on it's own line
*/
$string =preg_replace("/>\s*</",">\n<",$string);
/**
* each element to own array
*/
$xmlArray = explode("\n",$string);
/**
* holds indentation
*/
$currIndent = 0;
/**
* set xml element first by shifting of initial element
*/
$string = array_shift($xmlArray) . "\n";
foreach($xmlArray as $element) {
/** find open only tags... add name to stack, and print to string
* increment currIndent
*/
if (preg_match('/^<([\w])+[^>\/]*>$/U',$element)) {
$string .= str_repeat(' ', $currIndent) . $element . "\n";
$currIndent += self::indent;
}
/**
* find standalone closures, decrement currindent, print to string
*/
elseif ( preg_match('/^<\/.+>$/',$element)) {
$currIndent -= self::indent;
$string .= str_repeat(' ', $currIndent) . $element . "\n";
}
/**
* find open/closed tags on the same line print to string
*/
else {
$string .= str_repeat(' ', $currIndent) . $element . "\n";
}
}
return $string;
}
?>
Regards,
Gary Malcolm
22-Jun-2007 07:27
When trying to use the DOMDocument method for pretty printing the output of asXML be careful how you format the starting XML string. It cannot have spaces or other hidden chars "\n". I also had trouble with using different types of quotes for the starting XML, but I am unable to replicate that. So if you cannot get this to work then you might try swapping the single and double quotes.
<?php
$no_spaces = '<?xml version="1.0" encoding="UTF-8"?><Example></Example>';
$one_space = '<?xml version="1.0" encoding="UTF-8"?><Example> </Example>';
echo printy($no_spaces);
/* Outputs
<?xml version="1.0"?>
<Example>
<poop from="Myself">
<smell>stinky</smell>
</poop>
</Example>
*/
echo printy($one_space);
/* Outputs... note the space...
<?xml version="1.0"?>
<Example> <poop from="Myself"><smell>stinky</smell></poop></Example>
*/
function printy($xmlstr){// a combination from the comments below...
$xml = new SimpleXMLElement($xmlstr);
$poop = $xml->addChild("poop");
$poop->addAttribute("from", "Myself");
$poop->addChild("smell", "stinky");
$doc = new DOMDocument('1.0');
$doc->formatOutput = true;
$domnode = dom_import_simplexml($xml);
$domnode = $doc->importNode($domnode, true);
$domnode = $doc->appendChild($domnode);
return $doc->saveXML();
}
?>
11-May-2007 12:21
Just a note to add onto the previous note: if your xml has already got a "\n" (new line) straight after the opening root tag, then the layout of the rest of the saveXML() will all be on one line, regardless of if you've set formatOutput to true. it's taken me about an hour to figure this out, and i hope this helps someone.
08-Apr-2007 05:39
One simple way to write out nicely indented XML data is by converting the whole batch to a DOM document, and using its formatOutput option:
$doc = new DOMDocument('1.0');
$doc->formatOutput = true;
$domnode = dom_import_simplexml($some_simplexml_node);
$domnode = $doc->importNode($domnode, true);
$domnode = $doc->appendChild($domnode);
echo $doc->saveXML();
06-Mar-2007 02:39
Awww snap. If you are to do something like this:
<?php
// ... You have already read an xml file into a SimpleXMLElement stored in variable $poop
$poop = $simpEle->addChild("poop");
$poop->addAttribute("from", "Myself");
$poop->addChild("smell", "stinky");
file_put_contents("xml.xml", $poop->asXML());
?>
It will add all of the new xml on one line
<poop from="Myself"><smell>stinky</smell></poop>
So when you look at what was originally a nicely tabbed out xml file, it looks like doof. I understand why this happens, so let me just say that it would be awesome if someone wrote and shared function that takes the asXML() string, parses it, and returns a nicely tabbed out version. As a lot of the XML files I work with are smaller than large, the benefit of having a file readable to the human eye far outweights the benefit of having a smaller filesize.
