Eliminar elementos de un XML utilizando XSLT
Introducción
XSLT (eXtensible Stylesheet Language Transformations) es un estándar de la W3C basado en XML que permite transformar un XML en un documento de otro tipo: otro XML, HTML, texto, etc. El estándar XSLT está basado en plantillas (templates) que no son más que XMLs que cumple un esquema determinado. Dentro de estos XMLs, se describe cómo transformar los diferentes elementos que componen el documento de origen, utilizando el estándar XPath para asociar los elementos del documento de origen a la salida de la transformación
Una transformación XLST está compuesta por los siguientes elementos:
- Un documento XML de origen
- Una plantilla XLST
- Un motor de procesamiento de plantillas XSLT
- Un documento resultante de la transformación
El motor toma como entrada una plantilla y un XML de origen y retorna como resultado otro documento (ver diagrama en Wikipedia).
El lenguaje de XSLT no es imperativo, las acciones a realizar se declaran en un conjunto de reglas que definen cómo actuar cuando un nodo coincide con la expresión XPath definida para esa regla. De esta forma el motor, luego de haber procesado el documento de entrada y armado una especie de árbol con esa estructura, parte del nodo raíz del XML y ejecuta las reglas que mejor apliquen para cada elemento, siendo el resultado de esta ejecución el documento de salida.
Eliminar elementos del XML
Si queremos eliminar elementos de un XML existente, podemos utilizar una plantilla XSLT para transformarlo y eliminar el contenido que no necesitemos.
Veamos el siguiente ejemplo: tenemos un XML con un conjunto de empleados, en donde cada elemento tiene un nombre (elemento compuesto), un e-mail y una relación de dependencia con otro(s) empleado(s), que puede ser como subordinado o como jefe. Queremos procesar ese XML y retornar otro XML que no contenga el apellido o información de dependencia dentro de la empresa. Además, queremos sacar a “Big Boss” de esa lista.
El XML de entrada es el siguiente:
<?xml version="1.0" encoding="UTF-8"?>
<personnel>
<person id="Big.Boss">
<name>
<family>Boss</family>
<given>Big</given>
</name>
<email>chief@email.com</email>
<link subordinates="one.worker two.worker three.worker four.worker five.worker"/>
</person>
<person id="one.worker">
<name>
<family>Worker</family>
<given>One</given>
</name>
<email>one@email.com</email>
<link manager="Big.Boss"/>
</person>
<person id="two.worker">
<name>
<family>Worker</family>
<given>Two</given>
</name>
<email>two@email.com</email>
<link manager="Big.Boss"/>
</person>
<person id="three.worker">
<name>
<family>Worker</family>
<given>Three</given>
</name>
<email>three@email.com</email>
<link manager="Big.Boss"/>
</person>
<person id="four.worker">
<name>
<family>Worker</family>
<given>Four</given>
</name>
<email>four@email.com</email>
<link manager="Big.Boss"/>
</person>
<person id="five.worker">
<name>
<family>Worker</family>
<given>Five</given>
</name>
<email>five@email.com</email>
<link manager="Big.Boss"/>
</person>
</personnel>
Una solución para el problema sería tener una plantilla XLST como la siguiente:
<?xml version="1.0" encoding="iso-8859-1" ?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <xsl:output omit-xml-declaration="yes" method="xml" media-type="xml" indent="yes"/> <xsl:strip-space elements="*"/> <xsl:template match="node()|@*"> <xsl:copy> <xsl:apply-templates select="node()|@*"/> </xsl:copy> </xsl:template> <xsl:template match="/personnel/person/name/family"/> <xsl:template match="/personnel/person/link"/> <xsl:template match="/personnel/person[@id='Big.Boss']"/> </xsl:stylesheet>
En el XLST tenemos por un lado los <xsl:template> que aplican para casos bien puntuales (cuando el nodo visitado es coincide con la expresión XPath) y actúan ignorando ese elemento sin escribirlo al documento de salida. Por otro lado está <xsl:template match=”node()|@*”>, que actúa como regla para el resto de los nodos, copiando su contenido y continuando la transformación en sus hijos.
En <xsl:output> configuramos el tipo de documento de salida, la indentación, etc. Si interesa que el XML resultante quede del menor tamaño posible, podemos eliminar la indentación (indent=”no”) y ahorrarnos alguna línea y algún tabulador.
La línea que contiene <xsl:strip-space elements=”*”/> elimina las líneas en blanco que deja la transformación en donde originalmente estaban ubicados los elementos eliminados.
El resultado de la transformación es el siguiente:
<personnel>
<person id="one.worker">
<name>
<given>One</given>
</name>
<email>one@email.com</email>
</person>
<person id="two.worker">
<name>
<given>Two</given>
</name>
<email>two@email.com</email>
</person>
<person id="three.worker">
<name>
<given>Three</given>
</name>
<email>three@email.com</email>
</person>
<person id="four.worker">
<name>
<given>Four</given>
</name>
<email>four@email.com</email>
</person>
<person id="five.worker">
<name>
<given>Five</given>
</name>
<email>five@email.com</email>
</person>
</personnel>
Conclusión
XSLT nos da una infinidad de posibilidades a la hora de transformar un XML a la salida deseada. Este es un ejemplo bastante simple, pero con 16 líneas de XLST y algunas más de código para instanciar un procesador y configurarle la transformación, cumplimos el objetivo con la posibilidad de cambiar o expandir el XML original sin afectar el documento transformado. Además tiene un plus haberlo logrado de forma eficiente y basándonos en estándares.
Referencias
http://en.wikipedia.org/wiki/XSLT
http://www.w3.org/TR/xslt
No existen posts relacionados.

Muy util.
¿Algun programa para aplicar una XSLT a varios XMLs a la vez?
Hola Tom. Para hacer una transformación a varios XMLs con el mismo XSLT puedes usar un editor XML. Uno que está muy bueno es el (http://www.oxygenxml.com/) pero es pago y el trial dura sólo 30 días. Otra opción es hacer un programita que cargue la plantilla XSLT, levante los diferentes XMLs y vaya aplicando la transformación a cada uno de ellos.
Espero haber respondido tu pregunta. Saludos,
José