search for in the  
<shmop_writeSimpleXMLElement->asXML>
Last updated: Thu, 19 May 2005

CXV. SimpleXML functions

Introduction

The SimpleXML extension provides a very simple and easily usable toolset to convert XML to an object that can be processed with normal property selectors and array iterators.

Requirements

The SimpleXML extension requires PHP 5.

Installation

The SimpleXML extension is enabled by default. To disable it, use the --disable-simplexml configure option.

Examples

Many examples in this reference require an XML string. Instead of repeating this string in every example, we put it into a file which we include in each example. This included file is shown in the following example section. Alternatively, you could create an XML document and read it with simplexml_load_file().

Example 1. Include file example.php with XML string

<?php
$xmlstr
= <<<XML
<?xml version='1.0' standalone='yes'?>
<movies>
 <movie>
  <title>PHP: Behind the Parser</title>
  <characters>
   <character>
   <name>Ms. Coder</name>
   <actor>Onlivia Actora</actor>
   </character>
   <character>
   <name>Mr. Coder</name>
   <actor>El Act&#211;r</actor>
   </character>
  </characters>
  <plot>
   So, this language. It's like, a programming language. Or is it a
   scripting language? All is revealed in this thrilling horror spoof
   of a documentary.
  </plot>
  <rating type="thumbs">7</rating>
  <rating type="stars">5</rating>
 </movie>
</movies>
XML;
?>

The simplicity of SimpleXML appears most clearly when one extracts a string or number from a basic XML document.

Example 2. Getting <plot>

<?php
include 'example.php';

$xml = simplexml_load_string($xmlstr);

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

Example 3. Accessing non-unique elements in SimpleXML

When multiple instances of an element exist as children of a single parent element, normal iteration techniques apply.

<?php
include 'example.php';

$xml = simplexml_load_string($xmlstr);

/* For each <movie> node, we echo a separate <plot>. */
foreach ($xml->movie as $movie) {
   echo
$movie->plot, '<br />';
}

?>

Example 4. Using attributes

So far, we have only covered the work of reading element names and their values. SimpleXML can also access element attributes. Access attributes of an element just as you would elements of an array.

<?php
include 'example.php';

$xml = simplexml_load_string($xmlstr);

/* Access the <rating> nodes of the first movie.
 * Output the rating scale, too. */
foreach ($xml->movie[0]->rating as $rating) {
   switch((string)
$rating['type']) { // Get attributes as element indices
  
case 'thumbs':
       echo
$rating, ' thumbs up';
       break;
   case
'stars':
       echo
$rating, ' stars';
       break;
   }
}
?>

Example 5. Comparing Elements and Attributes with Text

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.

<?php   
include 'example.php';

$xml = simplexml_load_string($xmlstr);

if ((string)
$xml->movie->title == 'PHP: Behind the Parser') {
   print
'My favorite movie.';
}

htmlentities((string) $xml->movie->title);
?>

Example 6. Using Xpath

SimpleXML includes builtin Xpath support. To find all <character> elements:

<?php
include 'example.php';
$xml = simplexml_load_string($xmlstr);

foreach (
$xml->xpath('//character') as $character) {
   echo
$character->name, 'played by ', $character->actor, '<br />';
}
?>

'//' serves as a wildcard. To specify absolute paths, omit one of the slashes.

Example 7. Setting values

Data in SimpleXML doesn't have to be constant. The object allows for manipulation of all of its elements.

<?php
include 'example.php';
$xml = simplexml_load_string($xmlstr);

$xml->movie[0]->characters->character[0]->name = 'Miss Coder';

echo
$xml->asXML();
?>

The above code will output a new XML document, just like the original, except that the new XML will change Ms. Coder to Miss Coder.

Example 8. DOM Interoperability

PHP has a mechanism to convert XML nodes between SimpleXML and DOM formats. This example shows how one might change a DOM element to SimpleXML.

<?php
$dom
= new domDocument;
$dom->loadXML('<books><book><title>blah</title></book></books>');
if (!
$dom) {
     echo
'Error while parsing the document';
     exit;
}

$s = simplexml_import_dom($dom);

echo
$s->book[0]->title;
?>

Table of Contents
SimpleXMLElement->asXML --  Return a well-formed XML string based on SimpleXML element
SimpleXMLElement->attributes --  Identifies an element's attributes
SimpleXMLElement->children --  Finds children of given node
SimpleXMLElement->xpath --  Runs Xpath query on XML data
simplexml_import_dom --  Get a SimpleXMLElement object from a DOM node.
simplexml_load_file --  Interprets an XML file into an object
simplexml_load_string --  Interprets a string of XML into an object


User Contributed Notes
SimpleXML functions
toma at smartsemantics dot com
11-May-2005 08:18
After much hair pulling, I have created a function that allows you work with your XML data as
a standard object (stdClass), rather than doing all kinds of iterations and element type-casting.
It makes comparision of values and data MUCH easier.

NOTE: If any attributes() tags exist, you will lose them in the conversion.  Keep a copy of your
SimpleXML object before conversion if you need the attribute data!  Also note that SimpleXML
objects cannot be serialized and then unserialized, so this function is
uni-directional.

Example:
config.xml
---------
<?xml version='1.0' encoding="ISO-8859-1"?>
<CONFIG>
   <DATABASE>
       <SERVER>localhost</SERVER>
       <USER>user</USER>
       <PASSWD>password</PASSWD>
       <DATABASE>MyDatabase</DATABASE>
   </DATABASE>
</CONFIG>
---------

config.php
---------
<?php
/**
 * @return void
 * @param variable $obj
 * @param class $class_type
 * @desc Takes a variable and converts it to an object of class $class_type
*/
function ClassTypeCast(&$obj,$class_type){
   if(
class_exists($class_type,true)){
      
$obj=unserialize(
          
$toreplace="/(^|;)*O:[0-9]+:\"[^\"]+\":/i";
          
preg_replace($toreplace,"\\1"."O:" . strlen($class_type).":\"" . $class_type."\":", serialize($obj))
       );
   }
}

$xmlfile='config.xml';
$CONFIG=simplexml_load_file($xmlfile);
ClassTypeCast($CONFIG,'stdClass');
//no need to type cast
if($CONFIG->DATABASE->SERVER=='localhost') echo "It Works!!!";
?>
---------
cyberlot at cyberlot dot net
09-May-2005 04:24
outping  a SimpleXML object is deceptive

For example

<doc channel="chat"><mess>Hello</mess></doc>

print_r returns

SimpleXMLElement Object
(
   [mess] => Hello
)

One might assume you are "losing" the attribute of doc BUT

echo $object['channel']

Does return the value of chat

No xpath /doc/@channel mess needed to access it, Its there you just can't "see" it until you access it directly

Everything is there, sometimes you just have to hunt for it.
paul at preinheimer dot com
06-May-2005 08:11
Hi,

If you want to access an element that has a dash in its name, (as is common with the XML documents provided by the Library of Congress, as well as the NWS) you will need to handle it a little bit differently.

You can either use XPATH, which works fine, but will return an array of results every time, even if there is a single result.
eg.
$xml->xpath('/data/time-layout/start-valid-time'}

You can also choose just to encapsulate the element names containing a dash:
$xml->data->{'time-layout'}->{'start-valid-time'}

--

On a only partially related note, dealing with SimpleXML is one of the only times I have employed casting with PHP. While iterating (foreach) through the valid times, echo'ing the element worked great (it merely echo'ed the apropriate time), assigning it to another variable resulted in a SimpleXML object containing the time to be assigned, rather than just the time itself. This was resolved by casting the time to a string:

foreach($xml->data->{'time-layout'}->{'start-valid-time'} AS $time)
{
 $weatherDates[] = (string) $time;
}
T CHASSAGNETTE t_chassagnette at yahoo dot fr
04-May-2005 04:57
Another method to parse an XML Document into a PHP array with SIMPLEXML inspired from Daniel FAIVRE !

function xml2php($xml)
{
   $fils = 0;
   $tab = false;
   $array = array();
   foreach($xml->children() as $key => $value)
   {   
       $child = xml2php($value);
      
       //To deal with the attributes
       foreach($node->attributes() as $ak=>$av)
       {
           $child[$ak] = (string)$av;
          
       }
      
       //Let see if the new child is not in the array
       if($tab==false && in_array($key,array_keys($array)))
       {
           //If this element is already in the array we will create an indexed array
           $tmp = $array[$key];
           $array[$key] = NULL;
           $array[$key][] = $tmp;
           $array[$key][] = $child;
           $tab = true;
       }
       elseif($tab == true)
       {
           //Add an element in an existing array
           $array[$key][] = $child;
       }
       else
       {
           //Add a simple element
           $array[$key] = $child;
       }
              
       $fils++;       
     }
  
  
   if($fils==0)
   {
       return (string)$xml;
   }
  
   return $array;
  
}
nelson_menezes at yahoo dot co dot uk
01-Mar-2005 08:05
Note that SimpleXML expects to both read and output XML in UTF-8 encoding. You'll need to add a line such as this at the top of your input XML file if it isn't saved in UTF-8 (adjust to whatever encoding used):

<?xml version="1.0" encoding="ISO-8859-1" ?>

On the output side of things, if you're not serving/handling UTF-8, you'll need to use utf8_decode(). Common mistake: http://bugs.php.net/bug.php?id=28154
webmarks
14-Feb-2005 12:57
I'm new to PHP and XML, but I think others might pull their hair out over this too.  I forgot about XML and whitespace when I was populating an array with node values, and was getting what appeared to be duplicate values despite using array_unique(). Use trim() when populating an array or assigning a variable.

<?php
$xml_array
= array();
foreach (
$resource->xpath($node_match) as $option){
  
$xml_array[$i] = trim($option);
  
$i++;
}
$xml_unique_array = array_unique($xml_array);
?>
roland dot swingler at transversal dot com
08-Feb-2005 05:24
Just a quick note - if you wish to get the name of the tag you are operating on, use the the key bit of foreach, i.e in the example:

<?php
// Outputs title characters plot rating rating
foreach($xml->movie[0]->children() as $tag => $child){
  echo
$tag;
}
?>

This might seem obvious but it stumped me for a bit.
yannis dot haralambous at enst-bretagne dot fr
29-Jan-2005 03:44
Sometimes tag names do not respect PHP variable name syntax. For example I have a file like this:
<livre>
   <éditorial>
     <édition-originale ref="123">
         bla bla bla
     </édition-originale>
   </éditorial>
</livre>
It's a perfectly valid XML file, but
$livre->éditorial[0]->édition-originale[0]->attributes()
will not work because of the hyphen.

The only solution I found is to write:
$livre->éditorial[0]->{"édition-originale"}[0]->attributes()

$livre->xpath("/livre/éditorial/édition-originale/@ref") doesn't work either but for that one I don't know how to solve the problem...
Daniel FAIVRE - geomaticien.com
14-Jan-2005 06:46
I've searched a while for a convenient "to array" function, and finally wrote it. These one provide at least 5 cool features:
- the MOST IMPORTANT: return a correct structure when several childs nodes have the same name: nodes are numbered properly
- read CDATA values
- returned array is very easy-to-use
- attributes returned in sub-arrays with key [@]
- very fast

When you create a "xml2array" function, you need to manage  nodes with attributes, but without children: i've choosed to ignore their attributes to avoid a "virtual ['value'] node" for such nodes in the returned array.

<?php
/**
 * Convert SimpleXMLElement object to array
 * Copyright Daniel FAIVRE 2005 - www.geomaticien.com
 * Copyleft GPL license
 */

function simplexml2array($xml) {
   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] = simplexml2array($value);
       }
       if (isset(
$a)) $r['@'] = $a;    // Attributes
      
return $r;
   }
   return (string)
$xml;
}

?>
igor kraus
07-Jan-2005 01:37
A simple way to merge two SimpleXML objects.

<?php
/**
* Pumps all child elements of second SimpleXML object into first one.
*
* @param    object      $xml1  SimpleXML object
* @param    object      $xml2  SimpleXML object
* @return  void
*/
function simplexml_merge (SimpleXMLElement &$xml1, SimpleXMLElement $xml2)
{
  
// convert SimpleXML objects into DOM ones
  
$dom1 = new DomDocument();
  
$dom2 = new DomDocument();
  
$dom1->loadXML($xml1->asXML());
  
$dom2->loadXML($xml2->asXML());

  
// pull all child elements of second XML
  
$xpath = new domXPath($dom2);
  
$xpathQuery = $xpath->query('/*/*');
   for (
$i = 0; $i < $xpathQuery->length; $i++)
   {
      
// and pump them into first one
      
$dom1->documentElement->appendChild(
          
$dom1->importNode($xpathQuery->item($i), true));
   }
  
$xml1 = simplexml_import_dom($dom1);
}

$xml1 = simplexml_load_string('<root><child>child 1</child></root>');
$xml2 = simplexml_load_string('<root><child>child 2</child></root>');
simplexml_merge($xml1, $xml2);
echo(
$xml1->asXml());
?>

Will output:
<?xml version="1.0"?>
<root>
   <child>child 1</child>
   <child>child 2</child>
</root>
brcavanagh AT NO SPAM hotmail.com
03-Jan-2005 12:18
If you are looking to use SimpleXML for anything but reading XML documents, you should really reconsider, and use the XML DOM library.  By the time you get enough utilities implemented in DOM to handle all the set backs in SimpleXML, you will have defeated the purpose of using SimpleXML.  There are a few reasons for this, and there are already many workrounds, but the primairy issues are this

1) No complex node assignment.  You cannot switch nodes or replace them. 

2) No appending new child nodes

3) Whenever you do something like $new_node = $xml_doc->node you will always get a reference even if you use a clone method, which will crash the script.

Other than that, its a great tool for reading docs.
aidan at php dot net
24-Dec-2004 03:42
SimpleXML does support namespaces, however their use is not as "simple".

This article explains much about SimpleXML, the limitations and problems in supporting namespaces, and possible solutions.

http://www.zend.com/php5/articles/php5-simplexml.php
aidan at php dot net
22-Dec-2004 02:20
SimpleXML doesn't allow the creation of new elements (nodes). However, we can use DOM as an intermediary.

This function allows you to add elements with SimpleXML:

http://aidan.dotgeek.org/lib/?file=function.simplexml_add_element.php
lajos dot arpasi at maxxlogic dot hu
08-Oct-2004 08:31
If you use PHP4 and miss the features of SimpleXML try MiniXML (http://minixml.psychogenic.com).
MiniXML is a PHP class library for generating and parsing XML.
MiniXML have similar abilities like creating XML files from Arrays and importing XML files into Arrays.
You can manipulate the XML files more easily than SimpleXML.
It saved my life:).
majkqball_gmail_com
25-Sep-2004 06:44
Converting SimpleXML objects to an array:

<?php
$sx
= simplexml_load_string('your xml string here');

function
recursive_obj2array($obj, &$subject_array=array()) {
   foreach ((array)
$obj as $key => $var) {
       if (
is_object($var)) {
           if(
count((array) $var) == 0) {
              
$subject_array[$key] = 'NULL';
           }
           else {
              
recursive_obj2array($var, $subject_array[$key]);
           }
       }
       else {
          
$subject_array[$key] = $var;
       }
   }
}

$gimmie = array();

recursive_obj2array($sx, $gimmie);
?>

Then $gimmie is foreach friendly.

Quick and dirty, but rather effective.
farzan ath ifarzan dod com
25-Sep-2004 06:38
You can access XML elements in a SimpleXML object using variables:

<?
$xml
= simplexml_loaf_file(...);

print
$xml->$element;
?>

or use functions:

<?
print $xml->{getLanguage()};
?>

Note: You Must use { and } or PHP would think you are calling a member function.
You can use members of other objects as well:

<?
print $xml->{$obj->var};
?>

As a real life example; I have used this statement in one of my projects:

<?
$x
= $xrules->listing->fieldtitles->$lang->{$obj->name}->title;
?>

As you see, using varialbes and functions as element names are posible in SimpleXML; Thanks to PHP5's object orientaion new features.
jam from Russia
24-Sep-2004 11:23
Example:
<?xml version="1.0"?>
<root status="ok">
   <login status="logining"/>
   <user:name xmlns:user="http://user.com/">jam</user:name>
</root>

You can get value from "user:name" element:
$user_name = $xml->xpath('/root/user:name');

You can get value from "status" attribute "root" element:
$status = $xml->xpath('/root/@status');

You can get value from "status" attribute "login" element:
$logined = $xml->xpath('/root/login/@status');

SimpleXML work with namespace :-)
cellog at php dot net
31-Aug-2004 07:11
simplexml does not simply handle CDATA sections in a foreach loop.

<?php
$sx
= simplexml_load_string('
<test>
 <one>hi</one>
 <two><![CDATA[stuff]]></two>
 <t>
  <for>two</for>
 </t>
 <multi>one</multi>
 <multi>two</multi>
</test>'
);
foreach((array)
$sx as $tagname => $val) {
   if (
is_string($val)) {
      
// <one> will go here
  
} elseif (is_array($val)) {
      
// <multi> will go here because it happens multiple times
  
} elseif (is_object($val)) {
    
// <t> will go here because it contains tags
     // <two> will go here because it contains CDATA!
  
}
}
?>

To test in the loop, do this

<?php
if (count((array) $val) == 0) {
  
// this is not a tag that contains other tags
  
$val = '' . $val;
  
// now the CDATA is revealed magically.
}
?>
bb at nospam xnull dot de
20-Jul-2004 06:39
the simplexml_to_array function below has a bug, if there are 2 or more fields, it get's bit out of control, here is the right one:

<?
function simplexml_to_array($xml) {
  
$ar = array();
   foreach(
$xml->children() as $k => $v) {
      
// recurse the child
      
$child = simplexml_to_array($v);
      
// if it's not an array, then it was empty, thus a value/string
      
if( count($child) == 0 ) {
          
$child = (string)$v;
       }

      
// add the childs attributes as if they where children
      
foreach( $v->attributes() as $ak => $av ) {
          
// if the child is not an array, transform it into one
          
if( !is_array( $child ) ) {
              
$child = array( "value" => $child );
           }
          
$child[$ak] = (string)$av;
       }

      
// if the $k is already in our children list, we need to transform
       // it into an array, else we add it as a value
      
if (!in_array($k,array_keys($ar))) {
          
$ar[$k] = $child;
       } elseif (@
in_array(0,@array_keys($ar[$k]))) {
          
$ar[$k][] = $child;
       } else {
          
$ar[$k] = array($ar[$k]);
          
$ar[$k][] = $child;
       }

   }
   return
$ar;
}
?>
rishad at kaluma dot com
01-Jul-2004 12:12
To test whether a child node exists I used the following code:

<?php

function child_exists($xml, $childpath)
{
  
$result = $xml->xpath($childpath);
   if (
count($result)) {
       return
true;
   } else {
       return
false;
   }
}

?>
greg dot steffensen at spamless dot richmond dot edu
19-Feb-2004 06:04
Simplexml's simplicity can be deceptive.  Simplexml elements behave either as objects or strings, depending on the context in which they're used (through overloading of the __toString() method, I assume).  Statements implying conversion to string treat them as strings, while assignment operations treat them as objects.  This can lead to unexpected behavior if, for example, you are trying to compare the values of two Simplexml elements.  The expected syntax will not work.  To force conversion to strings, just "typecast' whatever Simplexml element you're using.  For example:

<?php
$s
= simplexml_load_string('<foo>43</foo> <bar>43</bar>');

// Evaluates to false by comparing object IDs instead of strings
($s->foo == $s->bar);

// Evaluates to true
((string)$s->foo == (string)$s->bar);
?>

[Ed. Note: Changed from quotes to casts because casts provide a quicker and more explicit conversion than do double quotes.]

<shmop_writeSimpleXMLElement->asXML>
 Last updated: Thu, 19 May 2005
Copyright © 2001-2005 The PHP Group
All rights reserved.
This unofficial mirror is operated at: The Server Pages
Last updated: Thu May 19 18:35:34 2005 EDT