Отримайте значення з SimpleXMLElement Object


198

У мене є щось подібне:

$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 року: Так більше не відображається найкраща відповідь у верхній частині. Найкраща відповідь тут .
rinogo

2
@rinogo Ви, ймовірно, випадково натиснули одну з вкладок сортування у верхній частині блоку відповідей. Відповідь, з якою ви пов’язали, має 345 голосів, тож показує вгорі, якщо у вас сортування встановлено на "голоси".
IMSoP

1
Дякую, @IMSoP! Ви маєте рацію - я, мабуть, в якийсь момент натиснув "активний" (корисно для старих питань із застарілими відповідями, btw) - добре знати, що мені потрібно змінити його на "голоси"! :)
rinogo

Відповіді:


427

Ви повинні накинути об’єкт simpleXML в рядок.

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

10
Щойно помітив, якщо ви json_encode коду xml, а потім json_decode це, ви отримаєте вкладений stdObject для вирішення, що дуже зручно, коли ви лінуєтесь і працюєте з простими структурами: D
Луї,

1
дурне питання, але хіба це не помилка? перегляньте php.net/simplexml#95762, чому вам не потрібно вводити тип на деяких полях, а на інших, що потрібно?
gcb

7
Ця відповідь все ще б'є удари ще сильніше у 2016 році!
Hirdesh Vishwdewa

4
я не можу повірити, що це так складно. чому б вони створили клас під назвою "getName", але не "getValue"? чому вони друкують порожню рядок, якщо ви надрукували її замість того, щоб перетворити її вручну в (рядок). ЧОМУ ??
користувач151496

1
@ user151496 Технічно, передавання рядків дає не "значення", а "текстовий вміст". Але так, конкретно названий метод виявився б більш відкритим. Після того як ви звикнете до цього, хоча, це на самому справі не якийсь - або складніше використання .
IMSoP

92

Ви також можете використовувати магічний метод __toString ()

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

5
Або sprintfз %sформатом. Або echoі вивести буферизацію, або або або або ...
hakre

Як я можу перетворити об'єкт у XML у PHP? @sglessard
Gem

17

Якщо ви знаєте, що значенням XML-елемента є плаваюче число (широта, довгота, відстань), ви можете використовувати (float)

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

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

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

16

якщо ви не знаєте значення 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


Будь-який спосіб перевірити також булеві, крім: (string) $ 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);

4
Перехід до JSON, а потім повернення в тому ж контексті неймовірно неефективний, якщо ви дійсно не поспішаєте. Робота з об’єктами не є складною, і якщо ви дійсно віддаєте перевагу масивам, вам слід перетворити об’єкт у масив на самому собі.
Вільям

1
Я ніколи не розумію, чому люди так роблять - ви викидаєте всі функції 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;
}

Це викине або порушить, серед іншого, будь-які атрибути, що-небудь у просторі імен, будь-які блоки CDATA. Все так, що ви можете втратити зручні методи, які SimpleXML запропонував вам в першу чергу.
IMSoP

2

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

він повертає елемент під поточним покажчиком масиву, який дорівнює 0, тому ви отримаєте значення


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

Можна, але чому б ти цього хотів?
IMSoP

Тому що якщо індекс - це число, це може бути проблемою. Як ця $ змінна-> код-> 0? SimpleXMLElement Object ([code] => Array ([0] => SimpleXMLElement Object (...
nixis

<0>не є дійсним тегом XML, тому цього ніколи не відбудеться. Кілька дійсних імен XML не є дійсними іменами PHP, як <foo-bar>, але їх можна обробити ->{'foo-bar'}синтаксисом. Або ви просто маєте на увазі доступ до цього 0елемента у списку подібних названих елементів? Це просто $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, ви впевнені, що ви можете: foreach ( $xml->code as $code ) { $lat = (string)$code->lat; echo $lat; }Але те, що ви тут цикли, - це "всі діти першого <code>елемента"; що для мене не має великого сенсу. Для уточнення, $xml->code->children()це скорочення $xml->code[0]->children(), а не "діти покликані code".
IMSoP

@IMSoP, Ну, це справедлива справа. Я повинен був дати пояснення; мені це, мабуть, здавалося настільки очевидним, що мені не прийшло в голову. Однак, на мою користь, принаймні, той факт, що той, хто перебуває на цій сторінці, вже знає контекст і не потребуватиме пояснень, оскільки вони вже знають, що відбувається. Це доводить той факт, що одна людина вже підкреслила мою відповідь, або я зараз був би негативно. Я буду краще розміщувати пояснення в майбутньому.
викрадено

Крім того, я майже можу гарантувати, що спершу я б спробував вашу пропозицію, і це не вийшло, тому мені довелося знайти інше.
викрадено

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.