Получить значение из объекта SimpleXMLElement

197

У меня есть что-то вроде этого:

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

Предполагается скачать XML с геонеймов. Если print_r($xml)я получу:

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
                )

Я делаю, как вы можете видеть, $xml->code[0]->latи он возвращает объект. Как я могу получить значение?

Кубас
источник
@kubas вы можете выбрать ответ?
KQW
1
2017 Обновление: SO больше не отображает лучший ответ в верхней части. Лучший ответ здесь .
Риного
2
@rinogo Вы, вероятно, случайно нажали одну из вкладок сортировки в верхней части блока ответа. Ответ, на который вы ссылаетесь, имеет 345 голосов, поэтому вверху показывается, если для сортировки установлено значение «голоса».
IMSoP
1
Спасибо, @IMSoP! Вы правы - я, должно быть, в какой-то момент нажал «активно» (полезно для старых вопросов с устаревшими ответами, кстати) - приятно знать, что мне нужно изменить его на «голоса»! :)
риного

Ответы:

426

Вы должны преобразовать объект simpleXML в строку.

$value = (string) $xml->code[0]->lat;
Луис Мелгратти
источник
9
Просто заметил, что если вы json_encode xml-объект, а затем json_decode его, вы получите вложенный stdObject для работы, очень удобно, когда вы ленитесь и работаете с простыми структурами: D
Louis
1
глупый вопрос, но разве это не ошибка? см. php.net/simplexml#95762 почему не нужно приводить тип для одних полей, а для других -?
gcb
7
Этот ответ все еще бьет себя еще сильнее в 2016 году!
Хирдеш Вишдева
4
Я не могу поверить, что это так сложно. почему они создают класс с именем "getName", а не "getValue"? зачем им печатать пустую строку, если вы печатаете ее вместо того, чтобы вручную преобразовывать ее в (строку). ЗАЧЕМ??
user151496
1
@ user151496 Технически, приведение строки дает не «значение», а «текстовое содержимое». Но да, метод с конкретным именем был бы более обнаружим. Однако, как только вы привыкнете к этому, на самом деле использовать его будет не сложнее .
IMSoP
91

Вы также можете использовать магический метод __toString ()

$xml->code[0]->lat->__toString()
sglessard
источник
5
Или sprintfс %sформатом. Или echoи буферизация вывода, или или или или ...
хакре
Как я могу преобразовать объект в XML в PHP? @sglessard
Gem
17

Если вы знаете, что значением элемента XML является число с плавающей точкой (широта, долгота, расстояние), вы можете использовать (float)

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

Также (int)для целого числа:

$value = (int) $xml->code[0]->distance;
CoursesWeb
источник
15

если вы не знаете значение элемента XML, вы можете использовать

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

if (ctype_digit($value)) {
    // the value is probably an integer because consists only of digits
}

Это работает, когда вам нужно определить, является ли значение числом, потому (string)что всегда будет возвращать строку и is_int($value)возвращаетfalse

vladkras
источник
Любой способ проверить также на логическое значение, кроме: (строка) $ value == 'true' || (строка) $ value == 'false'?
Талисин
12

Для меня это проще использовать массивы, чем объекты,

Итак, я конвертирую Xml-объект,

$xml = simplexml_load_file('xml_file.xml');    
$json_string = json_encode($xml);    
$result_array = json_decode($json_string, TRUE);
dazzafact
источник
3
Преобразование в JSON, а затем обратно в тот же контекст невероятно неэффективно, если вы действительно не торопитесь. Работать с объектами несложно, и если вы действительно предпочитаете массивы, вам следует преобразовать объект в массив.
Уильям
Я никогда не понимаю, почему люди так делают - вы отбрасываете все функции SimpleXML, просто чтобы писать $xml['foo'][0]['bar'][0]['@attributes']['baz']вместо $xml->foo->bar['baz'].
IMSoP
2

Это функция, которая всегда помогала мне преобразовывать значения, связанные с XML, в массив

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

    return $out;
}
pal4life
источник
Это отбросит или порвет, среди прочего: любые атрибуты, что-либо в пространстве имен, любые блоки CDATA. Все просто так, что вы можете потерять удобные методы, которые SimpleXML предложил вам в первую очередь.
IMSoP
1

пытаться current($xml->code[0]->lat)

он возвращает элемент под текущим указателем массива, который равен 0, поэтому вы получите значение

Bendeberia
источник
1

Вы можете использовать «{}» для доступа к своей собственности, а затем можете делать все, что пожелаете. Сохраните его или отобразите содержимое.

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

Из вашего примера ее код

        $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'];
               ....

            }     

        }
Закария Чарик
источник
3
Нет необходимости использовать, {}если там нет специальных символов, таких как дефисы. $xml->{'key'}это просто уродливый способ написания $xml->key.
IMSoP
0
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/>';
}
Шахин Солмаз
источник
2
В этом ответе отсутствуют какие-либо объяснения, и, следовательно, отсутствует ключевая идея, которая echoзаставляет $vстать строкой, а не объектом, как это (string)$vбыло бы.
IMSoP
0

Вы можете конвертировать массив с помощью этой функции

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;
}
nixis
источник
Вы можете, но почему вы хотите?
IMSoP
Потому что, если индекс - это число, это может быть проблемой. Как этот $ variable-> code-> 0? Объект SimpleXMLElement ([code] => Array ([0] => Объект SimpleXMLElement (...
nixis
<0>не является допустимым тегом XML, так что это никогда не произойдет. Некоторые действительные имена XML не являются действительными именами PHP, <foo-bar>но могут быть обработаны с помощью ->{'foo-bar'}синтаксиса. Или вы просто имеете в виду доступ к 0элементу th в списке похожих именованных элементов? Это просто $parent->childName[0].
IMSoP
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;
   }
}
вытягивали
источник
Я не уверен, что этот фрагмент кода пытается показать, но похоже, что это очень запутанный (и неправильный) способ написания $codeZero = $xml->code[0]и$lat = $xml->code[0]->lat
IMSoP
@IMSoP, вы голосуете, даже не пытаясь код? Я не отправил бы это, если бы это не работало. Ваше предложение не учитывает foreach, который чище, чем простой цикл for. Я не помню все детали больше, но это работало, когда другие решения не делали.
вытянул
Я проголосовал в основном потому, что у него нет объяснения тому, что он делает. Если даже вы не понимаете этого, когда читаете его обратно, как это должно быть полезно для кого-то еще? Что касается использования foreach, конечно, вы можете: foreach ( $xml->code as $code ) { $lat = (string)$code->lat; echo $lat; }Но то, что вы зацикливаете здесь, это «все потомки первого <code>элемента»; что не имеет особого смысла для меня. Чтобы уточнить, $xml->code->children()это сокращение для $xml->code[0]->children(), а не "дети называют code".
IMSoP
@IMSoP, ну, это справедливо. Я должен был предоставить объяснение; в то время мне это казалось настолько очевидным, что мне не приходило в голову. Однако, в мою пользу, по крайней мере, тот факт, что тот, кто находится на этой странице, уже знает контекст и не нуждается в объяснении, потому что он уже знает, что происходит. Это подтверждается тем фактом, что один человек уже проголосовал против моего ответа, иначе я бы сейчас был отрицательным. Я сделаю лучше в публикации объяснения в будущем.
вытянули
Кроме того, я почти гарантирую, что сначала попробовал бы ваше предложение, и оно не сработало, поэтому мне пришлось искать другое.
вытянули
-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);
Амаль Джо Энтони
источник