xml2array() - XML Parser for PHP

xml2arry() Logo

xml2array() is a easy to use PHP function that will convert the given XML text to an array in the XML structure. Kind of like my Javascript xml2array() function.

Demo

See a Sample - the output of this function.

See a demo.

Code

<?php
/**
 * xml2array() will convert the given XML text to an array in the XML structure.
 * Link: http://www.bin-co.com/php/scripts/xml2array/
 * Arguments : $contents - The XML text
 *                $get_attributes - 1 or 0. If this is 1 the function will get the attributes as well as the tag values - this results in a different array structure in the return value.
 * Return: The parsed XML in an array form.
 */
function xml2array($contents$get_attributes=1) {
    if(!
$contents) return array();

    if(!
function_exists('xml_parser_create')) {
        
//print "'xml_parser_create()' function not found!";
        
return array();
    }
    
//Get the XML parser of PHP - PHP must have this module for the parser to work
    
$parser xml_parser_create();
    
xml_parser_set_option$parserXML_OPTION_CASE_FOLDING);
    
xml_parser_set_option$parserXML_OPTION_SKIP_WHITE);
    
xml_parse_into_struct$parser$contents$xml_values );
    
xml_parser_free$parser );

    if(!
$xml_values) return;//Hmm...

    //Initializations
    
$xml_array = array();
    
$parents = array();
    
$opened_tags = array();
    
$arr = array();

    
$current = &$xml_array;

    
//Go through the tags.
    
foreach($xml_values as $data) {
        unset(
$attributes,$value);//Remove existing values, or there will be trouble

        //This command will extract these variables into the foreach scope
        // tag(string), type(string), level(int), attributes(array).
        
extract($data);//We could use the array by itself, but this cooler.

        
$result '';
        if(
$get_attributes) {//The second argument of the function decides this.
            
$result = array();
            if(isset(
$value)) $result['value'] = $value;

            
//Set the attributes too.
            
if(isset($attributes)) {
                foreach(
$attributes as $attr => $val) {
                    if(
$get_attributes == 1$result['attr'][$attr] = $val//Set all the attributes in a array called 'attr'
                    /**  :TODO: should we change the key name to '_attr'? Someone may use the tagname 'attr'. Same goes for 'value' too */
                
}
            }
        } elseif(isset(
$value)) {
            
$result $value;
        }

        
//See tag status and do the needed.
        
if($type == "open") {//The starting of the tag '<tag>'
            
$parent[$level-1] = &$current;

            if(!
is_array($current) or (!in_array($tagarray_keys($current)))) { //Insert New tag
                
$current[$tag] = $result;
                
$current = &$current[$tag];

            } else { 
//There was another element with the same tag name
                
if(isset($current[$tag][0])) {
                    
array_push($current[$tag], $result);
                } else {
                    
$current[$tag] = array($current[$tag],$result);
                }
                
$last count($current[$tag]) - 1;
                
$current = &$current[$tag][$last];
            }

        } elseif(
$type == "complete") { //Tags that ends in 1 line '<tag />'
            //See if the key is already taken.
            
if(!isset($current[$tag])) { //New Key
                
$current[$tag] = $result;

            } else { 
//If taken, put all things inside a list(array)
                
if((is_array($current[$tag]) and $get_attributes == 0)//If it is already an array...
                        
or (isset($current[$tag][0]) and is_array($current[$tag][0]) and $get_attributes == 1)) {
                    
array_push($current[$tag],$result); // ...push the new element into that array.
                
} else { //If it is not an array...
                    
$current[$tag] = array($current[$tag],$result); //...Make it an array using using the existing value and the new value
                
}
            }

        } elseif(
$type == 'close') { //End of tag '</tag>'
            
$current = &$parent[$level-1];
        }
    }

    return(
$xml_array);
}

Comments

eviL3 at 20 Jan, 2007 04:51
This seems to be the best xml parsing function that exists...

I'm very impressed.

I was wondering what's the license of the function? I'd like to use it for GPL projects, is that okay?

Thanks!
Reply to this.
Binny V A at 10 Feb, 2007 10:27
Sorry I did not specify the license - its in BSD License. Feel free to use it
anywhere.
Reply to this.
Anonymous at 09 Feb, 2007 05:02
Ok We now have the data in arrays but how do I call the data back from the arrays say

$contents = file_get_contents('sample.xml');//Or however you what it
$result = xml2array($contents);
so if one of my arrays is called say LAT and has a value of 100 how do I reference
it in my php? say echo $LAT[0];
//print_r($result);
Reply to this.
Binny V A at 10 Feb, 2007 10:31
If you do a print_r() with the resulting array(in the example it is $result), you will see the structure of the Array - you will understand how to refer it.
Reply to this.
Justin at 09 Dec, 2007 07:49
Can you please give an example of how to reference the information in the array?
Reply to this.
Pete at 04 Mar, 2007 06:56
I am a beginner at php, would it be possible to give me an example of how to read the array values into variables to upload to a mysql database?
Thanks
Reply to this.
Binny V A at 05 Mar, 2007 04:30
Its easy - I cannot give the answer here as I need to know the fields in your table to write the query.
Reply to this.
marije at 10 Mar, 2007 10:46
I have a xml node, containing html tags such as

and <li> and and they are not giving back the way I would want it. Is there a solution for this ??

example node:
<Tekst>

xxxxx.</li>
<li>yyyyy.</li>
<li>vvvvv.</li>
<li>qqqqq.</li>
News



zzzzz.




</Tekst>

$contents,0 gives : Array ( [p] => xxxxx. )
$contents gives : Array ( [p] => Array ( [value] => xxxxx. [attr] => Array ( [align] => justify ) ) )

Reply to this.
Neil at 30 May, 2007 06:19
Just looking at the code, a little confused. Where is this $level variable set?
Reply to this.
Binny V A at 31 May, 2007 06:54
Good question! The $level variable is one of the variables that is created by the statement 'extract($data);'. The other variables created are tag(string), type(string), level(int), attributes(array).

Sorry about the confusion. If you have any more doubts(I am sure you will - the code is complicated, don't hesitate to email me. My email is binnyva, gmail.
Reply to this.
Anonymous at 30 Jul, 2007 01:44
nice function, however it doesn't help when the number of elements is random. i.e.

the following xml, the message array contains 2 elements
<messageList>
<message>
<from>2</from>
<to>1</to>
<text>adf</text>
</message>
<message>
<from>3</from>
<to>4</to>
<text>bla adf</text>
</message>
</messageList>


in this case the message array contains 4 elements.
<messageList>
<message>
<from>2</from>
<to>1</to>
<text>adf</text>
</message>
</messageList>

There's isn't an easy way to determine how many messages are being passed.
Reply to this.
Binny V A at 01 Aug, 2007 06:07
True - you have to know the schema of the XML beforehand. This is a big defect of this library. Unfortunately, this cannot be solved without compromising the simplicity of the function.
Reply to this.
LT at 08 May, 2008 07:18
If you don't like actual way:


} elseif($type == "complete") { //Tags that ends in 1 line '<tag />'
//See if the key is already taken.
if(!isset($current[$tag])) { //New Key
$current[$tag] = array($result);

// last line just creates first element already in the array.
// enjoy!
Reply to this.
Me at 19 Sep, 2007 01:51
Man, this is really the simpliest xml parser that i found, and the best, if you know the xml schema, for my app it will be used for a webservice, so i'll know the schema before.
Reply to this.
sopppas at 30 Sep, 2007 09:55
add utf8_decode at line 33 for utf8 support:

if(isset($value)) $result['value'] = utf8_decode($value);

great piece of coding!
Reply to this.
Mike at 16 Oct, 2007 07:49
Thanks, this parser works really well.

I just have a quick question, how would i go about putting the resulting data into a mysql database?

I am a real newbie and cant for the life of me see/understand how to do it.
Reply to this.
jonal at 24 Oct, 2007 02:41
First of all! Your parser actually made my day! Excellent work! :-)
Reply to this.
Wim at 30 Oct, 2007 12:41
Great parser!

However, I am looking for a result which is somewhere in between of the 2 modes results this function is producing. I would like the attribute value of a tag to be included like the other tags inside the attributed tag in the result array, but without everything being array values. Is there a simple way of doing this?

like this: xml: <home id="1045">100000....y</home>

In the result array it should look like: home[id], home[price], home[available] etc.



Reply to this.
DaHopi at 31 Oct, 2007 06:08
Great! I'm impressed.
Best function i found in the net..
Greetz from Germany and thanks a lot!
Reply to this.
GrwN at 12 Nov, 2007 02:58
Idd, Great Parser!
I'm planning to use this for an API module i'm writing.
If it's ok by you, i'm gonna publish it with this parser.
Greets, GrwN
Reply to this.
Deepak at 05 Dec, 2007 12:28
This is the wonderful code.no doubt abt it?
but just i wants to know that how to extract the array results and store that value in a variable like $xyz.so on...
Just i wants to enter that variable in my database after retriving these values from the xml file.
Reply to this.
Pk at 07 Jan, 2008 03:43
Hi,
this parser works really well,
but i have a problem under php 5.2.4 that return
"Fatal error: Cannot use string
offset as an array in"

This is my code:

$parsedBis = xml2array($xmlfileBis,0);
print_r($parsedBis);

output:
Array
(
[products] => Array
(
[categories] =>
)

)


Fatal error: Cannot use string offset as an array in /prod/doc/site/products/index.php on line 18



PS
under php 5.1.6 and php 4 it works correctly

Reply to this.
Binny V A at 16 Jan, 2008 11:19
Hmm - never ran across that error. I think its a bug in that specific PHP version - although I am not sure.
Reply to this.
David at 21 Jan, 2008 05:16
Is there a reverse function, array2xml?
Reply to this.
Mihai at 27 Jan, 2008 07:45
Really great function! Marvelous!

To get the results you can use:
print_r ($array['rss']['channel']['item'][$i]['title']['value']);

if you look into an RSS feed from a weblog you can find the same dropdown structure. You can then adapt it to your needs!

Cheers Binny! Thanks!
Reply to this.
Anonymous at 22 Feb, 2008 02:30
This routine doesn't store an array with one element in the same manner as multiple entry arrays.
I'm using the eBay APIs which may return one or more elements. The XML structure is the same regardless of the number of entries.

Also I suggest adding a version number to the header comments.

Single entry:
Array
(
[Item] => Array
(
[ItemID] => Array
(
[value] => 150216600790
)

Multiple entries:
Array
(
[Item] => Array
(
[0] => Array
(
[ItemID] => Array
(
[value] => 150216600790
)


Reply to this.
Jake at 19 Mar, 2008 12:11
If I include html in the xml, how do i get it to parse correctly?
Reply to this.
Anonymous at 19 Mar, 2008 02:21
Good work! Have tried out a lot of parsers for my project and they all sucked except this one! This was also the simplest. Thanks for providing it!
// Mikael from Sweden
Reply to this.
Anonymous at 10 Apr, 2008 12:13
Is there a way for the code to continue even if it finds a special chars in the XML (ie: Éé)
Reply to this.
Anonymous at 10 Apr, 2008 12:40
Is there a way fot special char. to be display (ie: Éééé) the code won't go past an accent.

thanks
Reply to this.
Binny V A at 13 Apr, 2008 10:04
I am looking into this issue - this page will be updated once I fix this bug.
Reply to this.
Anonymous at 25 Apr, 2008 04:00
Hi, I can get the value inside xml tags but I can't get the tag name itself!
Example:

XML CODE

<general>
<context>default</context>
<srvlookup>yes</srvlookup>
</general>

What I want is to parse the tags and their contents so I can write it into a text file. Example:

[general]
context=default
srvlookup=yes

I get the value with: echo $array['general']['context']['value'];

Any idea on how to get the tag's name? Thank you.
Reply to this.
Anonymous at 25 Apr, 2008 04:54
After lots of research I finally managed to make it, maybe it's useful for somebody. This is what worked for me:

while (list($i) = each ($result)) {
while (list($j) = each ($result[$i])){
echo "[".$j."]
";
while (list($k) = each ($result[$i][$j])){
echo $k."=";
while(list($h) = each ($result[$i][$j][$k])){
echo $result[$i][$j][$k][$h]."
";
}
}
echo "
";
}
}
Reply to this.
Anonymous at 01 May, 2008 10:01
Below my schema,
Can anyone give me a hint, how to read the values IN trkpt....
Thanks....


“<?xml version="1.0" encoding="UTF-8" standalone="no" ?>”
<gpx
xmlns="http://www.topografix.com/GPX/1/1"
<metadata>
</metadata>
<trk>
<name>Huidig nummer: 26 APR 2008 08:12
</name>
<trkseg>
<trkpt lat="52.219812" lon="5.996262">
<ele>11.19</ele>
<time>2008-04-26T06:12:10Z</time>
<extensions>
<gpxtpx:TrackPointExtension>
<gpxtpx:atemp>27.3</gpxtpx:atemp>
</gpxtpx:TrackPointExtension>
</extensions>
</trkpt>

<trkpt lat="52.219872" lon="5.996397">
More trkpt…


</trkseg>
</trk>
</gpx>
Reply to this.
Saul Rosenberg at 06 May, 2008 07:41
Love the parser. Works phenomenally on Firefox (development platform). I am running up against a problem in IE7 that throws an error at:

if(assoc && arr_count == 1) {
if(arr[key]) { //If another element exists with the same tag name before,
// put it in a numeric array.
//Find out how many time this parent made its appearance

The error is about arr[key] and says that "undefined is null or not an object".

Is there an update to XML2Array() that fixes this?
Reply to this.
Binny V A at 06 May, 2008 11:23
I am not sure I understand - this is a server side script - browser differences don't affect it.
Reply to this.
Saul Rosenberg at 08 May, 2008 05:26
My mistake... there is an xml2array() function defined in javascript as well. I goofed and went to the wrong site. I am going to give this script a whirl as well because I have a php side XML parsing need. Thanks!
Reply to this.
Anonymous at 06 May, 2008 11:01
I'm facing the same problem as "Anonymous at 22 Feb, 2008 02:30"
reading the array's.
Is there a fix for this problem?

Anonymous at 22 Feb, 2008 02:30
This routine doesn't store an array with one element in the same manner as multiple entry arrays.
I'm using the eBay APIs which may return one or more elements. The XML structure is the same regardless of the number of entries.
Reply to this.
LT at 08 May, 2008 06:49
Thanks for posting it!
It's really working :)
Reply to this.
LT at 08 May, 2008 07:22
If you will have randomize number of elements in the tags, change your code to this:


} elseif($type == "complete") { //Tags that ends in 1 line '<tag />'
//See if the key is already taken.
if(!isset($current[$tag])) { //New Key
$current[$tag] = array($result);

// last line just creates first element already in the array.
// enjoy!
Reply to this.
Comment


Comment




Comment Formating : HTML tags a, strong, em, b, i, code, pre, p and br allowed. Other tags will be shown as code(< will become &lt;). Urls, Line breaks will be auto-formated.
Subscribe to Feed