Simplexml load string php error

(PHP 5, PHP 7, PHP 8)

(PHP 5, PHP 7, PHP 8)

simplexml_load_string
Интерпретирует строку с XML в объект

Описание

simplexml_load_string(
    string $data,
    ?string $class_name = SimpleXMLElement::class,
    int $options = 0,
    string $namespace_or_prefix = «»,
    bool $is_prefix = false
): SimpleXMLElement|false

Список параметров

data

Правильно сформированная XML-строка

class_name

Вы можете использовать этот необязательный параметр для того, чтобы функция
simplexml_load_string() возвращала объект указанного класса. Этот
класс должен расширять класс SimpleXMLElement.

options

Начиная с Libxml 2.6.0, вы также можете использовать параметр
options, чтобы указать дополнительные параметры Libxml.

namespace_or_prefix

Префикс пространства имён или URI.

is_prefix

true, если namespace_or_prefix является префиксом, и false, если URI;
по умолчанию равен false.

Возвращаемые значения

Возвращает объект (object) класса SimpleXMLElement со
свойствами, содержащими данные, которые хранятся внутри XML-документа или false в случае возникновения ошибки.

Внимание

Эта функция может возвращать как логическое значение false, так и значение не типа boolean, которое приводится к false. За более подробной информацией обратитесь к разделу Булев тип. Используйте оператор === для проверки значения, возвращаемого этой функцией.

Ошибки

Генерирует сообщение об ошибке уровня E_WARNING для
каждой ошибки, найденной в XML-данных.

Примеры

Пример #1 Интерпретация XML-строки


<?php
$string
= <<<XML
<?xml version='1.0'?>
<document>
<title>Что 40?</title>
<from>Джо</from>
<to>Джейн</to>
<body>
Я знаю, что это - ответ. В чем заключается вопрос?
</body>
</document>
XML;$xml = simplexml_load_string($string);print_r($xml);
?>

Результат выполнения данного примера:

SimpleXMLElement Object
(
  [title] => Что 40?
  [from] => Джо
  [to] => Джейн
  [body] =>
   Я знаю, что это - ответ. В чем заключается вопрос?
)

Здесь можно использовать $xml->body и т.д.

Смотрите также

  • simplexml_load_file() — Интерпретирует XML-файл в объект
  • SimpleXMLElement::__construct() — Создание нового объекта SimpleXMLElement
  • Работа с ошибками XML
  • libxml_use_internal_errors() — Отключение ошибок libxml и передача полномочий по выборке и обработке
    информации об ошибках пользователю
  • Базовое использование SimpleXML

ascammon at hotmail dot com

12 years ago


I had a hard time finding this documented, so posting it here in case it helps someone:

If you want to use multiple libxml options, separate them with a pipe, like so:

<?php
$xml
= simplexml_load_string($string, 'SimpleXMLElement', LIBXML_NOCDATA | LIBXML_NOBLANKS);
?>


Diego Araos, diego at klapmedia dot com

12 years ago


A simpler way to transform the result into an array (requires json module).

<?php

function object2array($object) { return @json_decode(@json_encode($object),1); }

?>



Example:

<?php

$xml_object
=simplexml_load_string('<SOME XML DATA');

$xml_array=object2array($xml_object);

?>


rowan dot collins at gmail dot com

14 years ago


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

?>


bojan

15 years ago


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

)

*/

?>


meustrus

7 years ago


Be careful checking for parse errors. An empty SimpleXMLElement may resolve to FALSE, and if your XML contains no text or only contains namespaced elements your error check may be wrong. Always use `=== FALSE` when checking for parse errors.

<?php

$xml

= <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<ns1:Root xmlns:ns1="http://example.com/custom">
<ns1:Node>There's stuff here</ns1:Node>
</ns1:Root>
XML;$simplexml = simplexml_load_string($xml);// This prints "Parse Error".
echo ($simplexml ? 'Valid XML' : 'Parse Error'), PHP_EOL;// But this prints "There's stuff here", proving that
// the SimpleXML object was created successfully.
echo $simplexml->children('http://example.com/custom')->Node, PHP_EOL;// Use this instead:
echo ($simplexml !== FALSE ? 'Valid XML' : 'Parse Error'), PHP_EOL;?>

See:

https://bugs.php.net/bug.php?id=31045
https://bugs.php.net/bug.php?id=30972
https://bugs.php.net/bug.php?id=69596


mindpower

16 years ago


A simple extension that adds a method for retrieving a specific attribute:

<?php
class simple_xml_extended extends SimpleXMLElement
{
    public    function   
Attribute($name)
    {
        foreach(
$this->Attributes() as $key=>$val)
        {
            if(
$key == $name)
                return (string)
$val;
        }
    }

}

$xml = simplexml_load_string('
<xml>
  <dog type="poodle" owner="Mrs Smith">Rover</dog>
</xml>'
, 'simple_xml_extended');

echo

$xml->dog->Attribute('type');?>

outputs 'poodle'

I prefer to use this technique rather than typecasting attributes.


nbijnens at servs dot eu

15 years ago


Please note that not all LIBXML options are supported with the options argument.

For instance LIBXML_XINCLUDE does not work. But there is however a work around:

<?php
$xml
= new DOMDocument();
$xml->loadXML ($XMLString);$xml->xinclude();
$xml = simplexml_import_dom($xml);?>


amir_abiri at ipcmedia dot com

15 years ago


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(). "nn";
$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(). "nn";
$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>


hattori at hanso dot com

15 years ago


Theres a problem with the below workaround when serializing fields containing html CDATA. For any other content type then HTML try to modfiy function parseCDATA.
Just add these lines before serializing.
This is also a workaround for this bug http://bugs.php.net/bug.php?id=42001

<?PHP
if(strpos($content, '<![CDATA[')) {
   function
parseCDATA($data) {
      return
htmlentities($data[1]);
   }
  
$content = preg_replace_callback(
     
'#<![CDATA[(.*)]]>#',
     
'parseCDATA',
     
str_replace("n", " ", $content)
   );
}
?>


javalc6 at gmail dot com

14 years ago


I wanted to convert an array containing strings and other arrays of the same type into a simplexml object.

Here is the code of the function array2xml that I've developed to perform this conversion. Please note that this code is simple without any checks.

<?php

function array2xml($array, $tag) {

    function

ia2xml($array) {

       
$xml="";

        foreach (
$array as $key=>$value) {

            if (
is_array($value)) {

               
$xml.="<$key>".ia2xml($value)."</$key>";

            } else {

               
$xml.="<$key>".$value."</$key>";

            }

        }

        return
$xml;

    }

    return

simplexml_load_string("<$tag>".ia2xml($array)."</$tag>");

}
$test['type']='lunch';

$test['time']='12:30';

$test['menu']=array('entree'=>'salad', 'maincourse'=>'steak');

echo

array2xml($test,"meal")->asXML();

?>


jeff at creabilis dot com

13 years ago


If you want to set the charset of the outputed xml, simply set the encoding attribute like this :

<?php simplexml_load_string('<?xml version="1.0" encoding="utf-8"?><xml/>'); ?>



The generated xml outputed by $xml->asXML will containt accentuated characters like 'é' instead of é.

Hope this help


Julio Cesar Oliveira

13 years ago


The XML2Array func now Recursive!

<?php
function XML2Array ( $xml , $recursive = false )
{
    if ( !
$recursive )
    {
       
$array = simplexml_load_string ( $xml ) ;
    }
    else
    {
       
$array = $xml ;
    }
$newArray = array () ;
   
$array = ( array ) $array ;
    foreach (
$array as $key => $value )
    {
       
$value = ( array ) $value ;
        if ( isset (
$value [ 0 ] ) )
        {
           
$newArray [ $key ] = trim ( $value [ 0 ] ) ;
        }
        else
        {
           
$newArray [ $key ] = XML2Array ( $value , true ) ;
        }
    }
    return
$newArray ;
}
?>


artistan at gmail dot com

7 years ago


Here is my update to Bob's simple SimpleXML wrapper function.
I noticed his version would turn an empty SimpleXMLElement into an empty array.

<?php
   
/**
     * http://php.net/manual/en/function.simplexml-load-string.php#91564
     *
     * bool/array unserialize_xml ( string $input [ , callback $callback ] )
     * Unserializes an XML string, returning a multi-dimensional associative array, optionally runs a callback on all non-array data
     * Returns false on all failure
     * Notes:
     * Root XML tags are stripped
     * Due to its recursive nature, unserialize_xml() will also support SimpleXMLElement objects and arrays as input
     * Uses simplexml_load_string() for XML parsing, see SimpleXML documentation for more info
     *
     * @param $input
     * @param null $callback
     * @param bool $recurse
     * @return array|mixed
     *
     */
   
function unserialize_xml($input, $callback = null, $recurse = false)
    {
       
// Get input, loading an xml string with simplexml if its the top level of recursion
       
$data = ((!$recurse) && is_string($input))? simplexml_load_string($input): $input;
       
// Convert SimpleXMLElements to array
       
if ($data instanceof SimpleXMLElement){
            if(!empty(
$data)){
               
$data = (array) $data;
            } else {
               
$data = '';
            }
        }
       
// Recurse into arrays
       
if (is_array($data)) foreach ($data as &$item) $item = unserialize_xml($item, $callback, true);
       
// Run callback and return
       
return (!is_array($data) && is_callable($callback))? call_user_func($callback, $data): $data;
    }
?>


AllenJB

10 years ago


<?php
$xml
= json_decode(json_encode((array) simplexml_load_string($string)), 1);
?>

A reminder that json_encode attempts to convert data to UTF-8 without specific knowledge of the source encoding. This method can cause encoding issues if you're not working in UTF-8.

Bob

13 years ago


Here is my simple SimpleXML wrapper function.
As far as I can tell, it does the same as Julio Cesar Oliveira's (above).
It parses an XML string into a multi-dimensional associative array.
The second argument is a callback that is run on all data (so for example, if you want all data trimmed, like Julio does in his function, just pass 'trim' as the second arg).
<?php
function unserialize_xml($input, $callback = null, $recurse = false)
/* bool/array unserialize_xml ( string $input [ , callback $callback ] )
* Unserializes an XML string, returning a multi-dimensional associative array, optionally runs a callback on all non-array data
* Returns false on all failure
* Notes:
    * Root XML tags are stripped
    * Due to its recursive nature, unserialize_xml() will also support SimpleXMLElement objects and arrays as input
    * Uses simplexml_load_string() for XML parsing, see SimpleXML documentation for more info
*/
{
   
// Get input, loading an xml string with simplexml if its the top level of recursion
   
$data = ((!$recurse) && is_string($input))? simplexml_load_string($input): $input;
   
// Convert SimpleXMLElements to array
   
if ($data instanceof SimpleXMLElement) $data = (array) $data;
   
// Recurse into arrays
   
if (is_array($data)) foreach ($data as &$item) $item = unserialize_xml($item, $callback, true);
   
// Run callback and return
   
return (!is_array($data) && is_callable($callback))? call_user_func($callback, $data): $data;
}
?>

m dot ament at mailcity dot com

15 years ago


Warning:

The parsing of XML-data will stop when reaching character 0.
Please avoid this character in your XML-data.


Pedro

15 years ago


Attention:

simplexml_load_string has a problem with entities other than (&lt;, &gt;, &amp;, &quot; and &apos;).

Use numeric character references instead!


dkrnl at yandex dot ru

9 years ago

cellog at php dot net

18 years ago


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.

}

?>


Maciek Ruckgaber <maciekrb at gmai dot com>

17 years ago


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:

<?php

$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:

<?php

$xml
= simplexml_load_string($xmlstr);

echo
$xml; // this will echo 2328  (string)

?>


erguven dot m at gmail dot com

5 years ago


if you want to use a class which exists in a name space, use it full name. simple_load_string did not recognize short one.

class.new.php
<?php
namespace foobar;

class new extends

SimpleXMLElement
{
    public function do()
    {
        echo
"done";
    }
}
?>

false.php
<?php
use foobarnew;$result = simplexml_load_string($xml, 'new'); // it gives warning
$result->do(); // fatal error
?>

true.php
<?php
use foobarnew;
$result = simplexml_load_string($xml, 'foobarnew');$result->do(); // prints done
?>


I’m trying to load parse a Google Weather API response (Chinese response).

Here is the API call.

// This code fails with the following error
$xml = simplexml_load_file('http://www.google.com/ig/api?weather=11791&hl=zh-CN');

( ! ) Warning: simplexml_load_string()
[function.simplexml-load-string]:
Entity: line 1: parser error : Input
is not proper UTF-8, indicate encoding
! Bytes: 0xB6 0xE0 0xD4 0xC6 in
C:htdocsweather.php on line 11

Why does loading this response fail?

How do I encode/decode the response so that simplexml loads it properly?

Edit: Here is the code and output.

<?php
$googleData = file_get_contents('http://www.google.com/ig/api?weather=11102&hl=zh-CN');
$xml = simplexml_load_string($googleData);

( ! ) Warning: simplexml_load_string()
[function.simplexml-load-string]:
Entity: line 1: parser error : Input
is not proper UTF-8, indicate encoding
! Bytes: 0xB6 0xE0 0xD4 0xC6 in
C:htdocstest4.php on line 3 Call
Stack
Time Memory Function Location 1 0.0020 314264 {main}(
) ..test4.php:0
2 0.1535 317520 simplexml_load_string
( string(1364) ) ..test4.php:3

( ! ) Warning: simplexml_load_string()
[function.simplexml-load-string]:
t_system
data=»SI»/>

( ! ) Warning: simplexml_load_string()
[function.simplexml-load-string]: ^ in
C:htdocstest4.php on line 3 Call
Stack
Time Memory Function Location 1 0.0020 314264 {main}(
) ..test4.php:0
2 0.1535 317520 simplexml_load_string
( string(1364) ) ..test4.php:3

nyedidikeke's user avatar

nyedidikeke

6,5427 gold badges44 silver badges56 bronze badges

asked May 24, 2010 at 18:26

John Himmelman's user avatar

John HimmelmanJohn Himmelman

21.2k22 gold badges65 silver badges80 bronze badges

0

The problem here is that SimpleXML doesn’t look at the HTTP header to determine the character encoding used in the document and simply assumes it’s UTF-8 even though Google’s server does advertise it as

Content-Type: text/xml; charset=GB2312

You can write a function that will take a look at that header using the super-secret magic variable $http_response_header and transform the response accordingly. Something like that:

function sxe($url)
{   
    $xml = file_get_contents($url);
    foreach ($http_response_header as $header)
    {   
        if (preg_match('#^Content-Type: text/xml; charset=(.*)#i', $header, $m))
        {   
            switch (strtolower($m[1]))
            {   
                case 'utf-8':
                    // do nothing
                    break;

                case 'iso-8859-1':
                    $xml = utf8_encode($xml);
                    break;

                default:
                    $xml = iconv($m[1], 'utf-8', $xml);
            }
            break;
        }
    }

    return simplexml_load_string($xml);
}

answered May 25, 2010 at 3:28

Josh Davis's user avatar

1

Update: I can reproduce the problem. Also, Firefox is auto-sniffing the character set as «chinese simplified» when I output the raw XML feed. Either the Google feed is serving incorrect data (Chinese Simplified characters instead of UTF-8 ones), or it is serving different data when not fetched in a browser — the content-type header in Firefox clearly says utf-8.

Converting the incoming feed from Chinese Simplified (GB18030, this is what Firefox gave me) into UTF-8 works:

 $incoming = file_get_contents('http://www.google.com/ig/api?weather=11791&hl=zh-CN');
 $xml = iconv("GB18030", "utf-8", $incoming);
 $xml = simplexml_load_string($xml);

it doesn’t explain nor fix the underlying problem yet, though. I don’t have time to take a deep look into this right now, maybe somebody else does. To me, it looks like Google are in fact serving incorrect data (which would surprise me. I didn’t know they made mistakes like us mortals. :P)

answered May 24, 2010 at 18:37

Pekka's user avatar

PekkaPekka

438k140 gold badges968 silver badges1083 bronze badges

5

Just came accross this.
This seems to work (the function itself I found on the web, just updated it a bit).:

header('Content-Type: text/html; charset=utf-8'); 


function getWeather() {

$requestAddress = "http://www.google.com/ig/api?weather=11791&hl=zh-CN";
// Downloads weather data based on location.
$xml_str = file_get_contents($requestAddress,0);
$xml_str = preg_replace("/(</?)(w+):([^>]*>)/", "$1$2$3", $xml_str); 

$xml_str = iconv("GB18030", "utf-8", $xml_str);


// Parses XML
$xml = new SimplexmlElement($xml_str, TRUE);
// Loops XML
$count = 0;
echo '<div id="weather">';

foreach($xml->weather as $item) {

    foreach($item->forecast_conditions as $new) {

        echo "<div class="weatherIcon">n";
         echo "<img src='http://www.google.com/" .$new->icon['data'] . "'   alt='".$new->condition['data']."'/><br>n";
        echo "<b>".$new->day_of_week['data']."</b><br>";
        echo "Low: ".$new->low['data']." &nbsp;High: ".$new->high['data']."<br>";
        echo "n</div>n";
        }

}

echo '</div>';
}


getWeather();

answered Nov 9, 2010 at 23:55

AR.'s user avatar

AR.AR.

1,9351 gold badge11 silver badges14 bronze badges

This is the script I have made in php to parse Google Weather API.

 <?php

function sxe($url)
{
$xml = file_get_contents($url);
foreach ($http_response_header as $header)
{
if (preg_match('#^Content-Type: text/xml; charset=(.*)#i', $header, $m))
{
switch (strtolower($m[1]))
{

case 'utf-8':
// do nothing
break;

case 'iso-8859-1':
$xml = utf8_encode($xml);
break;

default:
$xml = iconv($m[1], 'utf-8', $xml);
}
break;
}
}
return simplexml_load_string($xml);
}


$xml = simplexml_load_file('http://www.google.com/ig/api?weather=46360&h1=en-us');
$information = $xml->xpath("/xml_api_reply/weather/forecast_information");
$current = $xml->xpath("/xml_api_reply/weather/current_conditions");
$forecast = $xml->xpath("/xml_api_reply/weather/forecast_conditions");


print "<br><br><center><div style="border: 1px solid; background-color: #dddddd; background-image: url('http://mc-pdfd-live.dyndns.org/images/clouds.bmp'); width: 450">";


print "<br><h3>";
print $information[0]->city['data'] . "&nbsp;" . $information[0]->unit_system['data'] . "&nbsp;" .     $information[0]->postal_code['data'];
print "</h3>";
print "<div style="border: 1px solid; width: 320px">";
print "<table cellpadding="5px"><tr><td><h4>";
print "Now";
print "<br><br>";
print "<img src=http://www.google.com" . $current[0]->icon['data'] . ">&nbsp;";
print "</h4></td><td><h4>";
print "<br><br>";
print "&nbsp;" . $current[0]->condition['data'] . "&nbsp;";
print "&nbsp;" . $current[0]->temp_f['data'] . "&nbsp;°F";
print "<br>";
print "&nbsp;" . $current[0]->wind_condition['data'];
print "<br>";
print "&nbsp;" . $current[0]->humidity['data'];
print "<h4></td></tr></table></div>";




print "<table cellpadding="5px"><tr><td>";


print "<table cellpadding="5px"><tr><td><h4>";
print "Today";
print "<br><br>";
print "<img src=http://www.google.com" . $forecast[0]->icon['data'] . ">&nbsp;";
print "</h4></td><td><h4>";
print "<br><br>";
print  $forecast[0]->condition['data'];
print "<br>";
print  "High&nbsp;" . $forecast[0]->high['data'] . "&nbsp;°F";
print "<br>";
print  "Low&nbsp;" . $forecast[0]->low['data'] . "&nbsp;°F";
print "</h4></td></tr></table>";

print "<table cellpadding="5px"><tr><td><h4>";
print  $forecast[2]->day_of_week['data'];
print "<br><br>";
print "<img src=http://www.google.com" . $forecast[2]->icon['data'] . ">&nbsp;";
print "</h4></td><td><h4>";
print "<br><br>";
print  "&nbsp;" . $forecast[2]->condition['data'];
print "<br>";
print  "&nbsp;High&nbsp;" . $forecast[2]->high['data'] . "&nbsp;°F";
print "<br>";
print  "&nbsp;Low&nbsp;" . $forecast[2]->low['data'] . "&nbsp;°F";
print "</h4></td></tr></table>";


print "</td><td>";


print "<table cellpadding="5px"><tr><td><h4>";
print  $forecast[1]->day_of_week['data'];
print "<br><br>";
print "<img src=http://www.google.com" . $forecast[1]->icon['data'] . ">&nbsp;";
print "</h4></td><td><h4>";
print "<br><br>";
print  "&nbsp;" . $forecast[1]->condition['data'];
print "<br>";
print  "&nbsp;High&nbsp;" . $forecast[1]->high['data'] . "&nbsp;°F";
print "<br>";
print  "&nbsp;Low&nbsp;" . $forecast[1]->low['data'] . "&nbsp;°F";
print "</h4></td></tr></table>";

print "<table cellpadding="5px"><tr><td><h4>";
print  $forecast[3]->day_of_week['data'];
print "<br><br>";
print "<img src=http://www.google.com" . $forecast[3]->icon['data'] . ">&nbsp;";
print "</h4></td><td><h4>";
print "<br><br>";
print  "&nbsp;" . $forecast[3]->condition['data'];
print "<br>";
print  "&nbsp;High&nbsp;" . $forecast[3]->high['data'] . "&nbsp;°F";
print "<br>";
print  "&nbsp;Low&nbsp;" . $forecast[3]->low['data'] . "&nbsp;°F";
print "</h4></td></tr></table>";


print "</td></tr></table>";


print "</div></center>";


?>

answered May 24, 2011 at 15:57

cmluscco's user avatar

Try to add in the url query parameter eo = utf-8. In this case, the answer will be exclusively the UTF-8 encoding. It helped me.

http://www.google.com/ig/api?weather=?????&degree=??????&oe=utf-8&hl=es

answered Feb 10, 2012 at 14:24

Igor Vakulenko's user avatar

0

Содержание

  1. simplexml_load_string
  2. Описание
  3. Список параметров
  4. Возвращаемые значения
  5. Ошибки
  6. Примеры
  7. simplexml_load_string
  8. Description
  9. Parameters
  10. Return Values
  11. Errors/Exceptions
  12. Examples
  13. SimpleXML
  14. User Contributed Notes 32 notes

simplexml_load_string

(PHP 5, PHP 7, PHP 8)

simplexml_load_string — Интерпретирует строку с XML в объект

Описание

Получает правильно сформированную XML-строку и возвращает её как объект.

Список параметров

Правильно сформированная XML-строка

Вы можете использовать этот необязательный параметр для того, чтобы функция simplexml_load_string() возвращала объект указанного класса. Этот класс должен расширять класс SimpleXMLElement .

Начиная с Libxml 2.6.0, вы также можете использовать параметр options , чтобы указать дополнительные параметры Libxml.

Префикс пространства имён или URI.

true , если namespace_or_prefix является префиксом, и false , если URI; по умолчанию равен false .

Возвращаемые значения

Возвращает объект ( object ) класса SimpleXMLElement со свойствами, содержащими данные, которые хранятся внутри XML-документа или false в случае возникновения ошибки.

Эта функция может возвращать как логическое значение false , так и значение не типа boolean, которое приводится к false . За более подробной информацией обратитесь к разделу Булев тип. Используйте оператор === для проверки значения, возвращаемого этой функцией.

Ошибки

Генерирует сообщение об ошибке уровня E_WARNING для каждой ошибки, найденной в XML-данных.

Используйте функцию libxml_use_internal_errors() для того, чтобы подавить все ошибки XML, и функцию libxml_get_errors() для прохода по ним впоследствии.

Примеры

Пример #1 Интерпретация XML-строки

echo $xml -> dog -> Attribute ( ‘type’ );

I prefer to use this technique rather than typecasting attributes.

Please note that not all LIBXML options are supported with the options argument.

For instance LIBXML_XINCLUDE does not work. But there is however a work around:

= new DOMDocument ();
$xml -> loadXML ( $XMLString );

$xml -> xinclude ();
$xml = simplexml_import_dom ( $xml );

It doesn’t seem to be documented anywhere, but you can refer to an element «value» for the purpose of changing it like so:

= simplexml_load_string ( ‘ 1 ‘ );
echo $xml -> asXml (). «nn» ;

$xml -> number -> < 0 >= $xml -> number -> < 0 >+ 1 ;

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

= simplexml_load_string ( ‘ 1 ‘ );
echo $xml -> asXml (). «nn» ;

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

echo $xml -> asXml ();
?>

Both of the above cases would result in:

Theres a problem with the below workaround when serializing fields containing html CDATA. For any other content type then HTML try to modfiy function parseCDATA.
Just add these lines before serializing.
This is also a workaround for this bug http://bugs.php.net/bug.php?id=42001

if( strpos ( $content , ‘ )) <
function parseCDATA ( $data ) <
return htmlentities ( $data [ 1 ]);
>
$content = preg_replace_callback (
‘# #’ ,
‘parseCDATA’ ,
str_replace ( «n» , » » , $content )
);
>
?>

I wanted to convert an array containing strings and other arrays of the same type into a simplexml object.

Here is the code of the function array2xml that I’ve developed to perform this conversion. Please note that this code is simple without any checks.

function array2xml ( $array , $tag ) <

function ia2xml ( $array ) <
$xml = «» ;
foreach ( $array as $key => $value ) <
if ( is_array ( $value )) <
$xml .= » $key >» . ia2xml ( $value ). » $key >» ;
> else <
$xml .= » $key >» . $value . » $key >» ;
>
>
return $xml ;
>

return simplexml_load_string ( » $tag >» . ia2xml ( $array ). » $tag >» );
>

$test [ ‘type’ ]= ‘lunch’ ;
$test [ ‘time’ ]= ’12:30′ ;
$test [ ‘menu’ ]=array( ‘entree’ => ‘salad’ , ‘maincourse’ => ‘steak’ );

echo array2xml ( $test , «meal» )-> asXML ();
?>

If you want to set the charset of the outputed xml, simply set the encoding attribute like this :

( ‘ ‘ ); ?>

The generated xml outputed by $xml->asXML will containt accentuated characters like ‘é’ instead of é.

The XML2Array func now Recursive!

function XML2Array ( $xml , $recursive = false )
<
if ( ! $recursive )
<
$array = simplexml_load_string ( $xml ) ;
>
else
<
$array = $xml ;
>

$newArray = array () ;
$array = ( array ) $array ;
foreach ( $array as $key => $value )
<
$value = ( array ) $value ;
if ( isset ( $value [ 0 ] ) )
<
$newArray [ $key ] = trim ( $value [ 0 ] ) ;
>
else
<
$newArray [ $key ] = XML2Array ( $value , true ) ;
>
>
return $newArray ;
>
?>

Here is my update to Bob’s simple SimpleXML wrapper function.
I noticed his version would turn an empty SimpleXMLElement into an empty array.

/**
* http://php.net/manual/en/function.simplexml-load-string.php#91564
*
* bool/array unserialize_xml ( string $input [ , callback $callback ] )
* Unserializes an XML string, returning a multi-dimensional associative array, optionally runs a callback on all non-array data
* Returns false on all failure
* Notes:
* Root XML tags are stripped
* Due to its recursive nature, unserialize_xml() will also support SimpleXMLElement objects and arrays as input
* Uses simplexml_load_string() for XML parsing, see SimpleXML documentation for more info
*
* @param $input
* @param null $callback
* @param bool $recurse
* @return array|mixed
*
*/
function unserialize_xml ( $input , $callback = null , $recurse = false )
<
// Get input, loading an xml string with simplexml if its the top level of recursion
$data = ((! $recurse ) && is_string ( $input ))? simplexml_load_string ( $input ): $input ;
// Convert SimpleXMLElements to array
if ( $data instanceof SimpleXMLElement ) <
if(!empty( $data )) <
$data = (array) $data ;
> else <
$data = » ;
>
>
// Recurse into arrays
if ( is_array ( $data )) foreach ( $data as & $item ) $item = unserialize_xml ( $item , $callback , true );
// Run callback and return
return (! is_array ( $data ) && is_callable ( $callback ))? call_user_func ( $callback , $data ): $data ;
>
?>

The parsing of XML-data will stop when reaching character 0.
Please avoid this character in your XML-data.

simplexml_load_string has a problem with entities other than ( , &, » and ‘).

Use numeric character references instead!

Wrapper XMLReader class, for simple SAX-reading huge xml:
https://github.com/dkrnl/SimpleXMLReader

simplexml does not simply handle CDATA sections in a foreach loop.

= simplexml_load_string ( ‘

hi

two

one
two
‘ );
foreach((array) $sx as $tagname => $val ) <
if ( is_string ( $val )) <
// will go here
> elseif ( is_array ( $val )) <
// will go here because it happens multiple times
> elseif ( is_object ( $val )) <
// will go here because it contains tags
// will go here because it contains CDATA!
>
>
?>

To test in the loop, do this

if ( count ((array) $val ) == 0 ) <
// this is not a tag that contains other tags
$val = » . $val ;
// now the CDATA is revealed magically.
>
?>

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 😛

when you have something like:

=
2328
XML;
?>

you will have the simpleXML object «transformed» to the text() content:

= simplexml_load_string ( $xmlstr );
echo $xml ; // this will echo 2328 (string)
?>

if you want to use a class which exists in a name space, use it full name. simple_load_string did not recognize short one.

Источник

simplexml_load_string

(PHP 5, PHP 7, PHP 8)

simplexml_load_string — Interprets a string of XML into an object

Description

Takes a well-formed XML string and returns it as an object.

Parameters

A well-formed XML string

You may use this optional parameter so that simplexml_load_string() will return an object of the specified class. That class should extend the SimpleXMLElement class.

Since Libxml 2.6.0, you may also use the options parameter to specify additional Libxml parameters.

Namespace prefix or URI.

true if namespace_or_prefix is a prefix, false if it’s a URI; defaults to false .

Return Values

Returns an object of class SimpleXMLElement with properties containing the data held within the xml document, or false on failure.

This function may return Boolean false , but may also return a non-Boolean value which evaluates to false . Please read the section on Booleans for more information. Use the === operator for testing the return value of this function.

Errors/Exceptions

Produces an E_WARNING error message for each error found in the XML data.

Use libxml_use_internal_errors() to suppress all XML errors, and libxml_get_errors() to iterate over them afterwards.

Examples

Example #1 Interpret an XML string

echo $xml -> dog -> Attribute ( ‘type’ );

I prefer to use this technique rather than typecasting attributes.

If you want to set the charset of the outputed xml, simply set the encoding attribute like this :

( ‘ ‘ ); ?>

The generated xml outputed by $xml->asXML will containt accentuated characters like ‘é’ instead of é.

if you want to use a class which exists in a name space, use it full name. simple_load_string did not recognize short one.

class.new.php
namespace foo bar ;

class new extends SimpleXMLElement
<
public function do()
<
echo «done» ;
>
>
?>

false.php
use foo bar new;

$result = simplexml_load_string ( $xml , ‘new’ ); // it gives warning
$result -> do (); // fatal error
?>

true.php
use foo bar new;
$result = simplexml_load_string ( $xml , ‘foobarnew’ );

$result -> do (); // prints done
?>

The XML2Array func now Recursive!

function XML2Array ( $xml , $recursive = false )
<
if ( ! $recursive )
<
$array = simplexml_load_string ( $xml ) ;
>
else
<
$array = $xml ;
>

$newArray = array () ;
$array = ( array ) $array ;
foreach ( $array as $key => $value )
<
$value = ( array ) $value ;
if ( isset ( $value [ 0 ] ) )
<
$newArray [ $key ] = trim ( $value [ 0 ] ) ;
>
else
<
$newArray [ $key ] = XML2Array ( $value , true ) ;
>
>
return $newArray ;
>
?>

It doesn’t seem to be documented anywhere, but you can refer to an element «value» for the purpose of changing it like so:

= simplexml_load_string ( ‘ 1 ‘ );
echo $xml -> asXml (). «nn» ;

$xml -> number -> < 0 >= $xml -> number -> < 0 >+ 1 ;

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

= simplexml_load_string ( ‘ 1 ‘ );
echo $xml -> asXml (). «nn» ;

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

echo $xml -> asXml ();
?>

Both of the above cases would result in:

Theres a problem with the below workaround when serializing fields containing html CDATA. For any other content type then HTML try to modfiy function parseCDATA.
Just add these lines before serializing.
This is also a workaround for this bug http://bugs.php.net/bug.php?id=42001

if( strpos ( $content , ‘ )) <
function parseCDATA ( $data ) <
return htmlentities ( $data [ 1 ]);
>
$content = preg_replace_callback (
‘# #’ ,
‘parseCDATA’ ,
str_replace ( «n» , » » , $content )
);
>
?>

Please note that not all LIBXML options are supported with the options argument.

For instance LIBXML_XINCLUDE does not work. But there is however a work around:

= new DOMDocument ();
$xml -> loadXML ( $XMLString );

$xml -> xinclude ();
$xml = simplexml_import_dom ( $xml );

simplexml_load_string has a problem with entities other than ( , &, » and ‘).

Use numeric character references instead!

The parsing of XML-data will stop when reaching character 0.
Please avoid this character in your XML-data.

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 😛

when you have something like:

=
2328
XML;
?>

you will have the simpleXML object «transformed» to the text() content:

= simplexml_load_string ( $xmlstr );
echo $xml ; // this will echo 2328 (string)
?>

Wrapper XMLReader class, for simple SAX-reading huge xml:
https://github.com/dkrnl/SimpleXMLReader

simplexml does not simply handle CDATA sections in a foreach loop.

= simplexml_load_string ( ‘

hi

two

one
two
‘ );
foreach((array) $sx as $tagname => $val ) <
if ( is_string ( $val )) <
// will go here
> elseif ( is_array ( $val )) <
// will go here because it happens multiple times
> elseif ( is_object ( $val )) <
// will go here because it contains tags
// will go here because it contains CDATA!
>
>
?>

To test in the loop, do this

if ( count ((array) $val ) == 0 ) <
// this is not a tag that contains other tags
$val = » . $val ;
// now the CDATA is revealed magically.
>
?>

Here is my update to Bob’s simple SimpleXML wrapper function.
I noticed his version would turn an empty SimpleXMLElement into an empty array.

Источник

SimpleXML

User Contributed Notes 32 notes

Three line xml2array:

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

Here is a recursive function that will convert a given SimpleXMLElement object into an array, preserving namespaces and attributes.

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
);
>
?>

Simple means simple. If you know the structure and just want the value of a tag:

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

Warning, numbers can come out as strings, empty elements like come out as array(0)

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.

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:

= 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:

foreach( $files as $file ) <
$xml = simplexml_load_file ( $file );
XMLToArrayFlat ( $xml , $xmlarray , $file . ‘:’ , true );
>
?>
The respective filename/path is thus prefixed to each key.

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
)
So I rolled out my own; hope it helps someone.
/**
* Converts a simpleXML element into an array. Preserves attributes.

* You can choose to get your elements either flattened, or stored in a custom
* index that you define.

* For example, for a given element
*
*
*
*

* if you choose to flatten attributes, you would get:
*
* $array[‘field’][‘name’] = ‘someName’;
* $array[‘field’][‘type’] = ‘someType’;
*
* If you choose not to flatten, you get:
*
* $array[‘field’][‘@attributes’][‘name’] = ‘someName’;
*
*
__________________________________________________________

* Repeating fields are stored in indexed arrays. so for a markup such as:
*
*

* a
* b
* c
* .
*
* you array would be:
*
* $array[‘parent’][‘child’][0] = ‘a’;
* $array[‘parent’][‘child’][1] = ‘b’;
* . And so on.
*
* @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.

* 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.

* 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.

* 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 ))

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

$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 );>
>

In reply to soloman at textgrid dot com,

2 line XML2Array:

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

«, 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:

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

function array2XML ( $arr , $root ) <
$xml = new SimpleXMLElement ( » < $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 ();
>
?>

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;

$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
?>

dynamic sql in php using xml:

test.xml:

SELECT * FROM USERS
WHERE >
WHERE username = «%s» ;

index.php:
function callMe ( $param ) <
$search = array( ‘byUsername’ => ‘dynsql’ );

if (isset( $search [ $param [ 1 ]])) <
return sprintf ( $param [ 2 ], $search [ $param [ 1 ]]);
>

$xml = simplexml_load_file ( «test.xml» );
$string = $xml -> statement -> asXML ();
$string = preg_replace_callback ( ‘/ (.*?) /’ , ‘callMe’ , $string );
$node = simplexml_load_string ( $string );
echo $node ;
?>

obviously, this example can be improved [in your own code.]

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

= $_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.
= intval ( $_GET [ ‘id’ ]);
echo $xml -> page [ $page_id ]
?>

Wrapper XMLReader class, for simple SAX-reading huge xml:
https://github.com/dkrnl/SimpleXMLReader

/**
* Simple XML Reader
*
* @license Public Domain
* @author Dmitry Pyatkov(aka dkrnl)
* @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 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 ;
>

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.

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.

Reading this xml into a variable called $xml and then doing the following
= $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.
= (string) $xml -> Id ;
?>

Optimizing aalaap at gmail dot com’s 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 ;
>
?>

Here’s a function I came up with to convert an associative array to XML. Works for multidimensional arrays as well.

function assocArrayToXML ( $root_element_name , $ar )
<
$xml = new SimpleXMLElement ( » < $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 ();
>
?>

I rewrite the function to convert xml object to array because my case is more simple:

$array = [];
foreach($obj as $item) <
$row = [];
foreach($item as $key => $val) <
$col = array(
(string)$key => (string)$val
);
array_push($row,$col);

Here are two quick and dirty functions that use SimpleXML to detect if a feed xml is RSS or ATOM:

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.

I know it is over-done, but the following is a super-short example of a XML to Array conversion function (recursive):

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 ;
>

function array_to_xml ( $array , $xml = null ) <
if ( is_array ( $array ) ) <
foreach( $array as $key => $value ) <
if ( is_int ( $key ) ) <
if ( $key == 0 ) <
$node = $xml ;
> else <
$parent = $xml -> xpath ( «..» )[ 0 ];
$node = $parent -> addChild ( $xml -> getName () );
>
> else <
$node = $xml -> addChild ( $key );
>
array_to_xml ( $value , $node );
>
> else <
$xml [ 0 ] = $array ;
>
>

$xml = new SimpleXMLElement ( » » );

array_to_xml ( $array , $xml );
echo $xml -> asXML ();
?>

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

function amstore_xmlobj2array ( $obj , $level = 0 ) <

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 );
>
>
>
>
>

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

Two lines xml2array:

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

XML data values should not contain «&» and that need to be replaced by html-entity «&»

You can use this code to replace lonely «&» to «&»:

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;

$_SESSION[‘country’] = (string) $country;

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*)

Here is an example of an easy mapping between xml and classes defined by user.

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 ( ‘ ‘ );
$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

FAIL! This function works better than the one I posted below:

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 );
>

if for some reasons you need the string value instead of the simpleXML Object you can cast the return value as a string.

= 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 ;
>
?>

.

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.

/**
* 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 );
>
>
>
?>

I had to do the following to catch the fact that my simplexml_load_string call was not working right (it was returning empty objects).

if (($statistik === FALSE) or ($statistik === NULL) or empty($statistik))
<
echo «$ctr) STATISTIK ERROR—n»;
var_dump($statistik);
echo «nn»;
echo «Failed loading XMLn»;
foreach(libxml_get_errors() as $error)
<
echo «n», $error->message;
>
die();
>

before I put the check for «empty()» I was not catching the error.

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!

# 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 ;
>
?>

Источник

logo

What?
A quick article to stop me running into this issue again. This article serves to address the issue of importing characters from an XML in a different language character set and trying to load it in PHP with the function simplexml_load_string(). The error I get is something similar to:

PHP Warning:
simplexml_load_string(): Entity: line #: parser error : Input is not proper UTF-8, indicate encoding ! Bytes: 0xA0 0x3C 0x2F 0x73 in /home/public_html/my_folder/my_xml_processing_script.php on line 160

Why?
I’m downloading an XML feed to our servers, and then loading the downloaded file into memory with simplexml_load_string(). I get the above error when it is attempting to load an XML feed which is mostly in Spanish and breaks at the following XML node:

copyraw

<baños>2</baños>

-> yields issue: PHP Warning:  simplexml_load_string():     <baños>2</baños> in /home/public_html/my_folder/my_xml_processing_script.php on line 160

should read

<baños>2</baños>
  1.  <baños>2</baños> 
  2.   
  3.  —> yields issue: PHP Warning:  simplexml_load_string():     <baños>2</baños> in /home/public_html/my_folder/my_xml_processing_script.php on line 160 
  4.   
  5.  should read 
  6.   
  7.  <baños>2</baños> 

How?

A two-step process, my issue was with how the file was downloaded with cURL. The XML node should be

baños

.

The initial command using cURL was:

copyraw

function get_data($url) {
        $ch = curl_init();
        $timeout = 5;
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
        $data = curl_exec($ch);
        curl_close($ch);
        return $data;
}
$file_content = get_data( "http://joellipman.com/xml_feeds/my_XML_url.xml" );
$file_xml = simplexml_load_string( $file_content );  // doesn't work and returns a load of parser errors
  1.  function get_data($url) { 
  2.          $ch = curl_init()
  3.          $timeout = 5
  4.          curl_setopt($ch, CURLOPT_URL, $url)
  5.          curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1)
  6.          curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout)
  7.          $data = curl_exec($ch)
  8.          curl_close($ch)
  9.          return $data
  10.  } 
  11.  $file_content = get_data( «http://joellipman.com/xml_feeds/my_XML_url.xml» )
  12.  $file_xml = simplexml_load_string( $file_content );  

The tweaked command using cURL is:

copyraw

function get_data($url) {
        $ch = curl_init();
        $timeout = 5;
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
        $data = utf8_decode(curl_exec($ch));  // note the utf8_decode function applied here
        curl_close($ch);
        return $data;
}
$file_content = get_data( "http://joellipman.com/xml_feeds/my_XML_url.xml" );
$file_xml = simplexml_load_string( utf8_encode( $file_content ) );  // works!  DONE! Stop reading any further and tell your boss it was always in hand.
  1.  function get_data($url) { 
  2.          $ch = curl_init()
  3.          $timeout = 5
  4.          curl_setopt($ch, CURLOPT_URL, $url)
  5.          curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1)
  6.          curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout)
  7.          $data = utf8_decode(curl_exec($ch));  
  8.          curl_close($ch)
  9.          return $data
  10.  } 
  11.  $file_content = get_data( «http://joellipman.com/xml_feeds/my_XML_url.xml» )
  12.  $file_xml = simplexml_load_string( utf8_encode( $file_content ) );  

Other things I tried but to no avail
The solution above was as easy as that. Here are a number of other things I tried first:

  • mysql_set_charset(): No
  • iconv(): No
  • htmlentities(): No
  • preg_replace_callback(): No
  • sxe(): No
  • $xml = simplexml_load_string( utf8_encode($rss) );: No. Oh wait, yes! sorta, don’t forget the decode when downloading the XML.

Category: Personal Home Page :: Article: 642


I keep having to look up how to stop the warning that are emitted when simplexml_load_string & simplexml_load_file fail, so this time I’ve written the world’s simplest little class to take care of it for me from now on:

<?php

namespace Rka;

use UnexpectedValueException;

class Xml
{
    /**
     * Load an XML String and convert any warnings to an exception
     *
     * @param string  $string
     * @param string $class_name
     * @param int $options
     * @param string $ns
     * @param bool $is_prefix
     *
     * @throws UnexpectedValueException
     *
     * @return SimpleXMLElement
     */
    public static function loadXMLString(
        $string,
        $class_name = "SimpleXMLElement",
        $options = 0,
        $ns = "",
        $is_prefix = false
    ) {
        $previous = libxml_use_internal_errors(true);

        $xml = simplexml_load_string($string, $class_name, $options, $ns,
                 $is_prefix);

        if (!$xml) {
            $errors = self::getXMLErrorString();
            libxml_use_internal_errors($previous);
            throw new UnexpectedValueException($errors);
        }

        libxml_use_internal_errors($previous);
        return $xml;
    }

    /**
     * Load an XML File and convert any warnings to an exception
     *
     * @param string  $string
     * @param string $class_name
     * @param int $options
     * @param string $ns
     * @param bool $is_prefix
     *
     * @throws UnexpectedValueException
     *
     * @return SimpleXMLElement
     */
    public static function loadXMLFile(
        $string,
        $class_name = "SimpleXMLElement",
        $options = 0,
        $ns = "",
        $is_prefix = false
    ) {
        $previous = libxml_use_internal_errors(true);

        $xml = simplexml_load_file($string, $class_name, $options, $ns,
                 $is_prefix);

        if (!$xml) {
            $errors = self::getXMLErrorString();
            libxml_use_internal_errors($previous);
            throw new UnexpectedValueException($errors);
        }

        libxml_use_internal_errors($previous);
        return $xml;
    }

    /**
     * Helper method to format the XML errors into a string.
     *
     * @return string
     */
    protected static function getXMLErrorString()
    {
        $message = '';
        foreach (libxml_get_errors() as $error) {
            $message .= trim($error->message)
              . " on line: $error->line, column: $error->column.n";
        }
        libxml_clear_errors();
        return trim($message);
    }
}

Update: The code has been updated based on the comments below. Thanks!

This article was posted on
9 September 2014
in PHP

simplexml_load_string

(PHP 5, PHP 7)

simplexml_load_string
Интерпретирует строку с XML в объект

Описание

SimpleXMLElement simplexml_load_string
( string $data
[, string $class_name = «SimpleXMLElement»
[, int $options = 0
[, string $ns = «»
[, bool $is_prefix = false
]]]] )

Список параметров

data

Правильно сформированная XML-строка

class_name

Вы можете использовать этот необязательный параметр для того, чтобы функция
simplexml_load_string() возвращала объект
указанного класса. Этот класс должен расширять
класс SimpleXMLElement.

options

Начиная с PHP 5.1.0 и Libxml 2.6.0, вы также можете использовать параметр
options чтобы указать дополнительные параметры Libxml.

ns

Префикс пространства имен или URI.

is_prefix

TRUE если ns является префиксом, и FALSE если URI;
по умолчанию равен FALSE.

Возвращаемые значения

Возвращает объект (object) класса SimpleXMLElement со
свойствами, содержащими данные, которые хранятся внутри XML-документа или FALSE в случае возникновения ошибки.

Ошибки

Генерирует сообщение об ошибке уровня E_WARNING для
каждой ошибки, найденной в XML-данных.

Примеры

Пример #1 Интерпретация XML-строки


<?php
$string 
= <<<XML
<?xml version='1.0'?> 
<document>
 <title>Что 40?</title>
 <from>Джо</from>
 <to>Джейн</to>
 <body>
  Я знаю, что это - ответ. В чем заключается вопрос?
 </body>
</document>
XML;$xml simplexml_load_string($string);print_r($xml);
?>

Результат выполнения данного примера:

SimpleXMLElement Object
(
  [title] => Что 40?
  [from] => Джо
  [to] => Джейн
  [body] =>
   Я знаю, что это - ответ. В чем заключается вопрос?
)

Здесь вы можете использовать $xml->body
и проч.

Смотрите также

  • simplexml_load_file() — Интерпретирует XML-файл в объект
  • SimpleXMLElement::__construct() — Создание нового SimpleXMLElement объекта
  • Работа с ошибками XML
  • libxml_use_internal_errors() — Отключение ошибок libxml и передача полномочий по выборке и обработке
    информации об ошибках пользователю
  • Базовое использование SimpleXML

Вернуться к: SimpleXML

(PHP 5, PHP 7)

simplexml_load_string
Interprets a string of XML into an object

Description

SimpleXMLElement simplexml_load_string
( string $data
[, string $class_name = «SimpleXMLElement»
[, int $options = 0
[, string $ns = «»
[, bool $is_prefix = false
]]]] )

Parameters

data

A well-formed XML string

class_name

You may use this optional parameter so that
simplexml_load_string() will return an object of
the specified class. That class should extend the
SimpleXMLElement class.

options

Since PHP 5.1.0 and Libxml 2.6.0, you may also use the
options parameter to specify additional Libxml parameters.

ns

Namespace prefix or URI.

is_prefix

TRUE if ns is a prefix, FALSE if it’s a URI;
defaults to FALSE.

Return Values

Returns an object of class SimpleXMLElement with
properties containing the data held within the xml document, or FALSE on failure.

Warning

This function may
return Boolean FALSE, but may also return a non-Boolean value which
evaluates to FALSE. Please read the section on Booleans for more
information. Use the ===
operator for testing the return value of this
function.

Errors/Exceptions

Produces an E_WARNING error message for each error
found in the XML data.

Examples

Example #1 Interpret an XML string


<?php
$string 
= <<<XML
<?xml version='1.0'?> 
<document>
 <title>Forty What?</title>
 <from>Joe</from>
 <to>Jane</to>
 <body>
  I know that's the answer -- but what's the question?
 </body>
</document>
XML;$xml simplexml_load_string($string);print_r($xml);
?>

The above example will output:

SimpleXMLElement Object
(
  [title] => Forty What?
  [from] => Joe
  [to] => Jane
  [body] =>
   I know that's the answer -- but what's the question?
)

At this point, you can go about using $xml->body
and such.

See Also

  • simplexml_load_file() — Interprets an XML file into an object
  • SimpleXMLElement::__construct() — Creates a new SimpleXMLElement object
  • Dealing with XML errors
  • libxml_use_internal_errors() — Disable libxml errors and allow user to fetch error information as needed
  • Basic SimpleXML usage

User Contributed Notes

rowan dot collins at gmail dot com

7 years ago


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

?>


ascammon at hotmail dot com

5 years ago


I had a hard time finding this documented, so posting it here in case it helps someone:

If you want to use multiple libxml options, separate them with a pipe, like so:

<?php
$xml
= simplexml_load_string($string, 'SimpleXMLElement', LIBXML_NOCDATA | LIBXML_NOBLANKS);
?>


Diego Araos, diego at klapmedia dot com

5 years ago


A simpler way to transform the result into an array (requires json module).

<?php

function object2array($object) { return @json_decode(@json_encode($object),1); }

?>



Example:

<?php

$xml_object
=simplexml_load_string('<SOME XML DATA');

$xml_array=object2array($xml_object);

?>


Bob

6 years ago


Here is my simple SimpleXML wrapper function.
As far as I can tell, it does the same as Julio Cesar Oliveira's (above).
It parses an XML string into a multi-dimensional associative array.
The second argument is a callback that is run on all data (so for example, if you want all data trimmed, like Julio does in his function, just pass 'trim' as the second arg).
<?php
function unserialize_xml($input, $callback = null, $recurse = false)
/* bool/array unserialize_xml ( string $input [ , callback $callback ] )
* Unserializes an XML string, returning a multi-dimensional associative array, optionally runs a callback on all non-array data
* Returns false on all failure
* Notes:
    * Root XML tags are stripped
    * Due to its recursive nature, unserialize_xml() will also support SimpleXMLElement objects and arrays as input
    * Uses simplexml_load_string() for XML parsing, see SimpleXML documentation for more info
*/
{
   
// Get input, loading an xml string with simplexml if its the top level of recursion
   
$data = ((!$recurse) && is_string($input))? simplexml_load_string($input): $input;
   
// Convert SimpleXMLElements to array
   
if ($data instanceof SimpleXMLElement) $data = (array) $data;
   
// Recurse into arrays
   
if (is_array($data)) foreach ($data as &$item) $item = unserialize_xml($item, $callback, true);
   
// Run callback and return
   
return (!is_array($data) && is_callable($callback))? call_user_func($callback, $data): $data;
}
?>

bojan

8 years ago


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

)

*/

?>


nbijnens at servs dot eu

8 years ago


Please note that not all LIBXML options are supported with the options argument.

For instance LIBXML_XINCLUDE does not work. But there is however a work around:

<?php
$xml
= new DOMDocument();
$xml->loadXML ($XMLString);$xml->xinclude();
$xml = simplexml_import_dom($xml);?>


AllenJB

3 years ago


<?php
$xml
= json_decode(json_encode((array) simplexml_load_string($string)), 1);
?>

A reminder that json_encode attempts to convert data to UTF-8 without specific knowledge of the source encoding. This method can cause encoding issues if you're not working in UTF-8.

Julio Cesar Oliveira

7 years ago


<?php

function XML2Array ( $xml )

{

   
$array = simplexml_load_string ( $xml );

   
$newArray = array ( ) ;

   
$array = ( array ) $array ;

    foreach (
$array as $key => $value )

    {

       
$value = ( array ) $value ;

       
$newArray [ $key] = $value [ 0 ] ;

    }

   
$newArray = array_map("trim", $newArray);

  return
$newArray ;

}

?>

Mark Omohundro, ajamyajax.com

7 years ago


How about a recursive function to reduce the xml hard-coding in your apps?  Here is my simple listing routine as an example:

<?php

function list_xml($str) {

 
$root = simplexml_load_string($str);

 
list_node($root);

}

function

list_node($node) {

  foreach (
$node as $element) {

    echo
$element. "n";

    if (
$element->children()) {

      echo
"<br/>";

     
list_node($element);

    }

  }

}

?>


kyle at codeincarnate dot com

8 years ago


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]));

}
?>


artistan at gmail dot com

10 months ago


Here is my update to Bob's simple SimpleXML wrapper function.
I noticed his version would turn an empty SimpleXMLElement into an empty array.

<?php
   
/**
     * http://php.net/manual/en/function.simplexml-load-string.php#91564
     *
     * bool/array unserialize_xml ( string $input [ , callback $callback ] )
     * Unserializes an XML string, returning a multi-dimensional associative array, optionally runs a callback on all non-array data
     * Returns false on all failure
     * Notes:
     * Root XML tags are stripped
     * Due to its recursive nature, unserialize_xml() will also support SimpleXMLElement objects and arrays as input
     * Uses simplexml_load_string() for XML parsing, see SimpleXML documentation for more info
     *
     * @param $input
     * @param null $callback
     * @param bool $recurse
     * @return array|mixed
     *
     */
   
function unserialize_xml($input, $callback = null, $recurse = false)
    {
       
// Get input, loading an xml string with simplexml if its the top level of recursion
       
$data = ((!$recurse) && is_string($input))? simplexml_load_string($input): $input;
       
// Convert SimpleXMLElements to array
       
if ($data instanceof SimpleXMLElement){
            if(!empty(
$data)){
               
$data = (array) $data;
            } else {
               
$data = '';
            }
        }
       
// Recurse into arrays
       
if (is_array($data)) foreach ($data as &$item) $item = unserialize_xml($item, $callback, true);
       
// Run callback and return
       
return (!is_array($data) && is_callable($callback))? call_user_func($callback, $data): $data;
    }
?>


meustrus

11 months ago


Be careful checking for parse errors. An empty SimpleXMLElement may resolve to FALSE, and if your XML contains no text or only contains namespaced elements your error check may be wrong. Always use `=== FALSE` when checking for parse errors.

<?php

$xml

= <<<XML
<?xml version="1.0" encoding="UTF-8"?>
<ns1:Root xmlns:ns1="http://example.com/custom">
<ns1:Node>There's stuff here</ns1:Node>
</ns1:Root>
XML;$simplexml = simplexml_load_string($xml);// This prints "Parse Error".
echo ($simplexml ? 'Valid XML' : 'Parse Error'), PHP_EOL;// But this prints "There's stuff here", proving that
// the SimpleXML object was created successfully.
echo $simplexml->children('http://example.com/custom')->Node, PHP_EOL;// Use this instead:
echo ($simplexml !== FALSE ? 'Valid XML' : 'Parse Error'), PHP_EOL;?>

See:

https://bugs.php.net/bug.php?id=31045
https://bugs.php.net/bug.php?id=30972
https://bugs.php.net/bug.php?id=69596


jeff at creabilis dot com

6 years ago


If you want to set the charset of the outputed xml, simply set the encoding attribute like this :

<?php simplexml_load_string('<?xml version="1.0" encoding="utf-8"?><xml/>'); ?>



The generated xml outputed by $xml->asXML will containt accentuated characters like 'é' instead of é.

Hope this help


Julio Cesar Oliveira

7 years ago


The XML2Array func now Recursive!

<?php
function XML2Array ( $xml , $recursive = false )
{
    if ( !
$recursive )
    {
       
$array = simplexml_load_string ( $xml ) ;
    }
    else
    {
       
$array = $xml ;
    }
$newArray = array () ;
   
$array = ( array ) $array ;
    foreach (
$array as $key => $value )
    {
       
$value = ( array ) $value ;
        if ( isset (
$value [ 0 ] ) )
        {
           
$newArray [ $key ] = trim ( $value [ 0 ] ) ;
        }
        else
        {
           
$newArray [ $key ] = XML2Array ( $value , true ) ;
        }
    }
    return
$newArray ;
}
?>


javalc6 at gmail dot com

7 years ago


I wanted to convert an array containing strings and other arrays of the same type into a simplexml object.

Here is the code of the function array2xml that I've developed to perform this conversion. Please note that this code is simple without any checks.

<?php

function array2xml($array, $tag) {

    function

ia2xml($array) {

       
$xml="";

        foreach (
$array as $key=>$value) {

            if (
is_array($value)) {

               
$xml.="<$key>".ia2xml($value)."</$key>";

            } else {

               
$xml.="<$key>".$value."</$key>";

            }

        }

        return
$xml;

    }

    return

simplexml_load_string("<$tag>".ia2xml($array)."</$tag>");

}
$test['type']='lunch';

$test['time']='12:30';

$test['menu']=array('entree'=>'salad', 'maincourse'=>'steak');

echo

array2xml($test,"meal")->asXML();

?>


SmartD

7 years ago


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;

}
?>


paulyg76 at NOSPAM dot gmail dot com

8 years ago


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
?>


amir_abiri at ipcmedia dot com

8 years ago


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(). "nn";
$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(). "nn";
$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>


hattori at hanso dot com

8 years ago


Theres a problem with the below workaround when serializing fields containing html CDATA. For any other content type then HTML try to modfiy function parseCDATA.
Just add these lines before serializing.
This is also a workaround for this bug http://bugs.php.net/bug.php?id=42001

<?PHP
if(strpos($content, '<![CDATA[')) {
   function
parseCDATA($data) {
      return
htmlentities($data[1]);
   }
  
$content = preg_replace_callback(
     
'#<![CDATA[(.*)]]>#',
     
'parseCDATA',
     
str_replace("n", " ", $content)
   );
}
?>


Pedro

8 years ago


Attention:

simplexml_load_string has a problem with entities other than (&lt;, &gt;, &amp;, &quot; and &apos;).

Use numeric character references instead!


php at teamhirsch dot com

9 years ago


It's worth noting that in the example above, $xml->body will actually return an object of type SimpleXMLElement, not a string, e.g.

SimpleXMLElement Object (
       [0] => this is the text in the body tag
  ) 

If you want to get a string out of it you must explicitly cast it using (string) or double quotes, or pass $xml->body (or whatever attribute you want to access) to any function that returns a string, such as urldecode() or trim().


m dot ament at mailcity dot com

9 years ago


Warning:

The parsing of XML-data will stop when reaching character 0.
Please avoid this character in your XML-data.


mindpower

9 years ago


A simple extension that adds a method for retrieving a specific attribute:

<?php
class simple_xml_extended extends SimpleXMLElement
{
    public    function   
Attribute($name)
    {
        foreach(
$this->Attributes() as $key=>$val)
        {
            if(
$key == $name)
                return (string)
$val;
        }
    }

}

$xml = simplexml_load_string('
<xml>
  <dog type="poodle" owner="Mrs Smith">Rover</dog>
</xml>'
, 'simple_xml_extended');

echo

$xml->dog->Attribute('type');?>

outputs 'poodle'

I prefer to use this technique rather than typecasting attributes.


h

9 years ago


seems like simplexml has a line-length restriction - fails if a largeish XML doc with no linebreaks is passed as a string or file.

h


roy dot walter at nospam dot brookhouse dot co dot uk

9 years ago


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.

<?php

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());
?>


paul at santasoft dot com

9 years ago


If you have PHP > 5.1 and LibXML > 2.6, use this function call to have simplexml convert CDATA into plain text.

simplexml_load_string($xmlstring, 'SimpleXMLElement', LIBXML_NOCDATA);

Too bad, so sad with PHP < 5.1.


Maciek Ruckgaber <maciekrb at gmai dot com>

10 years ago


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:

<?php

$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:

<?php

$xml
= simplexml_load_string($xmlstr);

echo
$xml; // this will echo 2328  (string)

?>


igor kraus

11 years ago


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>


cellog at php dot net

11 years ago


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.

}

?>


hattori at hanso dot com

8 years ago


If you want to serialize and unserialize SimpleXMLElement objects for caching, you need to transform the SimpleXMLElement object into a standard class object before unserializing.
This is only if you want to cache converted data, the functionallity of the SimpleXMLElement will not be held.

$content = '<SomeXML....'

$serialized = str_replace(
  array('O:16:"SimpleXMLElement":0:{}', 'O:16:"SimpleXMLElement":'),
  array('s:0:"";', 'O:8:"stdClass":'),
  serialize(simplexml_load_string($content))
);

$unserialized = unserialize($serialized);


tiznull

7 years ago


SimpleXMLElement - Warning: unserialize() [function.unserialize]: Node no longer exists in … .php

If you get this error from storing serialized SimpleXMLElement data then this is your fix…

<?phpfunction sxml_unserialze($str) {
return
unserialize(str_replace(array('O:16:"SimpleXMLElement":0:{}', 'O:16:"SimpleXMLElement":'), array('s:0:"";', 'O:8:"stdClass":'), $str));
}
?>


supzero at phparts dot net

7 years ago


if we don't know children number. How many loop. How many key.

<?php

class XML {

    protected
$pointer;

    public   
$degerler=array();

   
    function

loadString($string){

       
$this->pointer = simplexml_load_string($string);

                return
$this->pointer;

    }

   
    function

loadFile($file){

       
$this->pointer = simplexml_load_file($file);

        return
$this->pointer;

    }

   
    function

getname(){

        return
$this->pointer->getName();

    }

    function
child(){

        return
$this->pointer->children();

    }

    function
att(){

        return
$this->pointer->attributes();

    }

    function
toArray(){

        foreach (
$this->child() as $sq){

           
$this->degerler[$this->getname()][$sq->getname()][][] = $sq; // How many key

       
}

        return;

    }

   
}

?>


nospam at qool dot com

7 years ago


simplexml doesn't appear to like long attributes. I have tried passing it a valid xhtml document but the url in the anchor tag was causing simplexml to generate an error.

youx_free_fr

8 years ago


While needing to add an xml subtree to an existing simplexml object, I noticed that simplexml_load_string fails with strings like
<emptynode></emptynode>

I needed to use dom instead of simplexml to bypass this problem and work with any kind of xml strings.


lists at cyberlot dot net

10 years ago


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>

lb at bostontech dot net

4 years ago


please note that:

<?
$data_array = (array) simplexml_load_string($xml_string);
?>

will only convert the root element to an array, where as the child elements remain XML objects.

To prove this, try returning a value N objects deep by association.  Then try the same exercise using something like the object2array example below. (Which works great).


thejhereg at gmail dot com

5 years ago


"simplexml_load_string() : Entity: line #: parser error : Comment not terminated"

On the off chance you see this error and you're pulling your hair out over it, simplexml can't seem to correctly parse XML comment tags if the comment contains "--".

Is silly and likely won't happen very often -- but sometimes it does. ;-)


greg dot steffensen at spamless dot richmond dot edu

12 years ago


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.]


Понравилась статья? Поделить с друзьями:
  • Siemens стиральная машина ошибка a02
  • Sfc dll ошибка
  • Simple error handler labview
  • Sims 4 orange emu error
  • Siemens посудомоечная машина ошибка е09