81

Let's say I have some XML like this

<channel>
  <item>
    <title>This is title 1</title>
  </item>
</channel>

The code below does what I want in that it outputs the title as a string

$xml = simplexml_load_string($xmlstring);
echo $xml->channel->item->title;

Here's my problem. The code below doesn't treat the title as a string in that context so I end up with a SimpleXML object in the array instead of a string.

$foo = array( $xml->channel->item->title );

I've been working around it like this

$foo = array( sprintf("%s",$xml->channel->item->title) );

but that seems ugly.

What's the best way to force a SimpleXML object to a string, regardless of context?

Vincent
  • 22,366
  • 18
  • 58
  • 61
Mark Biek
  • 146,731
  • 54
  • 156
  • 201
  • I've submitted multiple requests to PHP to implement something similar to SOAP_SINGLE_ELEMENT_ARRAYS for this, and would encourage others to do the same. SOAP_SINGLE_ELEMENT_ARRAYS forces elements that /could/ hold more than one string to be parsed always as just strings. Of course as others mentioned you need to know what you're getting back, but time and time again I've run into issues with .NET SOAP servers that the WSDL for ( by .NET's "magic" defaults ) prototyped every string as either mixed or an array of strings. Instead of current()'ing or typecasting, the bit just gives back a string – conrad10781 Dec 09 '17 at 20:37

11 Answers11

154

Typecast the SimpleXMLObject to a string:

$foo = array( (string) $xml->channel->item->title );

The above code internally calls __toString() on the SimpleXMLObject. This method is not publicly available, as it interferes with the mapping scheme of the SimpleXMLObject, but it can still be invoked in the above manner.

Aron Rotteveel
  • 81,193
  • 17
  • 104
  • 128
  • That's cleaner than using a sprintf. I like it – Mark Biek Jan 06 '09 at 14:10
  • 5
    Note that using a function that accepts string arguments will automatically do this type casting (e.g. echo, str_replace, substr). – Ross Jan 06 '09 at 14:33
  • Thanks Aron, I thought a typecast was the way to do this but it just didnt feel right. Now that I know the _toString method is private it makes sense. – Neil Aitken Aug 12 '09 at 11:03
  • 3
    $foo = (string) $xml->channel->item->title; is what I was looking for, since I don't need an array. Thanks. – Drazisil Aug 01 '12 at 17:36
  • 1
    +100 you just made my evening! Im new to SimpleXMLObject the vars I had extracted from it were 'printing' fine to the screen but failing my DB query...sigh! Since when was PHP strictly typed? ;-) – megaSteve4 Oct 28 '12 at 19:44
  • 1
    @megaSteve4 "Since when was PHP strictly typed?" - it's precisely because it's not that this needs to happen: most functions don't have a defined type context, so cannot implicitly cast to that type. Of course, they can *explicitly* cast their input params, which is why `substr` et al work. It's safer to do the cast as early as possible though, so you know all functions will see the data they expect. – IMSoP Feb 21 '13 at 10:13
23

You can use the PHP function

strval();

This function returns the string values of the parameter passed to it.

Zaje
  • 2,281
  • 5
  • 27
  • 39
  • 3
    @Mark Biek: It does work on objects that have `__toString()` implemented and especially in this questions case in specific, it works very well with objects of type `SimpleXMLElement`. You can compare it with the `string` cast in the accepted answer. `strval()` is a handy callback function often in conjunction with [`array_map()`](http://php.net/array_map) and [`iterator_to_array($simpleXMLElement, false)`](http://php.net/iterator_to_array) or `SimpleXMLElement::xpath()`. – hakre Feb 21 '13 at 11:21
9

There is native SimpleXML method SimpleXMLElement::asXML Depending on parameter it writes SimpleXMLElement to xml 1.0 file or just to a string:

$xml = new SimpleXMLElement($string);
$validfilename = '/temp/mylist.xml';
$xml->asXML($validfilename);    // to a file
echo $xml->asXML();             // to a string
Mixed Case
  • 91
  • 1
  • 3
3

Another ugly way to do it:

$foo = array( $xml->channel->item->title."" );

It works, but it's not pretty.

Mikepote
  • 6,042
  • 3
  • 34
  • 38
3

The accepted answer actually returns an array containing a string, which isn't exactly what OP requested (a string). To expand on that answer, use:

$foo = [ (string) $xml->channel->item->title ][0];

Which returns the single element of the array, a string.

DJ Far
  • 497
  • 5
  • 12
2

Not sure if they changed the visibility of the __toString() method since the accepted answer was written but at this time it works fine for me:

var_dump($xml->channel->item->title->__toString());

OUTPUT:

string(15) "This is title 1"
2

To get XML data into a php array you do this:

// this gets all the outer levels into an associative php array
$header = array();
foreach($xml->children() as $child)
{
  $header[$child->getName()] = sprintf("%s", $child); 
}
echo "<pre>\n";
print_r($header);
echo "</pre>";

To get a childs child then just do this:

$data = array();
foreach($xml->data->children() as $child)
{
  $header[$child->getName()] = sprintf("%s", $child); 
}
echo "<pre>\n";
print_r($data);
echo "</pre>";

You can expand $xml-> through each level until you get what you want You can also put all the nodes into one array without the levels or just about any other way you want it.

Pete
  • 31
  • 3
1

Try strval($xml->channel->item->title)

Ariel Ruiz
  • 163
  • 2
  • 6
0

There is native SimpleXML method SimpleXMLElement::asXML Depending on parameter it writes SimpleXMLElement to xml 1.0 file, Yes

$get_file= read file from path;
$itrate1=$get_file->node;
$html  = $itrate1->richcontent->html;


echo  $itrate1->richcontent->html->body->asXML();
 print_r((string) $itrate1->richcontent->html->body->asXML());
0

Just put the ''. before any variable, it will convert into string.

$foo = array( ''. $xml->channel->item->title );

Krishan Kumar
  • 394
  • 4
  • 13
-1

The following is a recursive function that will typecast all single-child elements to a String:

//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// FUNCTION - CLEAN SIMPLE XML OBJECT
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
function cleanSimpleXML($xmlObject = ''){

    // LOOP CHILDREN
    foreach ($xmlObject->children() as $child) {

        // IF CONTAINS MULTIPLE CHILDREN
        if(count($child->children()) > 1 ){

            // RECURSE
            $child = cleanSimpleXML($child);

        }else{

            // CAST
            $child = (string)$child;

        }

    }

    // RETURN CLEAN OBJECT
    return $xmlObject;

} // END FUNCTION
Tony
  • 2,890
  • 1
  • 24
  • 35