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

У меня примерно так:

$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 загружается с geonames. Если я сделаю 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, и он возвращает объект. Как я могу получить значение?


person kubas    schedule 19.05.2010    source источник
comment
возможный дубликат Принуждение объекта SimpleXML к строке, независимо от контекста   -  person hakre    schedule 28.09.2014
comment
Обновление 2017: SO больше не отображает лучший ответ вверху. Лучший ответ здесь.   -  person rinogo    schedule 07.06.2017
comment
@rinogo Вы, вероятно, случайно нажали одну из вкладок сортировки в верхней части блока ответов. Ответ, на который вы связались, получил 345 голосов, поэтому отображается вверху, если у вас настроена сортировка по голосам.   -  person IMSoP    schedule 29.08.2017
comment
Спасибо, @IMSoP! Вы правы - в какой-то момент я, должно быть, щелкнул активным (полезно для старых вопросов с устаревшими ответами, кстати) - хорошо знать, что мне нужно снова изменить его на голоса! :)   -  person rinogo    schedule 29.08.2017


Ответы (11)


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

$value = (string) $xml->code[0]->lat;
person Luis Melgratti    schedule 19.05.2010
comment
Просто заметил, что если вы json_encode объект xml, а затем json_decode, вы получите вложенный stdObject для работы, что очень удобно, когда вы ленивы и работаете с простыми структурами: D - person Louis; 20.09.2013
comment
Сегодня 10 января 2013 г., день, когда этот ответ сэкономил мне массу времени! - person Christian Page; 10.01.2014
comment
глупый вопрос, а разве это не баг? см. php.net/simplexml#95762, почему вам не нужно вводить тип в некоторых полях, кроме другие вы должны? - person gcb; 16.02.2014
comment
В 2016 году этот ответ по-прежнему остро стоит на ногах! - person Hirdesh Vishwdewa; 19.07.2016
comment
я не могу поверить, что это так сложно. зачем им создавать класс с именем getName, но не getValue? зачем им печатать пустую строку, если вы напечатали ее вместо того, чтобы вручную преобразовать ее в (строку). ЗАЧЕМ?? - person user151496; 17.10.2016
comment
@ user151496 Технически преобразование строки дает вам не значение, а текстовое содержимое. Но да, метод с конкретным названием было бы легче обнаружить. Однако, как только вы к этому привыкнете, использовать не станет труднее. - person IMSoP; 29.08.2017
comment
я всегда убиваю хотя бы полдня, обнаруживая причуды simpleXML каждый раз, когда мне нужно добраться до него раз в пару месяцев в некоторых проектах - person user151496; 19.09.2017
comment
Да, это простой элемент XMLElement, и как бы вы ни старались, вы всегда получите другой SimpleXMLElement (да даже для ->children() метода), поэтому нет innerHTML / innerText - Возвращает текст контент, который находится непосредственно в этом элементе. Не возвращает текстовое содержимое, которое находится внутри дочерних элементов этого элемента. - person jave.web; 29.04.2021

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

$xml->code[0]->lat->__toString()
person sglessard    schedule 01.09.2011
comment
Или sprintf в формате %s. Или echo и буферизация вывода, или или, или ... - person hakre; 31.05.2012
comment
Как я могу преобразовать объект в XML в PHP? @sglessard - person Gem; 16.11.2018
comment
@Gem, вам, вероятно, нужна какая-то сериализация - см. https://stackoverflow.com/questions/137021/php-object-as-xml-document. - person jave.web; 29.04.2021

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

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

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

$value = (int) $xml->code[0]->distance;
person CoursesWeb    schedule 30.08.2012

если вы не знаете значение элемента 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

person vladkras    schedule 14.08.2013
comment
Любой способ проверить также на логическое значение, отличное от: (string) $ value == 'true' || (строка) $ value == 'false'? - person Talisin; 29.06.2014
comment
Учтите, что это не всегда так. Это справедливо только для строк с натуральными (положительными) целыми числами. Значит, они должны быть в виде строки. Они не должны быть ни с плавающей точкой, ни с отрицательными, поскольку десятичные разделители, знаки минус и т. Д. Будут оценены как ложные. Итак, ctype_digit будет таким же, как preg_match ('/ ^ \ d + $ /', $ var). Если вы хотите проверить, является ли это числовым значением, включая числа с плавающей запятой и отрицательные, используйте вместо них is_numeric (). - person luis.ap.uyen; 18.03.2021

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

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

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

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

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

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

попробуйте current($xml->code[0]->lat)

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

person Bendeberia    schedule 07.04.2015

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

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

            }     

        }
person Zakaria Charik    schedule 23.05.2017
comment
Нет необходимости использовать {}, если в нем нет специальных символов, например дефисов. $xml->{'key'} - это просто более уродливый способ написания $xml->key. - person IMSoP; 29.08.2017

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

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;
}
person nixis    schedule 12.08.2015
comment
Вы можете, но зачем вам это нужно? - person IMSoP; 29.08.2017
comment
Потому что, если index - это число, это может быть проблемой. Как эта переменная $- ›code-› 0? Объект SimpleXMLElement ([code] = ›Массив ([0] =› Объект SimpleXMLElement (... - person nixis; 30.11.2017
comment
<0> не является допустимым тегом XML, поэтому этого никогда не произойдет. Некоторые допустимые имена XML не являются допустимыми именами PHP, например <foo-bar>, но с этим можно справиться с помощью синтаксиса ->{'foo-bar'}. Или вы просто имеете в виду доступ к 0-му элементу в списке элементов с похожими именами? Это просто $parent->childName[0]. - person IMSoP; 30.11.2017

person    schedule
comment
В этом ответе отсутствует какое-либо объяснение, и поэтому упускается главное понимание, которое заключается в том, что echo вынуждает $v стать строкой, а не объектом, как (string)$v. - person IMSoP; 29.08.2017

person    schedule
comment
Я не уверен, что пытается показать этот фрагмент кода, но похоже, что это очень запутанный (и неправильный) способ написания $codeZero = $xml->code[0] и $lat = $xml->code[0]->lat - person IMSoP; 29.08.2017
comment
@IMSoP, вы голосуете за это, даже не попробовав код? Я бы не выложил его, если бы он не работал. Ваше предложение не позволяет использовать foreach, который чище, чем простой цикл for. Я уже не помню всех деталей, но это сработало, когда другие решения не работали. - person craned; 08.09.2017
comment
Я проголосовал против в основном потому, что в нем нет объяснения того, что он делает. Если даже вы не понимаете этого, когда перечитываете его, как это может быть полезно для кого-то еще? Что касается использования foreach, конечно, вы можете: foreach ( $xml->code as $code ) { $lat = (string)$code->lat; echo $lat; } Но то, что вы здесь зацикливаете, - это все дочерние элементы первого <code> элемента; что для меня не имеет особого смысла. Чтобы уточнить, $xml->code->children() - это сокращение для $xml->code[0]->children(), а не для детей, называемых code. - person IMSoP; 08.09.2017
comment
@IMSoP, ну это справедливый вопрос. Я должен был дать объяснение; Наверное, тогда это казалось мне настолько очевидным, что не приходило мне в голову. Однако, по крайней мере, в мою пользу тот факт, что тот, кто находится на этой странице, уже знает контекст и не нуждается в объяснении, потому что они уже знают, что происходит. Это подтверждается тем фактом, что один человек уже проголосовал за мой ответ, иначе я был бы отрицательным. Я лучше опубликую объяснение в будущем. - person craned; 08.09.2017
comment
Кроме того, я могу почти гарантировать, что сначала попробую ваше предложение, но оно не сработало, поэтому мне пришлось искать другое. - person craned; 08.09.2017
comment
Ради удовольствия, я опробовал ваш код здесь: 3v4l.org/7FWgv Как и ожидалось, это не так. Не делаю ничего особенно полезного. - person IMSoP; 08.09.2017
comment
@IMSoP, спасибо, что доказали в качестве третьей стороны, что на самом деле это не так. Он делает что-то особенно полезное только тогда, когда ничего не работает. Всегда есть неожиданный сценарий, когда то, что должно работать, не работает. И вот что привело к моему решению. И, к слову, мне он кажется довольно чистым. Я не знаю, почему вы думаете, что это запутанно. - person craned; 08.09.2017
comment
Это зависит от того, что вы имеете в виду под неправильным. Он компилируется. С совершенно другой структурой XML он может даже получить значение, отличное от null. Он находит последний дочерний элемент первого <code> элемента, затем ищет дочерние элементы этого и находит последний из тех дочерних элементов, у которых есть дочерний элемент с именем <lat>, и возвращает его. Это кажется очень специфической задачей, но, возможно, вы столкнулись с ней. Однако это не имеет абсолютно никакого отношения к вопросу на этой странице, ответ на который, как гласит ответ, получивший наибольшее количество голосов, заключался в добавлении (string). Так что в этом смысле да, это совершенно неверный ответ. - person IMSoP; 09.09.2017
comment
Я был неправ, называя это запутанным. Если ваше требование действительно заключалось в том, чтобы выполнить поиск в 5-уровневом глубоком XML-документе, найти последний элемент на 3-м уровне и последний соответствующий определенному условию на 4-м уровне, это разумный алгоритм. Однако это не структура, представленная в этом вопросе, и никак не связанная с поставленной проблемой. Это все равно, что ответить на запрос о музыке к «Мессии» Генделя текстами к «Стране чудес Оазиса» - вы можете подумать, а можете и не подумать, что это хорошее музыкальное произведение, но оно совершенно бесполезно для запрошенной цели. - person IMSoP; 09.09.2017