12 Diciembre 2007

Cómo modificar documentos XML con PHP

Por Abel

Bien, después de haberme atrasado casi un mes y en vista de que es un tema difícil de encontrar en la red, voy a hacer un microtutorial sobre cómo modificar un documento XML usando PHP5. Ya vimos cómo hacer un parsing a un documento XML usando la extensión que provee PHP5 llamada SimpleXMLElement. Ahora veremos primero cómo modificar elementos de nuestro XML, estamos hablando de agregar o eliminar elementos.

Cómo agregar elementos, hijos y atributos

Hasta PHP 5.1.3 la extensión SimpleXMLElement no tenía forma de agregar elementos a un documento XML. Sólo era posible modificar los valores de elementos o atributos pero para agregar nuevos era necesario exportar el objeto SimpleXMLElement a DOM, hacer los cambios y exportar de nuevo a SimpleXMLElement, lo cual era una tarea complicada. Pero la versión 5.1.3 introdujo dos nuevos métodos que nos dan el poder de modificar el documento XML. Me refiero a los métodos:

SimpleXMLElement::addChild()
SimpleXMLElement::addAttribute()

El nombre lo dice todo, con el primero agregamos un elemento hijo al elemento en el que nos encontramos y con el segundo agregamos un atributo. addChild() acepta tres parámetros, el primero indica el nombre del nuevo elemento, el segundo es opcional e indica el valor del elemento, y el tercero también es opcional e indica el namespace al cual pertenece el elemento. addAttribute() recibe dos, el nombre del atributo y su valor.

Pongamos un ejemplo para ilustrar su uso. Recordemos el ejemplo de la vez pasada donde usamos un archivo XML cuyo contenido son libros con sus respectivos datos y pasemos a crear el objeto SimpleXMLElement.

$library = new SimpleXMLElement('library.xml', null, true);

Ahora supongamos que queremos agregar un nuevo libro llamado The finished mistery cuyo autor es J. F. Rutherford, el ISBN es 0812550706 y la editorial es Watchtower Society.

$book = $library->addChild('book');
$book->addAttribute('isbn', '0812550706');
$book->addChild('title', "The finished mistery");
$book->addChild('author', 'J. F. Rutherford');
$book->addChild('publisher', 'Watchtower Society');

Con eso es suficiente para modificar el contenido XML. En la primera línea estamos agregando un nuevo hijo llamado book al elemento raíz que es library, como SimpleXMLElement siempre nos regresa un objeto del mismo tipo, entonces a la variable $book también podemos aplicarle el metodo addChild() para crearle hijos, (que vendrían siendo los nietos de $library). Es como una especie de recursividad, donde podemos ir creando elementos en varios niveles, paras obtener hijos, nietos, bisnietos etc.

Ahora bien, hasta este punto no podemos ver cómo ha quedado nuestro documento XML. Lo siguiente será mostrarlo en el navegador. Para ello, debemos enviar una cabecera para indicar al navegador que el contenido a mostrar no es simple texto ni HTML, sino XML y después hacer la impresión del mismo.

header('Content-type: text/xml');
echo $library->asXML();

¿Para que sirve el método asXML()? regresa el contenido XML del objeto como una cadena, pero solo si lo llamamos sin argumentos. La otra opción, que sin duda es la qué podria darnos mas usabilidad es llamarlo con un parametro que contendría una ruta a un archivo, el cual se escribirá con el contenido XML del objeto. El método asXML($string) regresará un valor de tipo boolean dependiendo del resultado de la operación.

¿Cómo escribir entonces un archivo XML? Supongamos que, una vez agregado el nuevo libro a nuestro archivo de libros queremos guardar los cambios. Lo único que habría que hacer es:

$library->asXML('library.xml');

Y listo, si escribimos el nombre de un archivo que no existe, se crea automaticamente y si ya existe se sobrescribe.

¿Cómo eliminar ahora elementos y atributos de un documento XML?

SimpleXMLElement, no provee ningun metodo para hacerlo, sin embargo sí hay una forma de eliminar hijos. Supongamos que quiero eliminar el libro que acabo de agregar. Como es el elemento book número 6, solo hay que destruir el objeto que pertenece a ese hijo:

$library->book[5] = null;

El cinco es porque los elementos empiezan a contarse desde cero. Sin embargo, hay un inconveniente; esto solo eliminara a los hijos del elemento book y a sus respectivos atributos, pero los atributos que haya al nivel de book permaneceran ahi. Por lo que el atributo isbn seguirá existiendo. Si lo igualamos a null, solo conseguiremos vaciar su valor pero dejando intacto al atributo.

Para remover efectivamente hijos y atributos, debemos exportar el objeto SimpleXMLElement a DOM, donde las funcionalidades de PHP5 para manipular los datos se hacen más poderosas. Hablaré de ello después…

Espero que este microtutorial sea de utilidad para quien necesite manipular datos XML con PHP 5.

Escrito en Microtutoriales, PHP | 13 Comentarios

18 Noviembre 2007

Cómo acceder a los datos de XML en PHP

Por Abel

Bien, ahora si dedicaré una entrada completa al manejo de XML en PHP5. Veremos un ejemplo fácil y de paso servirá como explicación al funcionamiento de plugin que muestra la foto astronómica del día.

Lo primero de lo que hay que asegurarnos es de que el XML que vamos a parsear es válido. Esto significa que debe estar bien formado (un sólo elemento raíz, etiquetas abiertas y cerradas correctamente, anidaciones válidas, etc) y debe obedecer a un DTD. Después de segurarnos de esto, lo que sigue es trabajar sobre PHP5.

¿Por qué PHP5? por dos razones, una, nos da una orientación a objetos más eficiente que a versión 4 y, dos, nos provee de la extensión SimpleXMLElement que es con la trabajaremos el XML. ¿A caso PHP4 no tiene extensiones que hagan lo mismo? No lo sé, ni me interesa. PHP5 es mejor.

Bien, empecemos. Supongamos que tenemos un archivo XML llamado library.xml con el siguiente contenido:

<?xml version="1.0" ?>
<library>
	<book isbn="0345342968">
		<title>Fahrenheit 451</title>
		<author>R. Bradbury</author>
		<publisher>Del Rey</publisher>
	</book>
	<book isbn="0048231398">
		<title>The Silmarillion</title>
		<author>J.R.R. Tolkien</author>
		<publisher>G. Allen & Unwin</publisher>
	</book>
	<book isbn="0451524934">
		<title>1984</title>
		<author>G. Orwell</author>
		<publisher>Signet</publisher>
	</book>
	<book isbn="031219126X">
		<title>Frankenstein</title>
		<author>M. Shelley</author>
		<publisher>Bedford</publisher>
	</book>
	<book isbn="0312863551">
		<title>The Moon Is a Harsh Mistress</title>
		<author>R. A. Heinlein</author>
		<publisher>Orb</publisher>
	</book>
</library>

Y supongamos que lo que queremos hacer es una tabla con todos los libros y sus respectivos datos:

Title Author Publisher ISBN
Fahrenheit 451 R. Bradbury Del Rey 0345342968
The Silmarillion J.R.R. Tolkien G. Allen & Unwin 0048231398
1984 G. Orwell Signet 0451524934
Frankenstein M. Shelley Bedford 031219126X
The Moon Is a Harsh Mistress R. A. Heinlein Orb 0312863551

Debemos hacer una instancia de la clase SimpleXMLElement. Hay varias formas de hacerlo. Las dos primeras envuelven el uso de programación estructurada o usan funciones que solo regresan objetos SimpleXML.

// Carga una cadena XML desde un archivo...
$xmlstr = file_get_contents( 'library.xml' );
$library = simplexml_load_string( $xmlstr );

// Carga un archivo XML
$library = simplexml_load_file( 'library.xml' );

Las dos formas al final hacen lo mismo. Sin embargo en un escenario real definitivamente nos vamos por la segunda. Hay otras dos formas que implican el uso de algo más orientado a objetos:

// Carga una cadena XML desde un archivo...
$xmlstr = file_get_contents( 'library.xml' );
$library = new SimpleXMLElement( $xmlstr );

// Carga un archivo XML
$library = new SimpleXMLElement('library.xml', null, true);

Ahora sí, de las cuatro formas, recomiendo la última. El segundo argumento no tiene aplicación práctica para este ejemplo y el tercero es solo para informar al constructor que el primer parámetro es una ruta a un archivo y no una cadena XML.

Aquí viene lo interesante, el acceso a los hijos y atributos. He aquí por qué SimpleXMLElement hace magia; convierte a todos los nodos del árbol XML en atributos de clase y los atributos del XML mismo los convierte en variables a las que podemos acceder como arreglos asociativos.

Si hasta aquí todo va claro, entonces ya tenemos las bases para manipular de forma sencilla el archivo de la biblioteca para mostrar los libros en una tabla. Y nos debería quedar algo así:

echo '<table>';
echo '<tr>';
echo '<th>Title</th><th>Author</th>
       <th>Publisher</th><th>ISBN</th>';
echo '</tr>';
foreach( $library->book as $book ) {
	echo '<tr>';
	echo '<td>' . $book->title . '</td>';
	echo '<td>' . $book->author . '</td>';
	echo '<td>' . $book->publisher . '</td>';
	echo '<td>' . $book['isbn'] . ‘</td>’;
	echo ‘</tr>’;
}
echo ‘</table>’;

El problema ahora sería, ¿qué pasa si no conocemos todos los nombres de los elementos ni los atributos? SimpleXMLElement tiene la solución. Los métodos SimpleXMLElement::children() y SimpleXMLElement::attributes() así como el método recien introducido en PHP5.1.3 SimpleXMLElement::getName() nos ayudarán en gran medida.

Como bien se sobreentiende, el método children() regresa los nodos hijos de elemento actual. El método attributes() regresa los atributos del elemento actual y el método getName() el nombre del elemento actual. Todos se pueden aplicar recurrentemente dependiendo del nivel de anidación de los elementos. Es decir, si estamos en el elemento $x, y llamamos a $x->children() obtendremos a los hijos de $x, y si a uno de esos hijos le aplicamos el children() obtendremos los nietos de $x, y así sucesivamente.

De modo que, para concluir, el plugin que hice solo lee el feed, saco el nodo hijo <item> del elemento raíz que es <channel> llamándolo así:

$item = $apod->channel->item[0];

La posición cero indica que es el primer item del documento, es decir, el elemento con el cual se ha actualizado el feed. Y con ese elemento trabajo para obtener los demás datos. Por ejemplo, si la descripción es un elemento hijo de cada item, la obtengo así:

$descripcion = $apod->channel->item[0]->description;

Hasta aquí llega el microtutorial de hoy que ha servido para ver cómo parsear una cadena de XML para leerla nada más. La próxima semana escribiré cómo modificar documentos XML.

Fuente de inspiración: El manual para certificación de Zend PHP.

Escrito en Microtutoriales, PHP | 9 Comentarios

3 Octubre 2007

Cómo usar DTD's en HTML y XHTML

Por Abel

Document Type Declaration (DTD) es una definición o descripción de estructura y sintaxis de un documento XML o SGML. Su función básica es la descripción del formato de datos, para usar un formato común y mantener la consistencia entre todos los documentos que utilicen la misma DTD.

De esta forma, dichos documentos, pueden ser validados, conocen la estructura de los elementos y la descripción de los datos que trae consigo cada documento, y pueden además compartir la misma descripción y forma de validación dentro de un grupo de trabajo que usa el mismo tipo de información.

Las DTD se emplean generalmente para determinar la estructura de un documento mediante etiquetas XML o SGML. Una DTD describe:

  • Elementos: indican qué etiquetas son permitidas y el contenido de dichas etiquetas.
  • Estructura: indica el orden en que van las etiquetas en el documento.
  • Anidamiento: indica qué etiquetas van dentro de otras.

Para poder validar un documento HTML o XHTML es obligatorio establecer una definicion del tipo de documento. Esto se hace en la primera linea de código de cada página y puede tener tantos valores permitidos como versiones aprobadas por la W3C para documentos web existan.

Por extensión de uso y popularidad, las versiones más usadas actualmente para documentos HTML y XHTML son la 4.01 y 1.0 respectivamente. Veamos ahora los DTD’s asociados a cada versión:

DTD’s para HTML 4.01

HTML 4.01 Strict, no permite elementos antiguos (marquee, font, blink) que están en desuso y atributos que sirven para formatear el estilo. Se exige el uso de CSS para el diseño. La declaración de tipo de documento es:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN"
"http://www.w3.org/TR/html4/strict.dtd">

HTML 4.01 Transitional permite algunos elementos y atributos antiguos que están en desuso. La declaración de tipo de documento es:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN"
"http://www.w3.org/TR/html4/DTD/loose.dtd">

HTML 4.01 Frameset para el uso de frames (marcos). La declaración de tipo de documento es:

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Frameset//EN"
"http://www.w3.org/TR/html4/DTD/frameset.dtd">

DTD’s para XHTML 1.0

XHTML 1.0 Strict es la más estricta de las DTD disponibles: no soporta etiquetas antiguas y el código debe estar escrito correctamente. La declaración de tipo de documento es:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">

XHTML 1.0 Transitional es como XHTML Strict DTD, pero las etiquetas en desuso están permitidas. Actualmente ésta es la DTD más popular. La declaración de tipo de documento es:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

XHTML 1.0 Frameset es la única DTD XHTML que soporta Frameset. La declaración de tipo de documento es:

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Frameset//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-frameset.dtd">

Así que cuando querramos hacer que nuestro sitio web valide, lo más recomendable es apegarnos a un DTD y aplicar todas las especificaciones. Este es el primer paso para formar parte del mundo web estandarizado.

Escrito en Microtutoriales | Deja un comentario

23 Julio 2007

Manejo de errores en PHP

Por Abel

Si lo que buscabas era manejo de excepciones con try-catch, entonces no es este tu lugar. Aquí explicaré brevemente cómo manejar errores en PHP. ¿Cuál es la diferencia? Bueno, con excepciones lo que se quiere controlar es el comportamiento de nuestra aplicación validando que todo salga como se planeó por ejemplo: validar que una división nunca se haga por cero, hacer algo si falla una conexion a una base de datos entre otras. Mientras que los errores a los que nos enfocaremos aquí serán errores de parsing. Los errores de parsing pueden ser de léxico, sintácticos o semánticos.

Por ejemplo un error de léxico podría ser al escribir mal alguna sentencia de control:

$x = 1;
whle ( $x < 10 ) {
	echo $x;
	$x++;
}

El error en whle detendrá la ejecución.

Un ejemplo de error sintáctico sería cuando nos falta algo o le pusimos algo de más a nuestro código, algo de lo que el parser se quejaría.

while ( $x < 10 ) {
	echo $x
	$x++;
}

La falta del punto-y-coma provocará un error fatal.

Por último, un error de semántica se da cuando algo en el código no tiene lógica. Por ejemplo:

$x = 10;
while ( $x == 'hola' ) {
	echo $x;
	$x++;
}

No se puede comparar un entero con un string.

A veces movemos y movemos el código y sin querer dejamos “huecos” y “cosas repetidas” y al probar nuestra aplicación o simple página nos damos cuenta de que tenemos muchos errores. Si estamos en fase de desarrollo entonces esto nos va muy bien porque así podemos estar arreglando todo mientras vamos descubriendo los errores. Pero y ¿si el “trabajo” no era para nosotros sino para agluien mas?

La solución es usar la directiva de reporte de errores de PHP. Con ellas, y como desarrolladores de un sistema creado en PHP tenemos la habilidad de decidir si el usuario final puede o no ver los errores. Algunas configuraciones de los errores anteriormente mencionado se hacen en el archivo de configuración php.ini. Algunas de las funciones mas importantes son: error_reporting, display_errors y log_errors.

La función error_reporting() recibe un entero como parámetro y retorna otro entero. Los valores que recibe vienen dados en constantes predefinidas de PHP y el valor retornado es el antiguo nivel de reporte.

Por ejemplo, cuando estamos desarrollando es bueno conocer todos los errores. A veces usamos una variable sin definirla primero (PHP no se queja de ellos, pero aunque no lo creas eso produce un error de tipo E-NOTICE). Todos estos tipos de errores que por defecto no se muestran porque PHP4 y PHP5 vienen preconfigurados así:

	error_reporting( E_ALL & ~E_NOTICE );

Lo que significa que va a reportar todos menos noticias. Puedes configurarlo para que aparezcan las noticias simplemente llamando a error_repoting y mandandole como parámetro E-ALL.

	error_reporting( E_ALL );

En el registro de funciones y gestión de errores de php.net encontramos una explicación más amplia de todos los posibles valores. Ahora bien, ¿cómo ocultamos todos los errores? Simplemente poniendo un cero como parámetro:

	error_reporting( 0 );

En ambientes de producción, no es recomendable que el cliente pueda ver los errores o bugs que probablemente van a aparecer. Para ocultarlos y llevar un registro de ellos podemos establecer el reporte de errores a cero y además podemos configurar nuestro php.ini para que guarde un registro de errores al que podemos acceder más tarde y arreglarlos sin que el usuario final se dé cuenta. En el php.ini solo encenderiamos la directiva log_errors, para que qude así:

	log_errors = on;

En fín, son muchas las posibilidades, aquí solo muestro las más fáciles y comunes. Después haré un microtutorial para el manejo de excepciones en PHP, claro, orientado a objetos.

Escrito en Microtutoriales, PHP | 4 Comentarios

25 Mayo 2007

Pilas en PHP

Por Abel

Las pilas son estructuras de datos muy prácticas y que nos sirven para infinidad de aplicaciones. Dentro del desarrollo web no me ha tocado verles tanta utilidad como en aplicaciones de escritorio sin embargo las hay y en este microtutorial veremos como implementarlas en PHP.

Lo primero que hay que saber es que una pila -tanto en PHP como en Java y cualquier lenguaje- no es más que un arreglo de elementos que funciona mediante la filosofía LIFO. Entonces para usar una pila en PHP primero hay que tener un arreglo creado.

Podemos crearlo e inicializarlo o simplemente crearlo con la funcion array de esta manera.

$arreglo1 = array();
$arreglo2 = array( $dato1 , $dato 2 , $dato3 );

Bien, ya que tenemos un array las funciones que PHP nos da para manipular la pila son array_push() y array_pop() que sirven para insertar un elemento y retirar un elemento del arreglo respectivamente. Un ejemplo típico de uso de una pila es verificar si una palabra dada es palíndromo. Palíndromo es aquella palabra que leída de derecha a izquierda es igual que de izquierda a derecha.

Para hacer esto necesitamos tomar la palabra que queremos verificar. Luego hay que meter cada caracter a un arreglo y posteriormente sacar cada caracter en orden inverso a como se metieron y concatenarlo a otra cadena. Una vez vaciado el arreglo comparamos la palabra original y la cadena que creamos al vaciar el arreglo, si son iguales, la palabra es un palíndromo.

Esta sería la función PHP que comprueba si una palabra es palíndromo o no.

function es_palindromo( $word ) {
	$cadena = "";
	$pila = array();

	for ( $i = 0; $i< count( $word ); $i++ ) {
		array_push( $pila , substr($word,$i,$i+1) );
	}
	while ( count( $pila ) > 0 ) {
		$cadena .= array_pop( $pila );
	}
	return ( $word == $cadena );
}

Como se ve, array_push( $pila , $dato ) unicamente inserta en el arreglo o pila especificado el elemento dado, y es de tipo entero ya que regresa el número de elementos que contiene la pila (aunque en este caso no es necesario saberlo). array_pop( $pila ) extrae de la pila que se especifica el último elemento y lo regresa. Nótese que en el ciclo while la condición es que mientras el tamaño de la pila sea mayor a cero. Esto bien podría ser así: while (count($pila)) y ya, la diferencia es que esto consume más tiempo de ejecución ya que es más lento verificar que un elemento exista a hacer una comparación.

Ok, aqui termino, el código no lo chequé, creo que debe funcionar porque no le veo ningún error de parsing, pero equivocarse en algún código es lo más común de nosotros los programadores ademas Boltzmann lo tiene más que comprobado. Si hay errores o dudas sobre cómo implementarlo, dejen comentarios.

Escrito en Microtutoriales, PHP, Programacion | 1 Comentario

22 Mayo 2007

Variables de servidor de PHP

Por Abel

PHPCuando hacemos un sitio web utilizando tecnologías PHP a veces es necesario hacer uso de algunos datos del servidor o del cliente y dado que la naturaleza de lenguaje es de servidor entonces podemos obtener de ahí toda esa información.

¿Qué funciones de PHP podemos usar? Nos enfocaremos en una serie de variables que juntas pueden darnos acceso a información sobre nuestro servidor y sobre el cliente. La información de estas variables es atribuida por el servidor y en ningún caso nos es posible modificar sus valores directamente mediante el script. Para hacerlo es necesario influir directamente sobre la propiedad que definen.

La variable que examinaremos es $_SERVER[] que es una matriz que contiene información tal como cabeceras, rutas y ubicaciones de scripts. Las entradas de esta matriz son creadas por el servidor web.

Estas son algunos elementos de la matriz, solo destacaremos los más importantes:

$_SERVER['PHP_SELF']
// El nombre de archivo del script ejecutándose actualmente
$_SERVER['SERVER_ADDR']
//La dirección IP del servidor bajo la cual está siendo ejecutado el script actual.
$_SERVER['QUERY_STRING']
// La cadena de consulta, si existe, mediante la cual se accedió a la página.
$_SERVER['HTTP_REFERER']
// La dirección de la página que refirió al navegador a la página actual.
$_SERVER['HTTP_USER_AGENT']
// Esta es una cadena que denota el navegador que está accediendo a la página.
$_SERVER['REMOTE_ADDR']
// La dirección IP desde donde el usuario está observado la página actual.
$_SERVER['SCRIPT_NAME']
// Contiene la ruta del script actual, útil para páginas que necesitan apuntar a ellas mismas.
$_SERVER['REQUEST_URI']
// El URI que fue dado para acceder a esta página; por ejemplo, ‘/index.php?id=1′.

Todas las anteriores son cadenas, puedes ver muchas más en la clase HttpRequest y un ejemplo de uso en el archivo de pruebas de la misma clase. Repito, estas son solo las variables de servidor, aún quedan las variables de petición, las de sesiones, las de entorno, etc.

La clase HttpRequest, la consigues en EsLoMas.

Escrito en Microtutoriales, PHP, Programacion | 2 Comentarios

  • Ventana al cosmos

  • Apollo 17: Anaglifo de asientos VIP

  • Publicidad