238

I have something like this:

$url = "http://ws.geonames.org/findNearbyPostalCodes?country=pl&placename="; $url .= rawurlencode($city[$i]); $xml = simplexml_load_file($url); echo $url."\n"; $cityCode[] = array( 'city' => $city[$i], 'lat' => $xml->code[0]->lat, 'lng' => $xml->code[0]->lng ); 

It's supposed to download XML from geonames. If I do print_r($xml) I get :

SimpleXMLElement Object ( [code] => Array ( [0] => SimpleXMLElement Object ( [postalcode] => 01-935 [name] => Warszawa [countryCode] => PL [lat] => 52.25 [lng] => 21.0 [adminCode1] => SimpleXMLElement Object ( ) [adminName1] => Mazowieckie [adminCode2] => SimpleXMLElement Object ( ) [adminName2] => Warszawa [adminCode3] => SimpleXMLElement Object ( ) [adminName3] => SimpleXMLElement Object ( ) [distance] => 0.0 ) 

I do as you can see $xml->code[0]->lat and it returns an object. How can i get the value?

4
  • 1
    possible duplicate of Forcing a SimpleXML Object to a string, regardless of context Commented Sep 28, 2014 at 10:53
  • 2
    2017 Update: SO no longer displays the best answer at the top. The best answer is here. Commented Jun 6, 2017 at 21:23
  • 3
    @rinogo You've probably accidentally clicked one of the sorting tabs at the top of the answer block. The answer you linked to has 345 votes, so shows at the top if you have sorting set to "votes". Commented Aug 29, 2017 at 13:49
  • 1
    Thanks, @IMSoP! You're right - I must have clicked "active" at some point (useful for old questions with outdated answers, btw) - good to know I need to change it back to "votes"! :) Commented Aug 29, 2017 at 18:42

13 Answers 13

494

You have to cast simpleXML Object to a string.

$value = (string) $xml->code[0]->lat; 
Sign up to request clarification or add additional context in comments.

6 Comments

Just noticed if you json_encode the xml object and then json_decode it you get a nested stdObject to deal with, quite handy for when you're being lazy & working with simple structures :D
silly question, but isn't that a bug? see php.net/simplexml#95762 why you don't have to cast type on some fields but on others you have to?
i can't believe this is so complicated. why would they make a class called "getName" but not "getValue"? why would they print empty string if you printed it instead of converted it manually to (string). WHY??
@user151496 Technically, the string cast isn't giving you the "value", but the "text content". But yes, a specifically-named method would be more discoverable. Once you get used to this, though, it's not actually any harder to use.
i always kill at least half a day by discovering the quirks of simpleXML every time i have to get to it once in a couple of months on some projects
|
107

You can also use the magic method __toString()

$xml->code[0]->lat->__toString() 

3 Comments

Or sprintf with the %s format. Or echo and output buffering, or or or or ...
How can i convert the object to XML in PHP? @sglessard
@Gem you probably want some kind of serialization - see stackoverflow.com/questions/137021/php-object-as-xml-document
22

If you know that the value of the XML element is a float number (latitude, longitude, distance), you can use (float)

$value = (float) $xml->code[0]->lat; 

Also, (int) for integer number:

$value = (int) $xml->code[0]->distance; 

Comments

17

if you don't know the value of XML Element, you can use

$value = (string) $xml->code[0]->lat; if (ctype_digit($value)) { // the value is probably an integer because consists only of digits } 

It works when you need to determine if value is a number, because (string) will always return string and is_int($value) returns false

2 Comments

Any way to check also for boolean other than: (string)$value == 'true' || (string)$value == 'false'?
Note that this will not always be true. It's only valid for strings with natural (positive) integers. So, they must be in a string. They must not be float nor negative, since decimal separators, minus signs, etc will be evaluated to false. So, ctype_digit would be the same as preg_match('/^\d+$/', $var) If you want to check whether it's a numeric value, including floats and negatives, use is_numeric() instead.
16

Quick Solution if you in hurry.

convert a Xml-Object to an array (or object),

function loadXml2Array($file,$array=true){ $xml = simplexml_load_file($file); $json_string = json_encode($xml); return json_decode($json_string, $array); } 

2 Comments

Converting to JSON and then back in the same context is incredibly inefficient unless you are really in a hurry. Working with objects is not hard, and if you really prefer arrays, you ought to convert the object to an array natively.
I never understand why people do this - you throw away all the features of SimpleXML, just so you can write $xml['foo'][0]['bar'][0]['@attributes']['baz'] instead of $xml->foo->bar['baz'].
4

you can use the '{}' to access you property, and then you can do as you wish. Save it or display the content.

 $varName = $xml->{'key'}; 

From your example her's the code

 $filePath = __DIR__ . 'Your path '; $fileName = 'YourFilename.xml'; if (file_exists($filePath . $fileName)) { $xml = simplexml_load_file($filePath . $fileName); $mainNode = $xml->{'code'}; $cityArray = array(); foreach ($mainNode as $key => $data) { $cityArray[..] = $mainNode[$key]['cityCode']; .... } } 

2 Comments

There's no need to use {} unless there are special characters like hyphens in there. $xml->{'key'} is just an uglier way of writing $xml->key.
Exactly :p Its different, if you'd have it in some dynamic way, then you could use $xml->{$dynamicKey}
3

This is the function that has always helped me convert the xml related values to array

function _xml2array ( $xmlObject, $out = array () ){ foreach ( (array) $xmlObject as $index => $node ) $out[$index] = ( is_object ( $node ) ) ? _xml2array ( $node ) : $node; return $out; } 

1 Comment

This will throw away, or break with, among other things: any attributes, anything in a namespace, any CDATA blocks. All just so you can lose the convenience methods which SimpleXML offered you in the first place.
2

try current($xml->code[0]->lat)

it returns element under current pointer of array, which is 0, so you will get value

Comments

1
header("Content-Type: text/html; charset=utf8"); $url = simplexml_load_file("http://URI.com"); foreach ($url->PRODUCT as $product) { foreach($urun->attributes() as $k => $v) { echo $k." : ".$v.' <br />'; } echo '<hr/>'; } 

1 Comment

This answer is lacking any explanation, and therefore misses the key insight which is that echo forces $v to become a string rather than an object, just as (string)$v would.
1

you can convert array with this function

function xml2array($xml){ $arr = array(); foreach ($xml->children() as $r) { $t = array(); if(count($r->children()) == 0) { $arr[$r->getName()] = strval($r); } else { $arr[$r->getName()][] = xml2array($r); } } return $arr; } 

3 Comments

You can, but why would you want to?
Because if index is a number, it may be a problem. Like this $variable->code->0 ? SimpleXMLElement Object ( [code] => Array ( [0] => SimpleXMLElement Object (...
<0> is not a valid XML tag, so that would never happen. A few valid XML names are not valid PHP names, like <foo-bar>, but that can be handled with ->{'foo-bar'} syntax. Or do you just mean accessing the 0th element in a list of similar named elements? That's just $parent->childName[0].
0
$codeZero = null; foreach ($xml->code->children() as $child) { $codeZero = $child; } $lat = null; foreach ($codeZero->children() as $child) { if (isset($child->lat)) { $lat = $child->lat; } } 

9 Comments

I'm not sure what this code snippet is trying to show, but it looks like it's a very convoluted (and wrong) way of writing $codeZero = $xml->code[0] and $lat = $xml->code[0]->lat
@IMSoP, you're voting this down without even trying the code? I wouldn't have posted it if it didn't work. You're suggestion doesn't allow for a foreach, which is cleaner than a simple for loop. I don't remember all the details anymore, but it worked when other solutions didn't.
I voted down mostly because it has no explanation of what it's doing. If even you don't understand it when you read it back, how is it supposed to be useful to anybody else? As for using a foreach, sure you can: foreach ( $xml->code as $code ) { $lat = (string)$code->lat; echo $lat; } But what you're looping over here is "all the children of the first <code> element"; which doesn't make much sense to me. To clarify, $xml->code->children() is shorthand for $xml->code[0]->children(), not "children called code".
@IMSoP, Well, that's a fair point. I should have provided an explanation; it probably seemed so obvious to me at the time that it didn't occur to me. However, in my favor, at least, is the fact that whoever is on this page already knows the context and won't need an explanation because they already know what's happening. This is proven by the fact that one person already up-voted my answer or I would now be in the negative. I will do better at posting an explanation in the future.
Also, I can almost guarantee I would have tried your suggestion first, and it didn't work so I had to find another.
|
-1

This question is quite old - I appreciate that, but I also discovered (in PHP 8.2) that you can use trim() on a SimpleXMLElement Object and whilst the input isn't technically a string, it will convert it! Not sure if that is a glitch with PHP as clearly its an object not a string but does work as of 2024.

1 Comment

"A glitch"? No, the SimpleXMLElement has a __toString() method since PHP 5.3, as far as the documentation is correct. And using trim() does not look related to the given problem after all
-2
foreach($xml->code as $vals ) { unset($geonames); $vals=(array)$vals; foreach($vals as $key => $value) { $value=(array)$value; $geonames[$key]=$value[0]; } } print_r($geonames); 

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.