PHP
downloads | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | conferences | my php.net

search for in the

SimpleXMLElement->addAttribute> <SimpleXML
Last updated: Fri, 10 Oct 2008

view this page in

SimpleXML Functions

Table of Contents



SimpleXMLElement->addAttribute> <SimpleXML
Last updated: Fri, 10 Oct 2008
 
add a note add a note User Contributed Notes
SimpleXML Functions
phplasma at gmail dot com
15-Sep-2008 03:35
"I found simpleXML to be useful only in cases where the XML was extremely small, otherwise the server would run out of memory (I suspect there is a memory leak or something?)."

This appears for me in PHP 5.1.6 cli when you 'foreach' over elements.

Use a 'for' loop instead.
mario
02-Sep-2008 10:08
If you want CDATA in your object you should use LIBXML_NOCDATA

<?php
$xml
= simplexml_load_file($file_xml, 'SimpleXMLElement',LIBXML_NOCDATA);
   
   
print_r($xml);
?>
james dot ellis at gmail dot com
29-Aug-2008 02:55
While SimpleXML is a powerful tool, developers using it to process and handle large XML documents & strings should take into careful consideration its memory usage requirements.
SimpleXML requires the entire XML tree to be available prior to any processing actions on that tree -- this requires the entire tree to be in memory. Ok for a 40kb XML file but when dealing with > 100MB files you will see performance degradation, especially if you have a busy server.

An alternative to processing large XML files is the XMLReader class, which operates in streaming mode, of which an excellent tutorial is presented here:
http://www.ibm.com/developerworks/library/x-pullparsingphp.html

XML is an incredibly verbose format. If you are dealing with large data structures, especially in web services, do you you actually need to represent the data as an XML tree? - other serialisation formats such as JSON, Serialised PHP, Google Protocol Buffers (http://code.google.com/p/protobuf/) and even CSV can remarkably reduce processing time, bandwidth and load  when dealing with large files. A 110MB XML file can become a 65MB CSV file, with the same data in it, simply because the data identifiers (tags) are only represented once in the entire document.
clarke DOT chris at googley mail DOT com
26-Jul-2008 04:33
For clarification, finding attributes seems easier this way, hope I'm not being redundant.

Source XML:
<?xml version="1.0" encoding="ISO-8859-1"?>
<note>
<to>Tove</to>
<from>Jani</from>
<heading>Reminder</heading>
<body type="small" important="low">Don't forget me this weekend!</body>
</note>

Code Example:
<?php
$xml
= simplexml_load_file("test.xml");
print
$xml->body['type'];
?>

Output:
small
rowan dot collins at gmail dot com
10-Jul-2008 03:07
There seems to be a lot of talk about SimpleXML having a "problem" with CDATA, and writing functions to rip it out, etc. I thought so too, at first, but it's actually behaving just fine under PHP 5.2.6

The key is noted above example #6 here:
http://uk2.php.net/manual/en/simplexml.examples.php

"To compare an element or attribute with a string or pass it into a function that requires a string, you must cast it to a string using (string). Otherwise, PHP treats the element as an object."

If a tag contains CDATA, SimpleXML remembers that fact, by representing it separately from the string content of the element. So some functions, including print_r(), might not show what you expect. But if you explicitly cast to a string, you get the whole content.

<?php
$xml
= simplexml_load_string('<foo>Text1 &amp; XML entities</foo>');
print_r($xml);
/*
SimpleXMLElement Object
(
    [0] => Text1 & XML entities
)
*/

$xml2 = simplexml_load_string('<foo><![CDATA[Text2 & raw data]]></foo>');
print_r($xml2);
/*
SimpleXMLElement Object
(
)
*/
// Where's my CDATA?

// Let's try explicit casts
print_r( (string)$xml );
print_r( (string)$xml2 );
/*
Text1 & XML entities
Text2 & raw data
*/
// Much better
?>
erudd at netfor dot com
13-Jun-2008 09:10
Entity Oddities.

in reply to m0sh3 at hotmail dot com

This bug was fixed in PHP 5.2.6 (#44478)

However beware that the addChild method require input to be entity encoded.  IE. you can NOT input "one & two" you have to input "one &amp; two".

Assigning directly (aside from the bug fixed in 5.2.6) does not have this requirement.
SmartD
11-Jun-2008 04:40
A small 'n nice function to extract an XML and return it as an array. If there is a bug, please let me know here. I testet it for my purposes and it works.

<?php

public function extractXML($xml) {
       
if (!(
$xml->children())) {
    return (string)
$xml;
}
       
foreach (
$xml->children() as $child) {
   
$name=$child->getName();
    if (
count($xml->$name)==1) {
       
$element[$name] = $this->extractXML($child);
    } else {
       
$element[][$name] = $this->extractXML($child);
    }
}

return
$element;   
}

// you can call it this way

$xml = false;

$xml = @simplexml_load_string($xmlstring);

// 1)

if ($xml) {
 
$array = extractXML($xml);
}  else {
 
$array = false;
}

// 2)

if ($xml) {
 
$array[$xml->getName()] = extractXML($xml);
}  else {
 
$array = false;
}

?>
m0sh3 at hotmail dot com
22-May-2008 11:24
Be aware of quirks like this one:

<?php

$a
= new SimpleXMLElement('<a><b/></a>');

$a->b = 'test &amp; test';
$a->c = 'test &amp; test';

print_r($a);
/*
OUTPUT:

SimpleXMLElement Object
(
    [b] => test & test
    [c] => test &amp; test
)
*/
pc_storm at abv dot bg
20-May-2008 01:16
You can avoid easily, the unpredictable destruction of $_SESSION when loading a simple_xml object (which occurs under _some_ PHP versions) by serializing and unserializing it:

<?php
$oldsession
=serialize($_SESSION);
$myxml=@simplexml_load_file('my.xml');
$_SESSION=unserialize($oldsession);
unset (
$oldsession);
?>

This worked for me under PHP 5.2.5 while on 5.1.6 there was no need for such workaround at all.

Same workaround should help if there are other superglobals affected by this bug...
kyle at codeincarnate dot com
22-Apr-2008 01:28
A looked through a lot of the sample code for reading XML files with CDATA, but they didn't work out that well for me.  However, I found that the following piece of code worked perfectly for reading through a file using lots of CDATA.

<?php
$article_string
= file_get_contents($path);
$article_string = preg_replace_callback('/<!\[CDATA\[(.*)\]\]>/', 'filter_xml', $article_string);
$article_xml = simplexml_load_string($article_string); 

function
filter_xml($matches) {
    return
trim(htmlspecialchars($matches[1]));
}

?>
spambegone at cratemedia dot com
21-Apr-2008 07:39
I found simpleXML to be useful only in cases where the XML was extremely small, otherwise the server would run out of memory (I suspect there is a memory leak or something?). So while searching for alternative parsers, I decided to try a simpler approach. I don't know how this compares with cpu usage, but I know it works with large XML structures. This is more a manual method, but it works for me since I always know what structure of data I will be receiving.

Essentially I just preg_match() unique nodes to find the values I am looking for, or I preg_match_all to find multiple nodes. This puts the results in an array and I can then process this data as I please.

I was unhappy though, that preg_match_all() stores the data twice (requiring twice the memory), one array for all the full pattern matches, and one array for all the sub pattern matches. You could probably write your own function that overcame this. But for now this works for me, and I hope it saves someone else some time as well.

// SAMPLE XML
<RETS ReplyCode="0" ReplyText="Operation Successful">
  <COUNT Records="14" />
  <DELIMITER value="09" />
  <COLUMNS>PropertyID</COLUMNS>
  <DATA>521897</DATA>
  <DATA>677208</DATA>
  <DATA>686037</DATA>
</RETS>

<?PHP

// SAMPLE FUNCTION
function parse_xml($xml) {
   
   
   
// GET DELIMITER (single instance)
   
$match_res = preg_match('/<DELIMITER value ?= ?"(.*)" ?\/>/', $xml, $matches);
    if(!empty(
$matches[1])) {
       
$results["delimiter"] = chr($matches[1]);
    } else {
       
// DEFAULT DELIMITER
       
$results["delimiter"] = "\t";
    }
    unset(
$match_res, $matches);
   
   
   
// GET MULTIPLE DATA NODES (multiple instances)
   
$results["data_count"] = preg_match_all("/<DATA>(.*)<\/DATA>/", $xml, $matches);
   
// GET MATCHES OF SUB PATTERN, DISCARD THE REST
   
$results["data"]=$matches[1];
    unset(
$match_res, $matches);
   
   
// UNSET XML TO SAVE MEMORY (should unset outside the function as well)
   
unset($xml);

   
// RETURN RESULTS ARRAY
   
return $results;
   
   
}

?>
nathan at gimpstraw dot com
05-Apr-2008 06:43
I'm using SimpleXML to process data sent back from an API request, and I ran into the CDATA problem and the error you get from html entities, and here is a solution i came up with, don't know if it's the most practical, but it's working.

<?php
$str
= <<< XML
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<menu>
    <item>
        <title><![CDATA[Caf&eacute;]]></title>
        <description><![CDATA[Some description.]]></description>
    </item>
</menu>
XML;

$str = preg_replace("/\<\!\[CDATA\[(.*?)\]\]\>/ies", "'[CDATA]'.base64_encode('$1').'[/CDATA]'", $str);
$xml = new SimpleXMLElement($str);

// Return item title's
foreach ($xml->item as $item) {
   
$tmp = (string) $item->title;
   
$tmp = preg_replace("/\[CDATA\](.*?)\[\/CDATA\]/ies", "base64_decode('$1')", $tmp);
    echo
$tmp;
}
?>
l [DOT] anzinger [AT] gmail [DOT] com
26-Mar-2008 05:03
If you don't want that the CDATA values get escaped, just load the XML with LIBXML_NOCDATA as an 3rd argument.

Note: A PHP version >= 5.1.0 is required for this to work.

Example:

<?php simplexml_load_file('xmldatei.xml', null, LIBXML_NOCDATA); ?>
ngkongs at gmail dot com
19-Mar-2008 06:44
fix the function i posted before, have a wrong quote placement

function implode2($glue="", $var){
    if ($var){
        foreach ($var as $value){
            $array[]=strval($value);
        }
        return implode($glue, $array);
    }
    else return false;
}
ngkongs at gmail dot com
19-Mar-2008 06:39
implode() can't be used for simplexml's array but foreach() does the thing, make new implode function with foreach() will resolve this problem. use strval() to reset SimpleXMLElement object to a simple string variable.

function simplexml_implode ($glue="", $var){
    if ($var){
        foreach ($var as $value){
            $array[]=strval($value);
        }
    } return implode($glue, $array);
    else return false;
}
kristopherwilson at gmail dot com
12-Mar-2008 01:47
I believe the "proper" solution to wyzzard's problem is:

var_dump( $Hsp->{"Hsp_query-from"} );
wyzzard at wp dot pl
05-Mar-2008 12:33
Consider following php code:

$xml=<<<HSPXML
<Hsp>
<Hsp_query-from>10</Hsp_query-from>
</Hsp>
HSPXML;

$Hsp = new SimpleXMLElement($xml);

//You can't simply access Hsp_query-form element because '-' is PHP's operator
var_dump($Hsp->Hsp_query-from);
var_dump($Hsp["Hsp_query-from"]);
var_dump(array_key_exists("Hsp_query-from" , $Hsp));

//Prints:
/*
int(0)
NULL
bool(true)
*/

//so the key exists! but is inaccessible with[] (and {})
//Way around is to create an additional array:

$hsp_array = array();
foreach($Hsp as $key=>$value)
{
    $hsp_array[$key]=$value;
}

var_dump($hsp_array["Hsp_query-from"]);

//the proper result:

object(SimpleXMLElement)#3 (1) {
  [0]=>
  string(2) "10"
}

produced PHP 5.2.5, Windows, Wamp 2.0
david at davidkmuir dot com
25-Feb-2008 03:22
mtudor: It is not worth including in the documentation, as it works exactly as expected.

Using Vegar's XML example (slightly modified):

<?php

$xml
="<doc>
  <multi attr1='one' attr2='two' attr3='three'>One</multi>
  <multi>Two</multi>
</doc>"
;

$xml = new SimpleXMLElement($xml);

echo
count($xml->multi); //returns 2
echo count($xml->multi->attributes()); //returns 3
echo count($xml->multi[0]->attributes()); //returns 3
echo count($xml->multi[1]->attributes()); //returns 0

?>

So the only part that may throw people off is the fact that if an array key is not given, it will assume the first element. This should however be obvious since you work from this assumption whenever referring to a single element:

<?php

$xml
="<doc>
  <single>
      <tag>A Tag</tag>
  </single>
</doc>"
;

$xml = new SimpleXMLElement($xml);

echo
$xml->single[0]->tag[0]; //returns 'A Tag'
echo $xml->single->tag; //returns 'A Tag'

?>
maxim [at] novozhilov dot kiev dot ua
23-Feb-2008 06:12
One more comment to Jason's XMLToArray function. The best and right way, which I found for multidimensional arrays and tags with the same names is this hook(see method convert). This will right save all data in right array without losing first element of same_nodes_name (this happens when we find first element, saves it and when find later one more with the same_nodes_name, we need to recreate array to save old data in [0] element of new array, otherwise our first element will be outside of array /see my previous post/). Also I made this little class for facility.

final class XMLToArray {

    public function parse($xml) {
        return $this->convert(simplexml_load_string($xml));
    }

    function convert($xml) {
        if ($xml instanceof SimpleXMLElement) {
            $children = $xml->children();
            $return = null;
        }

        foreach ($children as $element => $value) {
            if ($value instanceof SimpleXMLElement) {
                $values = (array)$value->children();

                if (count($values) > 0) {
                    if (is_array($return[$element])) {
                        //hook
                        foreach ($return[$element] as $k=>$v) {
                            if (!is_int($k)) {
                                $return[$element][0][$k] = $v;
                                unset($return[$element][$k]);
                            }
                        }
                        $return[$element][] = $this->convert($value);
                    } else {
                        $return[$element] = $this->convert($value);
                    }
                } else {
                    if (!isset($return[$element])) {
                        $return[$element] = (string)$value;
                    } else {
                        if (!is_array($return[$element])) {
                            $return[$element] = array($return[$element], (string)$value);
                        } else {
                            $return[$element][] = (string)$value;
                        }
                    }
                }
            }
        }

        if (is_array($return)) {
            return $return;
        } else {
            return false;
        }
    }
}
maxim [at] novozhilov dot kiev dot ua
22-Feb-2008 11:30
As for Jason Sheets <jsheets at shadonet dot com> function - very good function, thanks for work! I've made only some changes in recursion to allow same_nodes_name support, like this one:

<node2>
   <node3>
      <node4>test</node4>
      <node4>test1</node4>
   </node3>
   <node5/>
</node2>

this hack allows you to have in array both "node4".
Simply remove line:

$return[$element] = XMLToArray($value);

and add this one

(!isset($return[$element])) ? $return[$element] = XMLToArray($value) : $return[$element][] = XMLToArray($value);
essen at dev-extend dot eu
21-Feb-2008 11:42
SimpleXMLElement is tricky to extend, because -> is overloaded and prevents you to set and use properties. So you can only add methods.

There is a trick to do it however, by extending SimpleXMLElement (or SimpleXMLIterator too), described in this blog post:
http://blog.extend.ws/2008/02/20/extending-simplexml/
paulyg76 at NOSPAM dot gmail dot com
19-Feb-2008 02:39
Be careful using nested SimpleXML objects in double quoted strings.

<?php
$xmlstring
= '<root><node>123</node><foo><bar>456</bar></foo></root>';

$root = simplexml_load_string($xmlstring);

echo
"Node is: $root->node"; // Works: Node is 123
echo "Bar is: $root->foo->bar"; // Doesn't work, outputs: Bar is: ->bar
// use curly brackets to fix
echo "Bar is: {$root->foo->bar}"; // Works: Bar is 456

?>
philippe_marc_--a---t--_novartis_com
12-Feb-2008 05:46
TIP: if you run into memory issue using simpleXML.
You may want to use PHP>5.2.5 in order to avoid that: http://bugs.php.net/bug.php?id=38604
If not possible, avoid "foreach ( $xmldata->node as $node )" like calls.
amir_abiri at ipcmedia dot com
08-Feb-2008 04:47
It doesn't seem to be documented anywhere, but you can refer to an element "value" for the purpose of changing it like so:

<?php
$xml
= simplexml_load_string('<root><number>1</number></root>');
echo
$xml->asXml(). "\n\n";

$xml->number->{0} = $xml->number->{0} + 1;

echo
$xml->asXml();
?>

echos:
<?xml version="1.0"?>
<root><number>1</number></root>

<?xml version="1.0"?>
<root><number>2</number></root>

However, this only works with a direct assignment, not with any of the other operators:

<?php
$xml
= simplexml_load_string('<root><number>1</number></root>');
echo
$xml->asXml(). "\n\n";

$xml->number->{0} += 1;
// Or:
$xml->number->{0}++;

echo
$xml->asXml();
?>

Both of the above cases would result in:

<?xml version="1.0"?>
<root><number>1</number></root>

<?xml version="1.0"?>
<root><number>1<0/></number></root>
bojan
04-Feb-2008 12:38
As was said before don't use var_dump() or print_r() to see SimpleXML object structure as they do not returns always what you expect.
Consider the following:

<?php

// data in xml
$xml_txt = '
<root>
  <folder ID="65" active="1" permission="1"><![CDATA[aaaa]]></folder>
  <folder ID="65" active="1" permission="1"><![CDATA[bbbb]]></folder>
</root>'
;

// load xml into SimpleXML object
$xml = simplexml_load_string($xml_txt, 'SimpleXMLElement', LIBXML_NOCDATA);//LIBXML_NOCDATA LIBXML_NOWARNING

// see object structure
print_r($xml);

/* this prints
SimpleXMLElement Object
(
    [folder] => Array
        (
            [0] => aaaa
            [1] => bbbb
        )

)
*/

// but...
foreach ($xml->folder as $value){
   
print_r($value);
}
/* prints complete structure of each folder element:
SimpleXMLElement Object
(
    [@attributes] => Array
        (
            [ID] => 65
            [active] => 1
            [permission] => 1
        )

    [0] => aaaa
)

SimpleXMLElement Object
(
    [@attributes] => Array
        (
            [ID] => 65
            [active] => 1
            [permission] => 1
        )

    [0] => bbbb
)

*/
?>
mtudor at N0SPMicefusion dot co dot uk
23-Jan-2008 11:50
Be careful when trying to access a repeated xml tag such as in the example below:
<?php
$xmlText
= "<test>
  <group>
    <multi>One</multi>
    <multi>Two</multi>
  </group>
</test>"
;

$xml = new SimpleXMLElement($xmlText);
?>

SimpleXML will convert this into an object as follows:

SimpleXMLElement Object
(
    [group] => SimpleXMLElement Object
        (
            [multi] => Array
                (
                    [0] => One
                    [1] => Two
                )
        )
)

From this, you may think as I did, that the following snippet will yield an Array with two elements:

<?php
print_r
($xml->group->multi)
?>

What actually happens is that SimpleXMLElement assumes that you want the first element in the array, so the above snippet will actually return:

SimpleXMLElement Object
(
  [0] => One
)

Accessing using Array notation:
<?php
print_r
($xml->group->multi[1]);
?>

Will return:

SimpleXMLElement Object
(
  [0] => Two
)

as would be expected.  It seems that SimpleXML has a mechanism to determine whether or not you are using Array notation and if not, returning the first element of the array.

Unfortunately, this is a real problem for using functions such as count() and is_array().  is_array($xml->group->multi) will actually return false, as you are actually testing against the first element of the multi array, wrapped in a SimpleXMLElement object.

The solution, it would seem, is one of the following:

1. Access the element using xpath, which returns an array that can be counted and edited etc.:
<?php
print_r
($xml->group->xpath("multi"));
?>

2. Use isset to detect if array index 1 is present:
<?php
if(isset($xml->group->multi[1]))
{
  echo
"The XML has more than one multi element";
}
?>

See http://vega.rd.no/article/simplexml-not-that-simple for further information.

I wonder if it might be worth including this in the body of the documentation, as it is quite a big gotcha?
andrvm
02-Jan-2008 11:01
<?php
/**
    * Remove node/nodes xml with xpath
    *
    * @param SimpleXMLElement                 $xml
    * @param string XPath                     $path
    * @param string ('one'|'child'|'all')     $multi
    *
    * Use:
    *
    * Example xml file - http://ru2.php.net/manual/ru/ref.simplexml.php
    *
    * $xml = simplexml_load_file($xmlfile);
    *
    * //1. remove only 1 node (without child nodes)
    * //   $path must return only 1 (unique) node without child nodes
    * removeNode($xml, '//movie/rating[@type="thumbs"]');
    *
    * //2. remove 1 node (with 1 child nodes)
    * //    $path can return any nodes - will be removed only first node
    * //   with all child nodes
    * removeNode($xml, '//characters', 'child')
    *
    * //3. remove all nodes (with child nodes)
    * //   $path can return any nodes - will be removed all
    * //   with child nodes
    * removeNode($xml, '//rating', 'all')
    *
    * $xml->asXML($xmlfile);
    *
    */
  
function removeNode($xml, $path, $multi='one')
   {
      
$result = $xml->xpath($path);
                
         
# for wrong $path
         
if (!isset($result[0])) return false;
        
          switch (
$multi) {
              case
'all':
                   
$errlevel = error_reporting(E_ALL & ~E_WARNING);
                    foreach (
$result as $r) unset ($r[0]);
                   
error_reporting($errlevel);
                    return
true;
                   
                case
'child':
                   unset(
$result[0][0]);
                   return
true;
                
                case
'one':
                   if (
count($result[0]->children())==0 && count($result)==1) {
                       unset(
$result[0][0]);
                       return
true;
                   }
                  
                default:
                      return
false;            
          }
 } 
?>

p.s. after use (if deleted all nodes):
<?php

  
function trimXml($xmlfile)
   {
      
$dom = new DOMDocument();
       
         
$dom->preserveWhiteSpace = false;
     
         if (!
$dom->load($xmlfile)) return false;
     
        
$dom->formatOutput = true;
     
         if (!
$dom->save($xmlfile)) return false;
       
         return
true;
   }
?>
tom at canobe dot com
02-Jan-2008 08:46
The earlier poster is right in that simplexml becomes pretty useless when you have mixed-content XML. This means that you basically cant use simplexml for (X)HTML, which is a bit of a blow.

Here's a potential solution (hack) for those of you just finding out the mixed-content problem and not wanting to rewrite using DOM. This probably only really works if you have well-formed xhtml, which in my case I have from running some html through Tidy beforehand.

Before passing to simplexml, run a couple of regexs on the html to put all the mixed content inside <span>s. This gets handled as separate elements in the tree.

// put all text content inside a <span> because simplexmlelement
// doesnt handle mixed content.
// lesson learnt: dont use simplexmlelement for html
$html = preg_replace('|>\s*<|','><',$html);
$html = preg_replace('|>\s*([^<]+)\s*|','><span>\1</span>',$html);
onPHP5.com
19-Nov-2007 02:49
For more info regarding encodings in SimpleXML and DOM, please visit http://www.onphp5.com/article/57
onPHP5.com
18-Nov-2007 12:37
It does not say in the docs, but SimpleXML will convert all text into UTF-8, if the source XML declaration has another encoding. Eg, if the source has the following XML decl:

<?xml version="1.0" encoding="windows-1251" ?>

all the text in the resulting SimpleXMLElement will be in UTF-8 automatically.
jevon at jevon dot org
09-Nov-2007 02:14
If you want to compare two XML documents for loose equality -- i.e. they both have the same attributes, children and text content, over all namespaces -- then you can use the function provided below.

I don't know of any easier way to do this -- it would make sense to be part of the SimpleXML extension, I'm sure.

<?php
$xml1
= new SimpleXMLElement(file_get_contents('file1.xml'));
$xml2 = new SimpleXMLElement(file_get_contents('file2.xml'));
$result = xml_is_equal($xml1, $xml2);
if (
$result === true) {
  
// the XML documents are the same
} else {
  
// they are different: print the reason why
  
printf(STDERR, "XML documents are different: $result");
}
?>

xml_is_equal() source: http://www.jevon.org/wiki/Comparing_Two_SimpleXML_Documents
David
31-Oct-2007 03:32
This function could be useful to somebody if you want to insert an XML into another when building an XML from many different files.
Note that you must specify a name for the node in which the child files content/node will be inserted :

foreach (xxx as $firstCondition){
    $xml_parent = simplexml_load_file("$firstCondition.xml");
    foreach (yyy as $secondCondition){
    $xml_children = simplexml_load_file("secondCondition.xml");

    SimpleXMLElementObj_into_xml($xml_parent , $xml_children , 'linkingNode'); //will insert every nodes of the files at the end of the parent_xml
}    }

function SimpleXMLElementObj_into_xml($xml_parent, $xml_children, $linkingNode= "linkingNode" , $child_count = 0 , $xml = false ){
    if(!$xml)    {
        $xml = $xml_parent->addChild($linkingNode);
    }else{
        $xml = $xml_parent[$child_count];
    }
    $child_count = 0;
    foreach($xml_children->children() as $k => $v)    {
        if($xml->$k){
            $child_count++;
        }
        if($v->children())        {
            $xml->addChild($k);
            SimpleXMLElementObj_into_xml($xml->$k, $v, '', $child_count, true);
        }else{
            $xml->addChild($k, $v);
        }
    }
    return $xml;
}

Thanks to some contributor whom I've taken the structure of this function.
lordi at msdi dot ca
23-Oct-2007 01:35
If you need to do math calculations on values extracted from simplexml document, you might need to cast the value as float to prevent precision loss. Here is an example:

<?
    $objXML
= new SimpleXMLElement('<test x="-123.45"></test>');
   
   
//Shows correctly
   
echo $objXML['x']."\n";
   
   
//We loose the decimals
   
echo $objXML['x'] + $objXML['x']."\n";
   
   
$x = $objXML['x'];
   
   
//This works if we cast the amounts
   
echo (float)$objXML['x'] + (float)$objXML['x']."\n";
   
   
//Calculated on a string, no problem
   
echo "-123.45" + "-123.45";
   
?>

This is due to the fact that $objXML['x'] is not a string (php would cast it automatically) neither a float, but a SimpleXMLElement object.

"echo var_dump($x);" will output this
~~
object(SimpleXMLElement)#3 (1) {
  [0]=>
  string(7) "-123.45"
}
~~

I opened a bug request on php but here is the answer they gave me:

~~
Status: Won't fix

The behavior is defined by the engine not the extension. When performing mathematical operations on objects, they are treated as integers. It is up to the user to cast the object to the appropriate type to maintain proper precision.
~~
http://menic.info
29-Aug-2007 02:04
@Leonid Kogan:

Your script is not working in all cases. It has problem with non-uniques elements, ie:
<?php     $array = array( 'root' => array( 'first' => array( 'value', 'other' ) ) );?>

In XML it should looks like this:
<root>
  <first>value</first>
  <first>other</first>
</root>

But it will looks:

<root>
  <first>
    <1>value</1>
    <2>other</2>
  </first>
</root>

which is wrong.
cmsa at gmx dot de
27-Aug-2007 01:07
I had a problem with entities.

My first solution:
I saved Data that way:
$ENTRY_->
addchild('Nachricht',htmlentities($_POST["blog"]));

Had Entities in the XML-File like:
<!ENTITY auml "&amp;auml">

And I loaded the Data that way:
html_entity_decode($ENTRY->Nachname);

But after saving and
loading the xml-file the entity-entry
<!ENTITY auml "&amp;auml">
disappeared. strange...

My second solution:
With saving the Data this way:
$ENTRY_->
addchild('Nachricht',htmlentities(htmlentities($_POST["blog"])));

I can now load it with html_entity_decode without the
 entity-entry in the XML-file!
I tested it with äöü.

Hope it helpes.
darkstream777 at gmx dot net
26-Aug-2007 03:29
You dont need a function named "fixCDATA".
Work with "htmlentities" and "html_entity_decode" is
better.

A short example:
$xml->addChild($key, "<![CDATA[".htmlentities($value)."]]>");
print_r((html_entity_decode($files_xml->asXML())));

Greetings S.P. aka darki777
Josh Sowin (fireandknowledge.org)
22-Aug-2007 03:40
You can't use CDATA with SimpleXML, but there is a way around it. Wrap your child in CDATA like this:

<? $listing->addChild( 'description', '<![CDATA[' . $row['description'] . ']]>' ); ?>

And then when you display the XML, run it through this function:

<?

function fixCDATA($string) {
   
$find[]     = '&lt;![CDATA[';
   
$replace[] = '<![CDATA[';
   
   
$find[]     = ']]&gt;';
   
$replace[] = ']]>';

    return
$string = str_replace($find, $replace, $string);
}

$xml = fixCDATA( $xml->asXML() );
echo
$xml;

?>
karsten dot bruch at bms-verlage dot de
16-Aug-2007 04:28
When creating a new XML document and adding text with umlauts and such
$SimpleXMLElement->asXML();
will silently NOT output any content with umlauts.

Use htmlentities () while adding Umlauts & co to solve the "problem"
Leonid Kogan
16-Aug-2007 10:10
if you want to export an array as xml you can use this script

<?php
$test
=array("TEST"=>"nurso",
       
"none"=>null,
       
"a"=>"b",
        array(
           
"c"=>"d",
            array(
"d"=>"e")));
$xml=array_to_simplexml($test);
print->(
$xml);
print_r($xml->asXML());
function
array_to_simplexml($array, $name="config" ,&$xml=null )
{
    if(
is_null($xml))
    {
       
$xml = new SimpleXMLElement("<{$name}/>");
    }
   
    foreach(
$array as $key => $value)
    {
        if(
is_array($value))
        {
           
$xml->addChild($key);
           
array_to_simplexml($value, $name, $xml->$key);
        }
        else
        {
           
$xml->addChild($key, $value);
        }
    }
    return
$xml;
}
?>
anthony dot parsons at manx dot net
04-Aug-2007 03:40
If you're handling lots of HTML or mixed-content XML you'll probably want to use the DOM functions instead of SimpleXML. Take this for example:
<?php
$html
= new SimpleXMLElement('<div><p>Some text, <a href="#">a link,</a> more text</p></div>');

echo
$html->p->a,"<br>\n"; // "a link,"
echo $html->p;             // "Some text, more text" (!)
?>
In the above example reconstructing the original markup is impossible because of the way SimpleXML represents the data.
php dot net at cashers dot de
04-Aug-2007 01:49
For the poor users who can only use a PHP4 solution, there are some alternatives to it like minixml or my simple php class called sxml which runs with php5 as well as with php4: http://www.shop24-7.info/32-0-simplexml-alternative-php4.html
It is easy to modify and has a clear structure. The result of the class is an array which owns the xml file's data.
have fun with it
jebner at computacenter dot com
24-Jul-2007 03:41
When using Apache & PHP on windows and you try to do a direct typecast to string or integer of your SimpleXMLElement objects, your Apache MAY crash  (mine did :-( ).

would look like this:

$id = (int)$xml->id;

so try other things like firts converting it to a string  with strval() NOT direct typecast - this won't work neither.

seems like direct typecast doesnt work on objects (doesn' suprise me very much)
julien plee using G mail dot com
19-Jul-2007 11:45
<to bens at effortlessis dot com>

I see your problem, but there's a workaround.
After loading your SimpleXML object into $xml, call $xml->getName  () and you'll get your root tag name.

I use PHP 5.1.4 on Apache 1.3.33 on MacOS X and this works on it. I hope there was no SimpleXML ability downgrading :o)

Also, I kinda remember reading somewhere in this doc an advise saying "Don't use data structures parsers like var_dump() on SimpleXML." This may be the reason. And you may will work your second problem around using SimpleXMLElement->attributes() and SimpleXMLElement->getName ().
bens at effortlessis dot com
18-Jul-2007 09:58
Data can be lost when using SimpleXML!!! Consider the following XML:

<root position="base">
 <edition id="20070705" onsale="2007-07-06" online="2007-07-06 09:00">
  <headline maxchars="50" someattr="whatever">
   <cell attr="meaningless">The new issue</cell>
  </headline>
 </edition>
 <monkey id="123">
  <face class="round">red</face>
  <face class="square">pink</face>
 </monkey>
</root>

parsed as follows

$res = simplexml_load_string($xml);
print_r($res);

1) The name of the first (root?) tag of the document is lost - there is no way to find out what the root tag was called. (in this case, I called it "root") However, the attributes within that tag are preserved. (position="base")

2) The innermost tag's attributes are lost.  (apparently, any tag with data in it) Note that attr='meaningless' in the cell tag, as well as the class="square"/"round" is lost.

This is when using PHP 5.1.6 on Fedora Core 6 with stock RPMs.
mail at jezz dot dk
05-Jul-2007 02:23
Correct me if I'm wrong, but I think the output of the SimpleXMLElement Object is dependent on the PHP version. Consider this code:

$xml = '<edition id="20070705" onsale="2007-07-06" online="2007-07-06 09:00">
            <headline maxchars="50">The new issue</headline>
        </edition>';
$res = simplexml_load_string($xml);
print("<pre>");
print_r($res);
print("</pre>");

PHP version 5.0.4 will return this:

SimpleXMLElement Object
(
    [headline] => The new issue
)

While PHP version 5.2.1 returns (some) attributes as well:

SimpleXMLElement Object
(
    [@attributes] => Array
        (
            [id] => 20070705
            [onsale] => 2007-07-06
            [online] => 2007-07-06 09:00
        )

    [headline] => The new issue
)
judas dot iscariote at gmail dot com
16-Jun-2007 05:27
In response to webmaster at mavoric dot net comment.

It is a complete non-sense to use include() to retrieve an external RSS feed, remember that include is intented to **parse and execute PHP code** and an RSS feed is, quite obivously, **not** PHP code.

people that wants to read external resources should use file_get_contents, fopen or an SplFileObject, never **ever** use include() with remote resources.
webmaster at mavoric dot net
05-Jun-2007 04:26
If you are using the above examples to get at external XML/RSS files and are encountering errors, you need to understand that PHP Version 5.2.3 + forbids the use of using include to get at external XML/RSS files . You need to change the start of the code slightly...

<?php
$url
= 'http://www.a_external_site.com/example.xml';

$rss_file = file_get_contents($url);

$xml = new SimpleXMLElement($rss_file);

echo
$xml->movie[0]->plot; // "So this language. It's like..."
?>

Just replace the first two lines of the exsisting code with the first two of the above code.
nicolas at lehuen dot com
30-Apr-2007 10:55
I've implemented a XML Pull Parser for PHP 5 that somewhat mimics SimpleXML - but doesn't need to load the whole document in memory :

http://tinyurl.com/2e9ew5
http://methylblue.com
09-Apr-2007 01:14
It is a grave misfortune that this doesn't work:

<?
  $node
= new SimpleXml;
  echo
$node->{"namespace:tagname"}[attribute'];
?>

Instead you have to go through loops!

<?
  $namespace = $node->children( '
namespace' );
  $attributes = $namespace->tagname->attributes;
  echo $attribute['
attribute];
?>

AFAICT there is no simpler way. SimpleXml is great in premise, but useless for things like RSS feeds, which lets face it, most PHP development with XML is about.

Great shame!
php at werner dash ott dot de
29-Mar-2007 10:13
Making SimpleXMLElement objects session save.

Besides the effect of not surviving sessions, the SimpleXMLElement object may even crash the session_start() function when trying to re-enter the session!

To come up with a solution for this, I used a pattern as follows. The core idea is to transform the SimpleXMLElement between session calls to and from a string representation which of course is session save.

<?php
 
//
  // session save handling of SimpleXMLElement objects
  // (applies to/ tested with PHP 5.1.5 and PHP 5.2.1)
  // The myClass pattern allows for conveniently accessing
  // XML structures while being session save
  //
 
class myClass
 
{
    private
$o_XMLconfig = null;
    private
$s_XMLconfig = '';
   
    public function
__construct($args_configfile)
    {
     
$this->o_XMLconfig = simplexml_load_file($args_configfile);
     
$this->s_XMLconfig = $this->o_XMLconfig->asXML();
    }
// __construct()
   
   
public function __destruct()
    {
     
$this->s_XMLconfig = $this->o_XMLconfig->asXML();
      unset(
$this->o_XMLconfig); // this object would otherwise crash
                                 // the subsequent call of
                                 // session_start()!
   
} // __destruct()
   
   
public function __wakeup()
    {
     
$this->o_XMLconfig = simplexml_load_string($this->s_XMLconfig);
    }
// __wakeup()
   
 
} // class myClass
?>
php at werner dash ott dot de
28-Mar-2007 03:03
Concerning SimpleXML and sessions:

When creating a SimpleXML object (to be precise: a SimpleXMLElement object) in the context of a session and storing it in $_SESSION['XMLobject'], this object does not "survive" the session!

By the time re-entering the session, print_r($_SESSION['XMLobject']) says:

['XMLobject'] => SimpleXMLElement Object
Warning:  Node no longer exists in /your_php_file.php on line xyz
   (
   )

(Message simplified for the sake of better readability.)
codje2 at lboro dot ac dot uk
11-Mar-2007 09:46
Sometimes it's nice to mix up data storage types. This is a very simple SQL to XML converter. Feed it a SQL query and it outputs the result in XML.

The first paramater should be a mysql_query result
(optional)The second is the xml name for each row (i.e the second depth of XML)
(optional)The third is the name of the XML document, the root name

<?php
$result
=mysql_query("SELECT * FROM users");
sql_to_xml($result,"users","members");

function
sql_to_xml($mysql_result,$row_name="row",$doc_name="root")
{
   
   
$xml= new SimpleXMLElement("<$doc_name></$doc_name>");
    while(
$line=mysql_fetch_assoc($mysql_result))
    {
       
$row=$xml->addChild($row_name);
        foreach(
$line as $column => $value)
        {
           
$row->$column="$value";
        }
    }
    return
$xml->asXML();
}

?>
php at NOSPAM dot coutch dot com
21-Feb-2007 10:04
Memory leak when setting attributes as in example (#Example 2134. Setting values)

This probably goes unnoticed in web scripts (unless you do a LOT of xml manipulations), but I ran into this in my standalone script that processes a large number of XML files.

The following code will eat up memory quite fast:

<?php
include 'example.php';

while (
true) {
 
$xml = new SimpleXMLElement($xmlstr);
 
$xml->movie[0]->characters->character[0]->name = 'Miss Coder';
}
?>

while this seems to behave correctly:

<?php
include 'example.php';

while (
true) {
 
$xml = new SimpleXMLElement($xmlstr);
 
$c = $xml->xpath("//character");
 
$c[0]->name = 'Miss Coder';
}
?>

This looks like bug #38604, and I just confirmed that in 6.0.0-dev (on Windows at least) it is fixed.  It is NOT fixed in 5.2.1 or  5.2.2-dev (2/21 build), so for 5.2 users, use the second form to avoid leaks.
joel [from the website] purerave.com
20-Feb-2007 01:57
It doesn't mention this anywhere, but creationg a new SimpleXMLElement object from a non-valid string throws an exception. It looks ugly in the php log as it dumps the stack in multiple lines.

The correct way to create a new SimpleXMLElement object is like so:
<?php
$xmlstr
= ''; // empty to throw an exception
try {
  
$xml = new SimpleXMLElement($xmlstr);
} catch (
Exception $e) {
  
// handle the error
  
echo '$xmlstr is not a valid xml string';
}
?>
joshi at sencore dot com
13-Dec-2006 03:10
One way to work around the issue that Arnaud presented on 19-Oct-2006 is to check for the existence of the node before doing a 'foreach' on it.

<?php
   $xml
= simplexml_load_string('<root></root>');
   if(
$xml->b // Or maybe 'isset' or 'array_key_exists'
  
{
      foreach(
$xml->b as $dummy);
   }
   echo
$xml->asXML();
?>

Gives the expected result:

<?xml version="1.0"?>
<root/>

You can see the same behavior using an array, although you'll get a warning:

<?php
  $p
['a'] = '1';
  foreach(
$p['b'] as $node );
 
print_r( $p );
?>

Result:

Warning:  Invalid argument supplied for foreach()

Array
(
    [a] => 1
    [b] =>
)
matt at mattbostock dot com
06-Nov-2006 07:40
Be careful when using var_export to debug element attributes - it won't work! Always use print() or similar for checking the contents of element attributes.
Arnaud Bienvenu
19-Oct-2006 03:35
As of PHP 5.1.4, trying to iterate on a non-existent node will actually create that node.

<?
$xml
= simplexml_load_string('<root></root>');
foreach(
$xml->b as $dummy);
echo
$xml->asXML();
?>

Gives :

<?xml version="1.0"?>
<root><b/></root>

You might think it is a bug, but PHP developers seam to consider it as a feature : http://bugs.php.net/bug.php?id=39164
roy dot walter at nospam dot brookhouse dot co dot uk
16-Oct-2006 05:15
simplexml provides a neat way to do 'ini' files. Preferences for any number of users can be held in a single XML file having elements for each user name with user specific preferences as attributes of child elements. The separate <pref/>'s could of course be combined as multiple attributes of a single <pref/> element but this could get unwieldy.

In the sample code below the makeXML() function uses the simplexml_load_string function to generate some XML to play with and the readPrefs() function parses the requested users preferences into an array.

<?
function makeXML() {

$xmlString = <<<XML
<preferences>
    <johndoe>
        <pref color="#FFFFFF"/>
        <pref size="14"/>
        <pref font="Verdana"/>
    </johndoe>
    <janedoe>
        <pref color="#000000"/>
        <pref size="16"/>
        <pref font="Georgia"/>
    </janedoe>   
</preferences>
XML;

return
simplexml_load_string($xmlString);

}
function
readPrefs($user, $xml) {
   
    foreach(
$xml->$user as $arr);
       
$n = count($arr);
           
    for(
$i=0;$i<$n;$i++) {
        foreach(
$xml->$user->pref[$i]->attributes() as $a=>$b) {
           
$prefs[$a] = (string)$b;
        }
    }
       
   
print_r($prefs);
}

readPrefs('johndoe', makeXML());

?>
lukemoscrop at aol dot com
28-Aug-2006 10:31
to eho when using name space you need to select the arry from it (xpath turns all of it in to array)
<?php
$logined
= $xml->xpath('/root/login/@status');

echo
$logined[0];

//to see the the array its self
//use print_r() function
//

print_r($logined);
?>
charles at etherscapes dot com
20-Jul-2006 08:41
Just a minor modification to Daniel Favire's simplexml2ISOarray function: I added an if-block around the attributes section so you don't get a SimpleXML attributes element along with each attributes array:

function simplexml2ISOarray($xml,$attribsAsElements=0) {
    if (get_class($xml) == 'SimpleXMLElement') {
        $attributes = $xml->attributes();
        foreach($attributes as $k=>$v) {
            if ($v) $a[$k] = (string) $v;
        }
        $x = $xml;
        $xml = get_object_vars($xml);
    }
    if (is_array($xml)) {
        if (count($xml) == 0) return (string) $x; // for CDATA
        foreach($xml as $key=>$value) {
            $r[$key] = simplexml2ISOarray($value,$attribsAsElements);
            if (!is_array($r[$key])) $r[$key] = utf8_decode($r[$key]);
        }
        if (isset($a)) {
            if($attribsAsElements) {
                $r = array_merge($a,$r);
            } else {
                $r['@'] = $a; // Attributes
            }
        }
        return $r;
    }
    return (string) $xml;
}
Brett
09-Jul-2006 07:29
"When parsing and processing an instance document, SimpleXML is an excellent technology choice. However, if significant manipulation is required, it is important that the technology understands the model for the document, and in that case, SDO [see http://php.net/sdo ] is probably a more appropriate choice."

(Charters, Peters, Maynard and Srinivas from http://www.zend.com/pecl/tutorials/sdo.php )
Jason Sheets <jsheets at shadonet dot com>
31-May-2006 06:31
Here is my Simple XML to array function, it is recursive and has the benefit of maintaining key value relationships and has worked well for me.

function XMLToArray($xml)
{
  if ($xml instanceof SimpleXMLElement) {
    $children = $xml->children();
    $return = null;
  }

  foreach ($children as $element => $value) {
    if ($value instanceof SimpleXMLElement) {
      $values = (array)$value->children();
     
      if (count($values) > 0) {
        $return[$element] = XMLToArray($value);
      } else {
        if (!isset($return[$element])) {
          $return[$element] = (string)$value;
        } else {
          if (!is_array($return[$element])) {
            $return[$element] = array($return[$element], (string)$value);
          } else {
            $return[$element][] = (string)$value;
          }
        }
      }
    }
  }
 
  if (is_array($return)) {
    return $return;
  } else {
&nbs