viernes 1 de agosto de 2008

Consumiendo Yahoo! Weather desde PHP 2da. parte

En la nota anterior vimos como consumir fácilmente el RSS de Yahoo! Weather para mostrar el estado del clima de una ciudad en nuestro sitio web en el formato que nos da Yahoo!.

Hoy vamos a ver como obtenemos la información específica sobre el estado del clima, es decir, la temperatura, nubosidad, vientos, etc., y así poder desplegar la información en nuestro sitio con la apariencia que queramos.

Para esto, necesitamos acceder a las propiedades de los elementos del namespace yweather que vienen incluidos en el RSS . Estos elementos son los que vemos en el código fuente del XML que comienzan con <yweather:

El problema es que el SimpleXML al parsear el RSS nos elimina del XML estos elementos por pertenecer a otro namespace. Entonces, para poder obtenerlos, debemos eliminar el texto 'yweather:' del RSS y lo hacemos de la siguiente manera (siguiendo con el código de ejemplo de la primer parte de la nota):


<?php
$url = "http://weather.yahooapis.com/forecastrss?p=$location&u=$units";
$rss = file_get_contents($url);
$yWeather = simplexml_load_string(str_replace('yweather:', '', $rss));
?>


Lo único que agregué es el str_replace() al momento de parsear el string $rss.

Ahora, tendremos disponible en nuestro objeto SimpleXML los elementos yweather:* que contienen informacion del clima actual, los proximos dias, el viento, la ubicación, y otros datos.

Entonces por ejemplo, si queremos acceder a las condiciones climáticas actuales (temperatura y descripción del estado del cielo), deberemos consumir el elemento yweather:conditions que contiene estas propiedades. En el código fuente puro del RSS lo veremos similar al siguiente:


<yweather:condition text="Cloudy" code="26" temp="12" date="Fri, 01 Aug 2008 12:00 pm ART" />


Ahi vemos que este elemento contiene las propiedades text, code, temp y date con la información que buscamos.

Bueno, aca nos encontramos con el primer problema: SimpleXML no parsea directamente los atributos de los elementos, sino que proporciona acceso a ellos a través de una iteración del método attributes() del elemento contenedor.
Entonces, siguiendo con el código anterior, podemos añadir lo siguiente al código anterior para ver como obtenemos las propiedades:


foreach($yWeather->channel->item->condition->attributes() as $a => $b) {
echo $a . ' => ' . $b
}


Como vemos, accedemos al método attributes() del elemento conditions que es el que queremos leer.

Si ejecutamos este código, veremos nuestro segundo problema: Al leer el valor de un atributo... por ejemplo code, veremos que se parsea toda la expresión entera del atributo y no solo el valor, o sea que estaremos viendo algo como:


code => code="26"


Asi que lo que nos queda por hacer es quitar los caracteres indeseados y el nombre del atributo del valor parseado por SimpleXML. Con esto ya podríamos obtener un array útil con la siguiente estructura:


array(
"text" => "Cloudy",
"code" => "26",
"temp" => "12",
"date" => "Fri, 01 Aug 2008 12:00 pm ART"
);


Y ahora vemos el código completo terminado para obtener nuestro array de información útil:


<?php
$url = "http://weather.yahooapis.com/forecastrss?p=$location&u=$units";
$rss = file_get_contents($url);
$yWeather = simplexml_load_string(str_replace('yweather:', '', $rss));

$aConditions = array();
foreach($yWeather->channel->item->condition->attributes() as $a => $b) {
$cleanStr = array("'" => '', '"' => '', '=' => '', $a => '');
$aConditions[$a] = trim(strtr($b->asXML(), $cleanStr));
}

var_dump($aConditions);

?>


Como ven, uso la función strtr() de PHP para eliminar el contenido indeseado del valor del atributo.
Al final hago un dump del array para que se muestre por pantalla el contenido del array a modo ilustrativo. A partir de ahi uds. usarán la información del array para sus propios fines.

Y ahi lo tenemos, en 8 líneas de código (sin el dump y sin las líneas vacías). Se pueden basar en el parseo del elemento conditions para obtener información de otros elementos como yweather:atmosphere o yweather:wind o el que necesiten consumir.

4 comentarios:

Esteban dijo...

Hola. Lei tu articulo y te hago una pregunta:

Como hago para hacer un "echo $text" por ejemplo, para que me muestre "Sunny".

Gracias

Leo dijo...

Esteban:
Al final del último código de ejemplo, podés hacer un:

echo $aConditions['text'];

Lo que te devolvería "Sunny" o la condición actual.

chapu dijo...

gracias viejo! me vino de diez, anduve buscando un montón para desarmar el rss este de yahoo... porque pasaba eso el simplexml no tomaba los yweather:

creativa la solución, gracias!

Leo dijo...

@chapu

Gracias por el feedback!
Seguramente haya soluciones mas elegantes para acceder a los elementos de un namespace diferente, pero para una tarea tan simple como esta, me pareció más practica esta solución.

Saludos!