Cómo modificar documentos XML con PHP
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.
Relacionados
Tags: dom, PHP, Programacion, simplexmlelement, xml
Siéntete libre de dejar tu comentario.
Comentarios
Disculpa la espera, estuve investigando eso, necesitas usar DomDocument y DomXpath, ambos son clases de PHP5. Solo permíteme un poco más para intentar dominar el tema.
Un saludo.
Bueno, esperare ya que es un tema el cual no logro comprender, te agradezco mucho tu ayuda, Gracias
Un Cordial Saludo
Buenas tardes y feliz a;o nuevo, me gustaria saber si has encontrado algo sobre el tema de mi interrogante.
Gracias
Hola! Muchas gracias.
Fijate que sí tengo un poco de documentación. Pero suficiente como para redactar un manual propio no lo creo… Sin embargo, puedo mostrarte un ejemplo pequeño de cómo modificar un elemento existente.
Como ya te habia dicho, necesitas crear una instancia de DOMDocument y pasar el objeto a DomXpath para trabajar por medio de queries… El ejemplo lo tomaré directamente de la guía de certificación de Zend.
$xml = <<<XML
<xml>
<text>some text here</text>
</xml>
XML;
$dom = new DOMDocument();
$dom->loadXML($xml);
$xpath = new DomXpath($dom);
$node = $xpath->query("//text/text()")->item(0);
$node->data = strtoupper($node->data);
echo $dom->saveXML();
Lo que hace ese script es tomar el elemento que contiene la cadena ‘text’ y poner en mayúscula su contenido. El resultado sería esto:
<?xml version="1.0"?> <xml> <text>SOME TEXT HERE</text> </xml>
He probado cosas más complejas y sigo teniendo algunos problemillas,por eso no me he animado a escribir al respecto, además de algunos pendientes importantes que tengo en el trabajo. Espero que eso te dé por lo menos una idea de cómo continuar.
Un saludo.
Vaya, Exelente ejemplo, creo que ya puedo seguir solo, gracias por tu tiempo y tu comprension, tienes un exelente web, muchas gracias.
Saludos
Buenas amigo, muxas gracias por tu tutorial, muy weno!, me sirvio de muxa ayuda!
io te dejo aki una forma k encontre para actualizar con el mismo simpleXML, dejo aki el codigo de ejemplo:
$admin = new SimpleXMLElement($xmlfile, null, true); // Carga un archivo XML
$users = $admin->xpath(‘//usuario[username="' . $nombreusuario . '"]‘);
if ($users){
$users[0]->avatar = $dire;
$admin->asXML($xmlfile);
}
eso modifica avatar dentro de mi xml,
Hola Que tal,
pero quisiera un ejemplo para modificar un nodo hijo XML desde php.
Modificar un dato existente dentro del nodo raiz.
GRACIAS DE ANTEMANO
Hola, tengo el siguiente Script para intentar agregar un nuevo nodo pero algo no me resulta:
La linea de $listaCDs=new SimpleXMLElement($userXML,null, true); me esta generando un error, solo que mi apache2triad en lugar de mostrarmelo me saca la agina en blanco. Espero y me puedan ayudar..
Perdon mi codigo era:
$relativepath=”../cds/”.$_SESSION['user'];
$userXML=$relativepath.”.xml”;
$elCD=$_POST['album'];
$elCantante=$_POST['artista'];
$elTrackList=$_POST['tracklist'];
$listaCDs=new SimpleXMLElement($userXML,null, true);
tengo este archivo xml (
Hola Caracola
KaoS
Olla Kaitos a Luisete
Nuevo articulo en desarrolloweb
Raul
Jeje hola, aqui estamos
XML;
?>)
luego de este codigo–
( noticias[0]->addChild(‘noticia’);
$noticia->addChild(‘titulo’, ‘muerte en inundaciones’);
$noticia->addChild(‘autor’, ‘lobo’);
$noticia->addChild(‘cuerpo’, ‘12 muertes por lluvias’);
//header(‘Content-type: text/xml’);
echo $xml->asXML();
?> )
me da este error–(Ha ocurrido un error al procesar el documento “” a XML )
alguien podria decirme ke debo hacer para arreglar eso ????
gracias
Hola, Bueno, yo igual me topé con algunos detalles al momento de crear XML y agregar nodos, encontré otro modo de agregar un nodo a mi archivo XML. Me funciona a la perfección.
Les comento rapidamente para que me sirvio, es para un panel de mensajes y agrego nodos por medio de un formulario.
Aqui les dejo la estructura de mi archivo xml:
/*
1
07-09-2008
PepoRuiz
Ejemplo
Este es la estructura de mi XML
1
*/
// Este es mi codigo…
//Mi archivo se llama Mensajes.xml, no olviden utilizar comilla simple en lugar de doble, les puede traer muchos dolores de cabeza.
$Archivo=’Mensajes.xml’;
// Lo siguiente lo utilizo para formatear el mensaje y asunto eliminando tildes y mas
$MensajeFix= strtr($Mensaje, “àáâãäåèéêëìíîïòóôõöùúûüñ”, “aaaaaaeeeeiiiiooooouuuun”);
$AsuntoFix= strtr($Asunto, “àáâãäåèéêëìíîïòóôõöùúûüñ”, “aaaaaaeeeeiiiiooooouuuun”);
// Los datos
$xml = simplexml_load_file($Archivo);
$xmltmp = $xml->addChild(‘msg’);
$xmltmp->addChild(‘idMensaje’, $IdMsg);
//Utilizo variables de sesion para pasar la fecha y nombre de usuario, ustedes pueden reemplazarlo con sus variables.
$xmltmp->addChild(‘Fecha’, $_SESSION['FechaHoy']);
$xmltmp->addChild(‘Emisor’, $_SESSION['NombreUsuario']);
// utilizo esta funcion “utf8_decode” por cualquier cosa extraña que pase en nuestro mensaje
$xmltmp->addChild(‘Asunto’, utf8_decode($AsuntoFix));
$xmltmp->addChild(‘Texto’, utf8_decode($MensajeFix));
$xmltmp->addChild(‘Edo’, ‘1′);
$contenido=$xml->asXML();
$gestor= fopen($Archivo, ‘w’);
fwrite($gestor, $contenido);
fclose($gestor);
unset($xml);
unset($xmltmp);
Bueno, espero que les haya servido, cualquier cosa, duda, solo agreguen un arroba a mi nick y completenlo con gmail, me envian correos para saber.. salu2
PepoRuizMx
Bueno, la estructura no me dejo ponerla y la convirtió automáticamente, aqui va nuevamente
1
hoy
PepoRuizMx
Ejemplo
ejemplo de estructura
no se les olvide cerrar las etiquetas, es el nodo y es del principal del archivo XML
Podrias decirme si la funcion utf8_decode la puedo usar para sustituir , y como podria hacerlo si almaceno mi XML en una cadena.
De antemano Gracias
Sustituir el encoding=”iso-8859-1″ por UTF8 desde php lo que pasa es k no tengo que cambiar el encoding desde php almaceno mi xml en una cadena me podrias ayudar?
Si usas la clase DOMDocument, verás que tiene una propiedad:
public string $encoding;
Solo tendrías que hacer algo así:
$dom = new DOMDocument(); $dom->encoding = 'utf-8'; $dom->loadXML( $cadena_de_xml );
Y ya, en teoría eso debe funcionar y si estoy mal que alguien me corrija porque no tengo tiempo para probar jeje.
hola, gracias por el tuto, me preguntaba si a la pieza de codigo que dolocaste para eliminar los hijos de un nodo especifico le falta aguna parte pues no funciona, este es el codigo que estoy utilizando…
comentario[0] = null;
$contenido->asXML(‘../xml/foro.xml’);
}
?>


Hola que tal, muchas gracias por el tutorial, pero tengo una interrogante aun, como puedo hacer para, en ves de agregar algo, solo modificarlo un elemento existente, ya sea, un elemento o un nodo, por ejemplo
Fahrenheit 451
R. Bradbury
Del Rey
como puedo hacer para modificar solamente el valor de isbn, modificarlo y guardar el cambio.
espero me puedas rsponder
Gracias de antemano