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

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()

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;

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


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

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

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


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

            }     

        }

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

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

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

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);
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.