Obtener valor del objeto SimpleXMLElement


197

Tengo algo como esto:

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

Se supone que descarga XML de geonames. Si lo hago print_r($xml), obtengo:

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
                )

Hago lo que puedes ver $xml->code[0]->laty devuelve un objeto. ¿Como puedo obtener el valor?



@kubas, ¿puedes seleccionar una respuesta?
kqw

1
Actualización 2017: SO ya no muestra la mejor respuesta en la parte superior. La mejor respuesta está aquí .
rinogo

2
@rinogo Probablemente has hecho clic accidentalmente en una de las pestañas de clasificación en la parte superior del bloque de respuesta. La respuesta a la que se vinculó tiene 345 votos, por lo que se muestra en la parte superior si tiene la clasificación establecida en "votos".
IMSoP

1
Gracias, @IMSoP! Tienes razón: debo haber hecho clic en "activo" en algún momento (útil para preguntas antiguas con respuestas desactualizadas, por cierto). ¡Es bueno saber que necesito volver a cambiarlo a "votos"! :)
rinogo

Respuestas:


426

Tienes que lanzar un objeto simpleXML a una cadena.

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

9
Acabo de notar que si json_encode el objeto xml y luego json_decode se obtiene un stdObject anidado con el que lidiar, bastante útil para cuando eres perezoso y trabajas con estructuras simples: D
Louis

1
pregunta tonta, pero ¿no es eso un error? vea php.net/simplexml#95762 ¿por qué no tiene que emitir texto en algunos campos sino en otros?
gcb

77
¡Esta respuesta sigue pateando traseros aún más duro en 2016!
Hirdesh Vishwdewa

44
No puedo creer que esto sea tan complicado. ¿por qué harían una clase llamada "getName" pero no "getValue"? ¿Por qué imprimirían una cadena vacía si la imprimiera en lugar de convertirla manualmente a (cadena)? ¿¿POR QUÉ??
user151496

1
@ user151496 Técnicamente, el reparto de cadenas no le proporciona el "valor", sino el "contenido de texto". Pero sí, un método específicamente nombrado sería más reconocible. Sin embargo, una vez que te acostumbras a esto, en realidad no es más difícil de usar .
IMSoP

91

También puedes usar el método mágico __toString ()

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

55
O sprintfcon el %sformato. O echoy búfer de salida, o o o o ...
hakre

¿Cómo puedo convertir el objeto a XML en PHP? @sglessard
Gema

17

Si sabe que el valor del elemento XML es un número flotante (latitud, longitud, distancia), puede usar (float)

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

Además, (int)para el número entero:

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

15

Si no conoce el valor del elemento XML, puede usar

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

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

Funciona cuando necesita determinar si el valor es un número, porque (string)siempre devolverá una cadena y is_int($value)devolveráfalse


Cualquier forma de verificar también para el valor booleano que no sea: (string) $ value == 'true' || (cadena) $ valor == 'falso'?
Talisin

12

Para mí es más fácil usar matrices que objetos,

Entonces, convierto un Xml-Object,

$xml = simplexml_load_file('xml_file.xml');    
$json_string = json_encode($xml);    
$result_array = json_decode($json_string, TRUE);

3
Convertir a JSON y luego volver al mismo contexto es increíblemente ineficiente a menos que tenga mucha prisa. Trabajar con objetos no es difícil, y si realmente prefiere las matrices, debe convertir el objeto en una matriz de forma nativa.
William

Nunca entiendo por qué la gente hace esto: descarta todas las características de SimpleXML, solo para poder escribir en $xml['foo'][0]['bar'][0]['@attributes']['baz']lugar de hacerlo $xml->foo->bar['baz'].
IMSoP

2

Esta es la función que siempre me ha ayudado a convertir los valores relacionados con xml en matriz

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

    return $out;
}

Esto arrojará, o romperá, entre otras cosas: cualquier atributo, cualquier cosa en un espacio de nombres, cualquier bloque CDATA. Todo para que pueda perder los métodos de conveniencia que SimpleXML le ofreció en primer lugar.
IMSoP

1

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

devuelve el elemento debajo del puntero actual de la matriz, que es 0, por lo que obtendrá valor


1

puede usar el '{}' para acceder a su propiedad, y luego puede hacer lo que desee. Guárdelo o muestre el contenido.

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

De tu ejemplo, ella es el 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
No es necesario usarlo a {}menos que haya caracteres especiales como guiones allí. $xml->{'key'}es solo una forma más fea de escribir $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
Esta respuesta carece de explicación y, por lo tanto, pierde la idea clave que echoobliga $va convertirse en una cadena en lugar de un objeto, tal como lo (string)$vharía.
IMSoP

0

puedes convertir una matriz con esta función

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

Puedes, pero ¿por qué quieres hacerlo?
IMSoP

Porque si el índice es un número, puede ser un problema. ¿Te gusta esta $ variable-> código-> 0? SimpleXMLElement Object ([code] => Array ([0] => SimpleXMLElement Object (...
nixis

<0>no es una etiqueta XML válida, por lo que eso nunca sucedería. Algunos nombres XML válidos no son nombres PHP válidos, como <foo-bar>, pero eso se puede manejar con ->{'foo-bar'}sintaxis. ¿O simplemente te refieres a acceder al 0elemento th en una lista de elementos con nombre similares? Eso es justo $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;
   }
}

No estoy seguro de lo que este fragmento de código está tratando de mostrar, pero parece que es una forma muy complicada (e incorrecta) de escribir $codeZero = $xml->code[0]y$lat = $xml->code[0]->lat
IMSoP

@IMSoP, ¿está rechazando esto sin siquiera probar el código? No lo habría publicado si no funcionara. Su sugerencia no permite un foreach, que es más limpio que un simple bucle for. Ya no recuerdo todos los detalles, pero funcionó cuando otras soluciones no lo hicieron.
Craned

Voté en contra principalmente porque no tiene explicación de lo que está haciendo. Si incluso no lo entiendes cuando lo lees de nuevo, ¿cómo se supone que será útil para alguien más? En cuanto a usar un foreach, seguro que puedes: foreach ( $xml->code as $code ) { $lat = (string)$code->lat; echo $lat; }Pero lo que estás haciendo aquí es "todos los hijos del primer <code>elemento"; lo cual no tiene mucho sentido para mí. Para aclarar, $xml->code->children()es la abreviatura de $xml->code[0]->children(), no "niños llamados code".
IMSoP

@IMSoP, bueno, ese es un punto justo. Debería haber proporcionado una explicación; probablemente me pareció tan obvio en ese momento que no se me ocurrió. Sin embargo, a mi favor, al menos, es el hecho de que quien está en esta página ya conoce el contexto y no necesitará una explicación porque ya sabe lo que está sucediendo. Esto se demuestra por el hecho de que una persona ya votó mi respuesta o ahora estaría en negativo. Lo haré mejor publicando una explicación en el futuro.
Craned

Además, casi puedo garantizar que habría intentado su sugerencia primero, y no funcionó, así que tuve que encontrar otra.
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);
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.