ConFoo Montreal 2017 Calling for Papers

SimpleXML

add a note add a note

User Contributed Notes 29 notes

up
165
soloman at textgrid dot com
5 years ago
Three line xml2array:

<?php

$xml
= simplexml_load_string($xmlstring);
$json = json_encode($xml);
$array = json_decode($json,TRUE);

?>

Ta da!
up
4
bxt at die-optimisten dot net
7 years ago
Addition to QLeap's post:
SimpleXML will return a reference to an object containing the node value and you can't use references in session variables as there is no feasible way to restore a reference to another variable.

This won't work too:
$val=$this->xml->node->attributes()->name;
echo $array[$val]; // will cause a warning because of the wrong index type.

You have to convert/cast to a String first:
echo $array[(string)$val];

This will work as expected, because converting will call the __toString() method. Therefor echo works too:
echo $val; // will display the name
up
4
streaver91 at gmail dot com
5 years ago
The BIGGEST differece between an XML and a PHP array is that in an XML file, the name of elements can be the same even if they are siblings, eg. "<pa><ch /><ch /><ch /></pa>", while in an PHP array, the key of which must be different.

I think the array structure developed by svdmeer can fit for XML, and fits well.

here is an example array converted from an xml file:
array(
"@tag"=>"name",
"@attr"=>array(
    "id"=>"1","class"=>"2")
"@text"=>"some text",
)

or if it has childrens, that can be:

array(
"@tag"=>"name",
"@attr"=>array(
    "id"=>"1","class"=>"2")
"@items"=>array(
    0=>array(
        "@tag"=>"name","@text"=>"some text"
    )
)

Also, I wrote a function that can change that array back to XML.

<?php
function array2XML($arr,$root) {
$xml = new SimpleXMLElement("<?xml version=\"1.0\" encoding=\"utf-8\" ?><{$root}></{$root}>");
$f = create_function('$f,$c,$a','
        foreach($a as $v) {
            if(isset($v["@text"])) {
                $ch = $c->addChild($v["@tag"],$v["@text"]);
            } else {
                $ch = $c->addChild($v["@tag"]);
                if(isset($v["@items"])) {
                    $f($f,$ch,$v["@items"]);
                }
            }
            if(isset($v["@attr"])) {
                foreach($v["@attr"] as $attr => $val) {
                    $ch->addAttribute($attr,$val);
                }
            }
        }'
);
$f($f,$xml,$arr);
return
$xml->asXML();
}
?>
up
1
oscargodson at gmail dot com
7 years ago
To add to what others have said, you can't directly put a $_GET or $_POST value into a variable then into an attribute using SimpleXML. You must first convert it to an integer.

This will NOT work

<?php
      $page_id
= $_GET['id'];
      echo
$xml->page[$page_id]
?>

You will get something like:
Notice: Trying to get property of non-object in /Applications/MAMP/htdocs/mysite/index.php on line 10

However, this WILL work and is much simpler then using (string) or other methods.
<?php
   $page_id
= intval($_GET['id']);
   echo
$xml->page[$page_id]
?>
up
2
phil at dier dot us
5 years ago
Here's a function I came up with to convert an associative array to XML.  Works for multidimensional arrays as well.

<?php
function assocArrayToXML($root_element_name,$ar)
{
   
$xml = new SimpleXMLElement("<?xml version=\"1.0\"?><{$root_element_name}></{$root_element_name}>");
   
$f = create_function('$f,$c,$a','
            foreach($a as $k=>$v) {
                if(is_array($v)) {
                    $ch=$c->addChild($k);
                    $f($f,$ch,$v);
                } else {
                    $c->addChild($k,$v);
                }
            }'
);
   
$f($f,$xml,$ar);
    return
$xml->asXML();
}
?>
up
3
philipp at strazny dot com
5 years ago
Here's a quick way to dump the nodeValues from SimpleXML into an array using the path to each nodeValue as key. The paths are compatible with e.g. DOMXPath. I use this when I need to update values externally (i.e. in code that doesn't know about the underlying xml). Then I use DOMXPath to find the node containing the original value and update it.

<?php
function XMLToArrayFlat($xml, &$return, $path='', $root=false)
{
   
$children = array();
    if (
$xml instanceof SimpleXMLElement) {
       
$children = $xml->children();
        if (
$root){ // we're at root
           
$path .= '/'.$xml->getName();
        }
    }
    if (
count($children) == 0 ){
       
$return[$path] = (string)$xml;
        return;
    }
   
$seen=array();
    foreach (
$children as $child => $value) {
       
$childname = ($child instanceof SimpleXMLElement)?$child->getName():$child;
        if ( !isset(
$seen[$childname])){
           
$seen[$childname]=0;
        }
       
$seen[$childname]++;
       
XMLToArrayFlat($value, $return, $path.'/'.$child.'['.$seen[$childname].']');
    }
}
?>

Use like this:

<?php
$xml
= simplexml_load_string(...some xml string...);
$xmlarray = array(); // this will hold the flattened data
XMLToArrayFlat($xml, $xmlarray, '', true);
?>

You can also pull multiple files in one array:

<?php
foreach($files as $file){
   
$xml = simplexml_load_file($file);
   
XMLToArrayFlat($xml, $xmlarray, $file.':', true);
}
?>
The respective filename/path is thus prefixed to each key.
up
2
xaviered at gmail dot com
4 years ago
Here is a recursive function that will convert a given SimpleXMLElement object into an array, preserving namespaces and attributes.

<?php
function xmlObjToArr($obj) {
       
$namespace = $obj->getDocNamespaces(true);
       
$namespace[NULL] = NULL;
       
       
$children = array();
       
$attributes = array();
       
$name = strtolower((string)$obj->getName());
       
       
$text = trim((string)$obj);
        if(
strlen($text) <= 0 ) {
           
$text = NULL;
        }
       
       
// get info for all namespaces
       
if(is_object($obj)) {
            foreach(
$namespace as $ns=>$nsUrl ) {
               
// atributes
               
$objAttributes = $obj->attributes($ns, true);
                foreach(
$objAttributes as $attributeName => $attributeValue ) {
                   
$attribName = strtolower(trim((string)$attributeName));
                   
$attribVal = trim((string)$attributeValue);
                    if (!empty(
$ns)) {
                       
$attribName = $ns . ':' . $attribName;
                    }
                   
$attributes[$attribName] = $attribVal;
                }
               
               
// children
               
$objChildren = $obj->children($ns, true);
                foreach(
$objChildren as $childName=>$child ) {
                   
$childName = strtolower((string)$childName);
                    if( !empty(
$ns) ) {
                       
$childName = $ns.':'.$childName;
                    }
                   
$children[$childName][] = xmlObjToArr($child);
                }
            }
        }
       
        return array(
           
'name'=>$name,
           
'text'=>$text,
           
'attributes'=>$attributes,
           
'children'=>$children
       
);
    }
?>
up
4
aalaap at gmail dot com
8 years ago
Here are two quick and dirty functions that use SimpleXML to detect if a feed xml is RSS or ATOM:

<?php
function is_rss($feedxml) {
    @
$feed = new SimpleXMLElement($feedxml);

    if (
$feed->channel->item) {
        return
true;
    } else {
        return
false;
    }
}

function
is_atom($feedxml) {
    @
$feed = new SimpleXMLElement($feedxml);

    if (
$feed->entry) {
        return
true;
    } else {
        return
false;
    }
}
?>

The functions take in the full text feed (retrieved via cURL, for example) and return a true or a false based on the result.
up
4
dkrnl at yandex dot ru
2 years ago
Wrapper XMLReader class, for simple SAX-reading huge xml:
https://github.com/dkrnl/SimpleXMLReader

Usage example: http://github.com/dkrnl/SimpleXMLReader/blob/master/examples/example1.php

<?php

/**
* Simple XML Reader
*
* @license Public Domain
* @author Dmitry Pyatkov(aka dkrnl) <dkrnl@yandex.ru>
* @url http://github.com/dkrnl/SimpleXMLReader
*/
class SimpleXMLReader extends XMLReader
{

   
/**
     * Callbacks
     *
     * @var array
     */
   
protected $callback = array();

   
/**
     * Add node callback
     *
     * @param  string   $name
     * @param  callback $callback
     * @param  integer  $nodeType
     * @return SimpleXMLReader
     */
   
public function registerCallback($name, $callback, $nodeType = XMLREADER::ELEMENT)
    {
        if (isset(
$this->callback[$nodeType][$name])) {
            throw new
Exception("Already exists callback $name($nodeType).");
        }
        if (!
is_callable($callback)) {
            throw new
Exception("Already exists parser callback $name($nodeType).");
        }
       
$this->callback[$nodeType][$name] = $callback;
        return
$this;
    }

   
/**
     * Remove node callback
     *
     * @param  string  $name
     * @param  integer $nodeType
     * @return SimpleXMLReader
     */
   
public function unRegisterCallback($name, $nodeType = XMLREADER::ELEMENT)
    {
        if (!isset(
$this->callback[$nodeType][$name])) {
            throw new
Exception("Unknow parser callback $name($nodeType).");
        }
        unset(
$this->callback[$nodeType][$name]);
        return
$this;
    }

   
/**
     * Run parser
     *
     * @return void
     */
   
public function parse()
    {
        if (empty(
$this->callback)) {
            throw new
Exception("Empty parser callback.");
        }
       
$continue = true;
        while (
$continue && $this->read()) {
            if (isset(
$this->callback[$this->nodeType][$this->name])) {
               
$continue = call_user_func($this->callback[$this->nodeType][$this->name], $this);
            }
        }
    }

   
/**
     * Run XPath query on current node
     *
     * @param  string $path
     * @param  string $version
     * @param  string $encoding
     * @return array(SimpleXMLElement)
     */
   
public function expandXpath($path, $version = "1.0", $encoding = "UTF-8")
    {
        return
$this->expandSimpleXml($version, $encoding)->xpath($path);
    }

   
/**
     * Expand current node to string
     *
     * @param  string $version
     * @param  string $encoding
     * @return SimpleXMLElement
     */
   
public function expandString($version = "1.0", $encoding = "UTF-8")
    {
        return
$this->expandSimpleXml($version, $encoding)->asXML();
    }

   
/**
     * Expand current node to SimpleXMLElement
     *
     * @param  string $version
     * @param  string $encoding
     * @param  string $className
     * @return SimpleXMLElement
     */
   
public function expandSimpleXml($version = "1.0", $encoding = "UTF-8", $className = null)
    {
       
$element = $this->expand();
       
$document = new DomDocument($version, $encoding);
       
$node = $document->importNode($element, true);
       
$document->appendChild($node);
        return
simplexml_import_dom($node, $className);
    }

   
/**
     * Expand current node to DomDocument
     *
     * @param  string $version
     * @param  string $encoding
     * @return DomDocument
     */
   
public function expandDomDocument($version = "1.0", $encoding = "UTF-8")
    {
       
$element = $this->expand();
       
$document = new DomDocument($version, $encoding);
       
$node = $document->importNode($element, true);
       
$document->appendChild($node);
        return
$document;
    }

}
?>
up
4
maikel at yuluma dot com
2 years ago
In reply to  soloman at textgrid dot com,

2 line XML2Array:

$xml = simplexml_load_string($file);
$array = (array)$xml;
up
1
whyme
3 years ago
Simple means simple.  If you know the structure and just want the value of a tag:

<?php
$xml
= simplexml_load_file($xmlfile);
print
$xml->City->Street->Address->HouseColor;
?>

Warning, numbers can come out as strings, empty elements like <HouseColor></HouseColor> come out as array(0)
up
1
sherwinterunez at yahoo dot com
5 years ago
<?php

// Sherwin R. Terunez
//
// This is my own version of XML Object to Array
//

function amstore_xmlobj2array($obj, $level=0) {
   
   
$items = array();
   
    if(!
is_object($obj)) return $items;
       
   
$child = (array)$obj;
   
    if(
sizeof($child)>1) {
        foreach(
$child as $aa=>$bb) {
            if(
is_array($bb)) {
                foreach(
$bb as $ee=>$ff) {
                    if(!
is_object($ff)) {
                       
$items[$aa][$ee] = $ff;
                    } else
                    if(
get_class($ff)=='SimpleXMLElement') {
                       
$items[$aa][$ee] = amstore_xmlobj2array($ff,$level+1);
                    }
                }
            } else
            if(!
is_object($bb)) {
               
$items[$aa] = $bb;
            } else
            if(
get_class($bb)=='SimpleXMLElement') {
               
$items[$aa] = amstore_xmlobj2array($bb,$level+1);
            }
        }
    } else
    if(
sizeof($child)>0) {
        foreach(
$child as $aa=>$bb) {
            if(!
is_array($bb)&&!is_object($bb)) {
               
$items[$aa] = $bb;
            } else
            if(
is_object($bb)) {
               
$items[$aa] = amstore_xmlobj2array($bb,$level+1);
            } else {
                foreach(
$bb as $cc=>$dd) {
                    if(!
is_object($dd)) {
                       
$items[$obj->getName()][$cc] = $dd;
                    } else
                    if(
get_class($dd)=='SimpleXMLElement') {
                       
$items[$obj->getName()][$cc] = amstore_xmlobj2array($dd,$level+1);
                    }
                }
            }
        }
    }

    return
$items;
}

?>
up
1
oleg at mastak dot fi
4 months ago
Two lines xml2array:

<?php

$xml
= simplexml_load_string($xmlstring);
$array = (array) $xml;

?>
up
0
Serge
1 year ago
XML data values should not contain "&" and that need to be replaced by html-entity "&amp;"

You can use this code to replace lonely "&" to "&amp;":

<?php
$sText
= preg_replace('#&(?![a-z]{1,6};)#i', '&amp;', $sText);
?>

This will replace just "&" into "&amp;" but dont touches other html-entities like "&nbsp;", "&lt;" etc and, of course, "&amp;".

P.S. In regexp max length is 6 becouse I found that is the maximum length of possible html entity using this code:
<?php
max
(array_map('strlen', array_values(get_html_translation_table(HTML_ENTITIES, ENT_QUOTES | ENT_HTML5)))) - 2
?>
minus two is for first "&" and last ";" in an any html entity.
up
0
Laurent Vervisch
4 years ago
Here is an example of an easy mapping between xml and classes defined by user.

<?php
class XmlClass extends SimpleXMLElement
{
   
/**
     * Returns this object as an instance of the given class.
     */
   
public function asInstanceOf($class_name)
    {
       
// should check that class_name is valid

       
return simplexml_import_dom(dom_import_simplexml($this), $class_name);
    }

    public function
__call($name, array $arguments)
    {
        echo
"magic __call called for method $name on instance of ".get_class()."\n";

       
// class could be mapped according $this->getName()
       
$class_name = 'Test';

       
$instance = $this->asInstanceOf($class_name);
        return
call_user_func_array(array($instance, $name), $arguments);
    }
}

class
Test extends XmlClass
{
    public function
setValue($string)
    {
       
$this->{0} = $string;
    }
}

$xml = new XmlClass('<example><test/></example>');
$test = $xml->test->asInstanceOf('Test');
echo
get_class($xml->test), "\n";
echo
get_class($test), "\n";

$test->setValue('value set directly by instance of Test');
echo (string)
$xml->test, "\n";
echo (string)
$test, "\n";

$xml->test->setValue('value set by instance of XmlClass and magic __call');
echo (string)
$xml->test, "\n";
echo (string)
$test, "\n";
?>

XmlClass
Test
value set directly by instance of Test
value set directly by instance of Test
magic __call called for method setValue on instance of XmlClass
value set by instance of XmlClass and magic __call
value set by instance of XmlClass and magic __call
up
0
thedoc8786 at gmail dot com
4 years ago
I know it is over-done, but the following is a super-short example of a XML to Array conversion function (recursive):

<?php
   
function toArray(SimpleXMLElement $xml) {
       
$array = (array)$xml;

        foreach (
array_slice($array, 0) as $key => $value ) {
            if (
$value instanceof SimpleXMLElement ) {
               
$array[$key] = empty($value) ? NULL : toArray($value);
            }
        }
        return
$array;
    }
up
0
kristof at viewranger dot com
5 years ago
If you tried to load an XML file with this, but the CDATA parts were not loaded for some reason, is because you should do it this way:

$xml = simplexml_load_file($this->filename, 'SimpleXMLElement', LIBXML_NOCDATA);

This converts CDATA to String in the returning object.
up
1
antoine dot rabanes at gmail dot com
6 years ago
if for some reasons you need the string value instead of the simpleXML Object you can cast the return value as a string.

exemple:

<?php
$all_api_call
= simplexml_load_file($url);
$all_api = array();
$all_api = $all_api_call->result;
$list_all_api_name = array();
$i = 0;
foreach (
$all_api->children() as $funcky_function)
{
   
$string_tmp = (string )$funcky_function->function;
   
$list_all_api_name[$i++] = $putain;
}
?>

...
up
0
michael dot allen at emp dot shentel dot com
6 years ago
Here is a very robust SimpleXML parser.  Can be used to load files, strings, or DOM into SimpleXML, or can be used to perform the reverse when handed SimpleXML.

<?php
/**
* XMLParser Class File
*
* This class loads an XML document into a SimpleXMLElement that can
* be processed by the calling application.  This accepts xml strings,
* files, and DOM objects.  It can also perform the reverse, converting
* an SimpleXMLElement back into a string, file, or DOM object.
*/
class XMLParser {
   
/**
     * While parsing, parse the supplied XML document.
     *
     * Sets up a SimpleXMLElement object based on success of parsing
     * the XML document file.
     *
     * @param string $doc the xml document location path
     * @return object
     */
   
public static function loadFile($doc) {
        if (
file_exists($doc)) {
            return
simplexml_load_file($doc);
        } else {
            throw new
Exception ("Unable to load the xml file " .
                                
"using: \"$doc\"", E_USER_ERROR);
        }
    }
   
/**
     * While parsing, parse the supplied XML string.
     *
     * Sets up a SimpleXMLElement object based on success of parsing
     * the XML string.
     *
     * @param string $string the xml document string
     * @return object
     */
   
public static function loadString($string) {
        if (isset(
$string)) {
            return
simplexml_load_string($string);
        } else {
            throw new
Exception ("Unable to load the xml string " .
                                
"using: \"$string\"", E_USER_ERROR);
        }
    }
   
/**
     * While parsing, parse the supplied XML DOM node.
     *
     * Sets up a SimpleXMLElement object based on success of parsing
     * the XML DOM node.
     *
     * @param object $dom the xml DOM node
     * @return object
     */
   
public static function loadDOM($dom) {
        if (isset(
$dom)) {
            return
simplexml_import_dom($dom);
        } else {
            throw new
Exception ("Unable to load the xml DOM node " .
                                
"using: \"$dom\"", E_USER_ERROR);
        }
    }
   
/**
     * While parsing, parse the SimpleXMLElement.
     *
     * Sets up a XML file, string, or DOM object based on success of
     * parsing the XML DOM node.
     *
     * @param object $path the xml document location path
     * @param string $type the return type (string, file, dom)
     * @param object $simplexml the simple xml element
     * @return mixed
     */
   
public static function loadSXML($simplexml, $type, $path) {
        if (isset(
$simplexml) && isset($type)) {
        switch (
$type) {
            case
'string':
                return
$simplexml->asXML();
            break;
            case
'file':
                if (isset(
$path)) {
                    return
$simplexml->asXML($path);
                } else {
                    throw new
Exception ("Unable to create the XML file. Path is missing or" .
                                        
"is invalid: \"$path\"", E_USER_ERROR);
                }
            break;
            case
'dom':
                return
dom_import_simplexml($simplexml);
            break;
        }
        } else {
            throw new
Exception ("Unable to load the simple XML element " .
                                
"using: \"$simplexml\"", E_USER_ERROR);
        }
    }
}
?>
up
0
emmanuel
6 years ago
dynamic sql in php using xml:

test.xml:
<?xml version="1.0" encoding="UTF-8"?>
<sql>
    <statement>
        SELECT * FROM USERS
        <call criteria="byId">WHERE id = %d</call>
        <call criteria="byUsername">WHERE username = "%s"</call>;
    </statement>
</sql>

index.php:
<?php
function callMe($param) {
   
$search = array('byUsername' => 'dynsql');
   
    if (isset(
$search[$param[1]])) {
        return
sprintf($param[2], $search[$param[1]]);
    }
   
    return
"";
}

$xml = simplexml_load_file("test.xml");
$string = $xml->statement->asXML();
$string = preg_replace_callback('/<call criteria="(\w+)">(.*?)<\/call>/', 'callMe', $string);
$node = simplexml_load_string($string);
echo
$node;
?>

obviously, this example can be improved [in your own code.]
up
0
mahmutta at gmail dot com
6 years ago
while using simple xml and get double or float int value from xml object for using math operations (+ * - / ) some errors happens on the operation, this is because of simple xml returns everythings to objects.
exmple;

<?php

$name
= "somestring";
$size = 11.45;
$xml = '
<xml>
<name>somestring</name>
<size>11.45</size>
</xml>'
;


$xmlget = simplexml_load_string($xml)

echo
$xml->size*2;    // 20  its false
// ($xml->size is an object (int)11 and  (45) )

// this is true
echo $size*2;            // 22.90
echo (float)$size*2;   // 22.90
?>
up
0
mail at kleineedv dot de
7 years ago
I had a problem with simplexml reading nodes from an xml file. It always return an SimpleXML-Object but not the text inside the node.

Example:
<?xml version="1.0" encoding="UTF-8"?>
<Test>
    <Id>123</Id>
</Test>

Reading this xml into a variable called $xml and then doing the following
<?php
$myId
= $xml->Id;
?>
Did not return 123 in $myId, but instead I got a SimpleXMLElement Object.

The solution is simple, when you know it. Use explicit string conversion.
<?php
$myId
= (string)$xml->Id;
?>
up
0
QLeap
7 years ago
Storing SimpleXMLElement values in $_SESSION does not work. Saving the results as an object or individual elements of the object will result in the dreaded "Warning: session_start() [function.session-start]: Node no longer exists" error.

For example, this does not work:

    $xml  = new SimpleXMLElement($page);
    $country  = $xml->Response->Placemark->AddressDetails->Country->CountryNameCode;
    $_SESSION['country'] = $country;

This will work:

    $_SESSION['country'] = (string) $country;
up
0
gwhitescarver at yahoo dot com
7 years ago
Moving some code from a PHP 5.2.6 / Windows environment to a 5.2.0 / Linux environment, I somehow lost access to a plain text node within a SimpleXML Object.  On a var_dump of $xml_node, a [0] element was shown as the string '12'.  However, $xml_node[0] was evaluating NULL in 5.2.0.  You can see below the code change I made, pulling my data out of the raw XML with a regular expression.  Hope this is useful to someone.

//In some versions of PHP it seems we cannot access the [0] element of a SimpleXML Object.  Doesn't work in 5.2.0:
//$count = $xml_node[0];
//grab the raw XML:
$count = ($xml_node->asXML());
//pull out the number between the closing and opening brace of the xml:
$count = preg_replace('/.*>(\d*)<.*/', '$1', $count);
up
0
charlie at blankcanvasstudios dot com
8 years ago
Optimizing aalaap at gmail dot com's php

<?php
function is_rss($feedxml) {
    @
$feed = simplexml_load_string($feedxml);

    return (
$feed->channel->item)?true:false;
}

function
is_atom($feedxml) {
    @
$feed = new SimpleXMLElement($feedxml);
    (
$feed->entry):true:false;
}
?>
up
-2
thedoc8786 at gmail dot com
4 years ago
FAIL! This function works better than the one I posted below:

<?php
   
function toArray($xml) {
       
$array = json_decode(json_encode($xml), TRUE);
       
        foreach (
array_slice($array, 0) as $key => $value ) {
            if ( empty(
$value) ) $array[$key] = NULL;
            elseif (
is_array($value) ) $array[$key] = toArray($value);
        }

        return
$array;
    }
up
-1
xananax at yelostudio dot com
4 years ago
None of the XML2Array functions that I found satisfied me completely; Their results did not always fit the project I was working on, and I found none that would account for repeating XML elements (such as
<fields><field/><field/><field/></fields>)
So I rolled out my own; hope it helps someone.
<?php
/**
* Converts a simpleXML element into an array. Preserves attributes.<br/>
* You can choose to get your elements either flattened, or stored in a custom
* index that you define.<br/>
* For example, for a given element
* <code>
* <field name="someName" type="someType"/>
* </code>
* <br>
* if you choose to flatten attributes, you would get:
* <code>
* $array['field']['name'] = 'someName';
* $array['field']['type'] = 'someType';
* </code>
* If you choose not to flatten, you get:
* <code>
* $array['field']['@attributes']['name'] = 'someName';
* </code>
* <br>__________________________________________________________<br>
* Repeating fields are stored in indexed arrays. so for a markup such as:
* <code>
* <parent>
*     <child>a</child>
*     <child>b</child>
*     <child>c</child>
* ...
* </code>
* you array would be:
* <code>
* $array['parent']['child'][0] = 'a';
* $array['parent']['child'][1] = 'b';
* ...And so on.
* </code>
* @param simpleXMLElement    $xml            the XML to convert
* @param boolean|string    $attributesKey    if you pass TRUE, all values will be
*                                            stored under an '@attributes' index.
*                                            Note that you can also pass a string
*                                            to change the default index.<br/>
*                                            defaults to null.
* @param boolean|string    $childrenKey    if you pass TRUE, all values will be
*                                            stored under an '@children' index.
*                                            Note that you can also pass a string
*                                            to change the default index.<br/>
*                                            defaults to null.
* @param boolean|string    $valueKey        if you pass TRUE, all values will be
*                                            stored under an '@values' index. Note
*                                            that you can also pass a string to
*                                            change the default index.<br/>
*                                            defaults to null.
* @return array the resulting array.
*/
function simpleXMLToArray(SimpleXMLElement $xml,$attributesKey=null,$childrenKey=null,$valueKey=null){

    if(
$childrenKey && !is_string($childrenKey)){$childrenKey = '@children';}
    if(
$attributesKey && !is_string($attributesKey)){$attributesKey = '@attributes';}
    if(
$valueKey && !is_string($valueKey)){$valueKey = '@values';}

   
$return = array();
   
$name = $xml->getName();
   
$_value = trim((string)$xml);
    if(!
strlen($_value)){$_value = null;};

    if(
$_value!==null){
        if(
$valueKey){$return[$valueKey] = $_value;}
        else{
$return = $_value;}
    }

   
$children = array();
   
$first = true;
    foreach(
$xml->children() as $elementName => $child){
       
$value = simpleXMLToArray($child,$attributesKey, $childrenKey,$valueKey);
        if(isset(
$children[$elementName])){
            if(
is_array($children[$elementName])){
                if(
$first){
                   
$temp = $children[$elementName];
                    unset(
$children[$elementName]);
                   
$children[$elementName][] = $temp;
                   
$first=false;
                }
               
$children[$elementName][] = $value;
            }else{
               
$children[$elementName] = array($children[$elementName],$value);
            }
        }
        else{
           
$children[$elementName] = $value;
        }
    }
    if(
$children){
        if(
$childrenKey){$return[$childrenKey] = $children;}
        else{
$return = array_merge($return,$children);}
    }

   
$attributes = array();
    foreach(
$xml->attributes() as $name=>$value){
       
$attributes[$name] = trim($value);
    }
    if(
$attributes){
        if(
$attributesKey){$return[$attributesKey] = $attributes;}
        else{
$return = array_merge($return, $attributes);}
    }

    return
$return;
}
?>
up
-1
walter
7 years ago
Working fix for the infamous SimpleXML + memcache bug.

Improves code at http://tinyurl.com/bmoon-simplexml to actually work for arbitrary-depth structures.  (Because neither the function nor the json_decode(json_encode($obj)) hack listed there worked for me.)

There's probably some superfluous code in here that could be improved on -- but it works!

<?php
# convert a structure that may include objects to a pure
# array-based structure (that can be stored in memcache)
#  ... includes support for simplexml!
# (nb: may have problems with infinite recursive structs)
function enforce_array($obj) {
 
$array = (array)$obj;
  if(empty(
$array)) {
  
$array = '';
  }
  else {
   foreach(
$array as $key=>$value) {
    if(!
is_scalar($value)) {
     if(
is_a($value,'SimpleXMLElement')) {
     
$tmp = memcache_objects_to_array($value);
      if(!
is_array($tmp)) {
      
$tmp = ''.$value;
      }
     
$array[$key] = $tmp;
     }
     else {
     
$array[$key] = enforce_array($value);
     }
    }
    else {
    
$array[$key] = $value;
    }
   }
  }
  return
$array;
}
?>
up
-3
Tim Adam Perez
2 years ago
XML to Array in a single line:
$array = (array) simplexml_load_string($xml);

Enjoy!
To Top