PHP: SimpleXML functions - Manual

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

search for in the

SimpleXMLElement->addAttribute() shmop_write

Last updated: Sat, 27 Jan 2007

view this page in

# CXLVIII. SimpleXML functions

# Введение

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.

# Требования

The SimpleXML extension requires PHP 5.

# Установка

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

# Примеры

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().

Пример 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.

Пример 2. Getting `<plot>`

`<?php include 'example.php'; $xml = new SimpleXMLElement($xmlstr); echo $xml->movie[0]->plot; // "So this language. It's like..." ?>`

Пример 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 = new SimpleXMLElement($xmlstr);
/* For each <movie> node, we echo a separate <plot>. */
foreach ($xml->movie as $movie) {
echo $movie->plot, '<br />';
}
?>`

Пример 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 = new SimpleXMLElement($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;
}
}
?>`

Пример 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 = new SimpleXMLElement($xmlstr);
if ((string) $xml->movie->title == 'PHP: Behind the Parser') {
print 'My favorite movie.';
}
htmlentities((string) $xml->movie->title);
?>`

Пример 6. Using XPath

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

`<?php
include 'example.php';
$xml = new SimpleXMLElement($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.

Пример 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 = new SimpleXMLElement($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.

Пример 8. Adding elements and attributes

Since PHP 5.1.3, SimpleXML has had the ability to easily add children and attributes.

`<?php
include 'example.php';
$xml = new SimpleXMLElement($xmlstr);
$character = $xml->movie[0]->characters->addChild('character');
$character->addChild('name', 'Mr. Parser');
$character->addChild('actor', 'John Doe');
$rating = $xml->movie[0]->addChild('rating', 'PG');
$rating->addAttribute('type', 'mpaa');
echo $xml->asXML();
?>`

The above code will output an XML document based on the original but having a new character and rating.

Пример 9. 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;
?>`

add a note User Contributed Notes
SimpleXML functions
php at NOSPAM dot coutch dot com
21-Feb-2007 02: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
19-Feb-2007 05: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 07: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
05-Nov-2006 11: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 07: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 09: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 02: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 12: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 11: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 10: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 {
return $false;
}
}`
Gregory Boshoff
19-May-2006 11:42
`I've written a tutorial demonstating how to update a Google sitemap dynamically using the PHP5 SimpleXML extension.
http://www.phpfive.net/article34.htm`
daniel dot oconnor at gmail dot com
17-May-2006 06:21
`SimpleXML handles namespaces, but it's not documented very well here at all.
If you wanted to parse, say, an open office manifest file or a piece of RDF/XML, you have to get elements and attributes by the namespace url.
Example:
<?php
function display($in) {
if (file_exists($in)) {
$xml = simplexml_load_file($in);
} else {
throw new Exception($in . " does not exist");
}
$manifest = $xml->children('http://openoffice.org/2001/manifest');
foreach ($manifest->xpath('//manifest:file-entry') as $file) {
foreach ($file->attributes('http://openoffice.org/2001/manifest') as $key => $value) {
print "Key:" . $key . "\n";
print "Value:" . $value . "\n";
}
}
}
?>
File: manifest.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE manifest:manifest PUBLIC "-//OpenOffice.org//DTD Manifest 1.0//EN" "Manifest.dtd">
<manifest:manifest xmlns:manifest="http://openoffice.org/2001/manifest">
<manifest:file-entry manifest:media-type="application/vnd.sun.xml.writer" manifest:full-path="/"/>
<manifest:file-entry manifest:media-type="application/vnd.sun.xml.ui.configuration" manifest:full-path="Configurations2/"/>
<manifest:file-entry manifest:media-type="application/binary" manifest:full-path="layout-cache"/>
<manifest:file-entry manifest:media-type="text/xml" manifest:full-path="content.xml"/>
<manifest:file-entry manifest:media-type="text/xml" manifest:full-path="styles.xml"/>
<manifest:file-entry manifest:media-type="text/xml" manifest:full-path="meta.xml"/>
<manifest:file-entry manifest:media-type="" manifest:full-path="Thumbnails/thumbnail.png"/>
<manifest:file-entry manifest:media-type="" manifest:full-path="Thumbnails/"/>
<manifest:file-entry manifest:media-type="text/xml" manifest:full-path="settings.xml"/>
</manifest:manifest>`
JaskaS
05-May-2006 12:11
`More new stuff.
<?php
$xml = "
<test></test>
";
$xml = simplexml_load_string($xml);
$xml->addChild('new','value','namespace');
echo $xml->asXml();
?>
output:
<?xml version="1.0"?>
<test><new xmlns="namespace">value</new></test>
Very nice and clean. DOM is so awkward compared to this.`
Vaedan
02-May-2006 10:04
`This is one new stuff to get the root name (since PHP 5.1.3) :
<?php
$xml = simplexml_load_string( '<foo name="bar" />' );
echo $xml->getName(); // displays foo
?>`
lists at cyberlot dot net
07-Sep-2005 12:51
`While you can't add new elements to a SimpleXML object you can however add new attributes
<?php
$string = '<doc channel="chat"><test1>Hello</test1></doc>';
$xml = simplexml_load_string($string);
$xml->test1['sub'] = 'No';
echo $xml->asXML();
?>
Will return output
<doc channel="chat"><test1 sub="No">Hello</test1></doc>`
galaxiaguy at hotmail dot com
03-Sep-2005 07:52
`I tried extending SimpleXMLElement to add some functionality and found you can't set new properties. I assume this is something to do with built-in magic methods or something.
So I wrote a class that behaves the same as SimpleXMLElement (by delegating most of it's work) but is arbitrarily extendable.
http://www.oliverbrown.me.uk/2005/09/03/extending-simplexml/
It's very new and not very well tested but could be useful to somebody.`
Maciek Ruckgaber <maciekrb at gmai dot com>
07-Jun-2005 05:07
`after wondering around some time, i just realized something (maybe obvious, not very much for me). Hope helps someone to not waste time as i did :-P
when you have something like:
$xmlstr = <<<XML
<?xml version="1.0" encoding="utf-8"?>
<double xmlns="http://foosite.foo/">2328</double>
XML;
you will have the simpleXML object "transformed" to the text() content:
$xml = simplexml_load_string($xmlstr);
echo $xml; // this will echo 2328 (string)`
paul at preinheimer dot com
06-May-2005 05: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 01: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 05: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() [red. but that will only work for ISO-8859-1, not other encodings]. Common mistake: http://bugs.php.net/bug.php?id=28154`
igor kraus
07-Jan-2005 10: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
02-Jan-2005 09: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 12: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`
cellog at php dot net
31-Aug-2004 04: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.
}
?>`
philip
17-Jun-2004 03:58
`A introductory tutorial on simplexml can be found here:
* http://www.zend.com/php5/articles/php5-simplexml.php
* http://www.zend.com/php5/abs/php101-11.php
* http://www.onlamp.com/pub/a/php/2004/01/15/simplexml.html`
greg dot steffensen at spamless dot richmond dot edu
19-Feb-2004 03: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.]`
add a note
SimpleXMLElement->addAttribute() shmop_write

Last updated: Sat, 27 Jan 2007
show source | credits | stats | sitemap | contact | advertising | mirror sites
Copyright © 2001-2007 The PHP Group
All rights reserved.
This mirror generously provided by: Yahoo! Inc.
Last updated: Sat Mar 10 11:33:19 2007 PST