Obter valor do objeto SimpleXMLElement

197

Eu tenho algo parecido com isto:

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

É suposto baixar XML de geonames. Se print_r($xml)eu receber:

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
                )

Eu faço como você pode ver $xml->code[0]->late ele retorna um objeto. Como posso obter o valor?

kubas
fonte
@kubas você pode selecionar uma resposta?
Kqw # 20/14
1
Atualização de 2017: SO não exibe mais a melhor resposta na parte superior. A melhor resposta está aqui .
Rinogo 6/06
2
@rinogo Você provavelmente clicou acidentalmente em uma das guias de classificação na parte superior do bloco de respostas. A resposta à qual você vinculou possui 345 votos; portanto, é exibida na parte superior se você tiver definido para "votos".
IMSoP 29/08
1
Obrigado, @IMSoP! Você está certo - eu devo ter clicado em "ativo" em algum momento (útil para perguntas antigas com respostas desatualizadas) - é bom saber que preciso alterá-lo novamente para "votos"! :)
rinogo

Respostas:

426

Você deve converter o objeto simpleXML em uma sequência.

$value = (string) $xml->code[0]->lat;
Luis Melgratti
fonte
9
Só notei se json_encode o objeto XML e, em seguida, json_decode que você começa um stdObject aninhada de lidar, bastante útil para quando você está sendo preguiçoso e trabalhar com estruturas simples: D
Louis
1
pergunta boba, mas isso não é um bug? veja php.net/simplexml#95762 por que você não precisa converter o tipo em alguns campos, mas em outros, precisa?
gcb
7
Essa resposta ainda está chutando as bundas ainda mais em 2016!
Hirdesh Vishwdewa
4
Eu não posso acreditar que isso é tão complicado. por que eles criariam uma classe chamada "getName", mas não "getValue"? por que eles imprimiriam uma string vazia se você a imprimisse em vez de convertê-la manualmente em (string). PORQUE??
user151496
1
@ user151496 Tecnicamente, a conversão de string não fornece o "valor", mas o "conteúdo de texto". Mas sim, um método com nome específico seria mais detectável. Depois de se acostumar com isso, porém, não é mais difícil de usar .
IMSoP 29/08
91

Você também pode usar o método mágico __toString ()

$xml->code[0]->lat->__toString()
sglessard
fonte
5
Ou sprintfcom o %sformato. Ou echoe buffer de saída, ou ou ou ou ...
hakre
Como posso converter o objeto para XML em PHP? @sglessard
Gem
17

Se você souber que o valor do elemento XML é um número flutuante (latitude, longitude, distância), poderá usar (float)

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

Além disso, (int)para número inteiro:

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

se você não souber o valor do elemento XML, poderá usar

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

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

Funciona quando você precisa determinar se o valor é um número, porque (string)sempre retornará string e is_int($value)retornafalse

vladkras
fonte
Qualquer maneira de verificar também se há booleano além de: (string) $ value == 'true' || (string) $ value == 'falso'?
Talisin
12

Para mim, é mais fácil usar matrizes do que objetos,

Então, eu converto um objeto Xml,

$xml = simplexml_load_file('xml_file.xml');    
$json_string = json_encode($xml);    
$result_array = json_decode($json_string, TRUE);
dazzafact
fonte
3
Converter para JSON e depois voltar para o mesmo contexto é incrivelmente ineficiente, a menos que você esteja realmente com pressa. Trabalhar com objetos não é difícil e, se você realmente prefere matrizes, deve converter o objeto em uma matriz nativamente.
William William
Eu nunca entendo por que as pessoas fazem isso - você joga fora todos os recursos do SimpleXML, apenas para escrever em $xml['foo'][0]['bar'][0]['@attributes']['baz']vez de $xml->foo->bar['baz'].
IMSOP
2

Esta é a função que sempre me ajudou a converter os valores relacionados a xml em array

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

    return $out;
}
pal4life
fonte
Isso descartará ou romperá, entre outras coisas: quaisquer atributos, qualquer coisa em um espaço para nome, qualquer bloco CDATA. Tudo para que você possa perder os métodos de conveniência que o SimpleXML lhe ofereceu em primeiro lugar.
IMSoP 29/08
1

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

retorna elemento sob o ponteiro atual da matriz, que é 0, para que você obtenha valor

Bendeberia
fonte
1

você pode usar o '{}' para acessar sua propriedade e, em seguida, pode fazer o que quiser. Salve ou exiba o conteúdo.

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

Do seu exemplo, ela é o código

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

            }     

        }
Zakaria Charik
fonte
3
Não há necessidade de usar, a {}menos que haja caracteres especiais como hífens. $xml->{'key'}é apenas uma maneira mais feia de escrever $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/>';
}
Solahin Solmaz
fonte
2
Essa resposta carece de explicação e, portanto, perde o insight principal, que é o de que as echoforças $vse tornam uma corda e não um objeto, exatamente como (string)$vfaria.
IMSOP
0

você pode converter array com esta função

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
fonte
Você pode, mas por que você gostaria?
IMSoP 29/08/17
Porque se o índice for um número, pode ser um problema. Como esse $ variable-> code-> 0? Objeto SimpleXMLElement ([code] => Array ([0] => Objeto SimpleXMLElement (...
nixis
<0>não é uma tag XML válida, portanto isso nunca aconteceria. Alguns nomes XML válidos não são nomes PHP válidos, como <foo-bar>, mas podem ser tratados com ->{'foo-bar'}sintaxe. Ou você quer apenas acessar o 0elemento th em uma lista de elementos nomeados semelhantes? Isso é só $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;
   }
}
guindaste
fonte
Eu não tenho certeza do que este trecho de código está tentando mostrar, mas parece que é uma maneira muito complicada (e errado) da escrita $codeZero = $xml->code[0]e$lat = $xml->code[0]->lat
IMSOP
@IMSoP, você está votando isso sem tentar o código? Eu não teria postado se não funcionasse. Sua sugestão não permite um foreach, que é mais limpo do que um loop for simples. Não lembro mais de todos os detalhes, mas funcionou quando outras soluções não.
craned
Eu votei contra, principalmente porque não tem explicação do que está fazendo. Se você nem entende quando lê de volta, como é que isso deve ser útil para mais alguém? Quanto ao uso de um foreach, com certeza você pode: foreach ( $xml->code as $code ) { $lat = (string)$code->lat; echo $lat; }Mas o que você está repetindo aqui é "todos os filhos do primeiro <code>elemento"; o que não faz muito sentido para mim. Para esclarecer, $xml->code->children()é uma abreviação de $xml->code[0]->children(), não "crianças chamadas code".
IMSoP
@ IMSoP, bem, esse é um ponto justo. Eu deveria ter fornecido uma explicação; provavelmente me pareceu tão óbvio na época que não me ocorreu. No entanto, a meu favor, pelo menos, está o fato de que quem está nesta página já conhece o contexto e não precisa de uma explicação porque já sabe o que está acontecendo. Isso é comprovado pelo fato de uma pessoa já ter votado positivamente na minha resposta ou agora estaríamos negativos. Farei melhor ao postar uma explicação no futuro.
craned
Além disso, quase posso garantir que eu teria tentado sua sugestão primeiro e ela não funcionou, então tive que encontrar outra.
craned
-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);
Amal Jo Antony
fonte