La transformación de identidad es una transformación de datos que copia los datos de origen en los datos de destino sin modificarlos.
La transformación de identidad se considera un proceso esencial para crear una biblioteca de transformaciones reutilizable . Al crear una biblioteca con variaciones de la transformación de identidad base, se puede mantener fácilmente una variedad de filtros de transformación de datos . Estos filtros se pueden encadenar en un formato similar a las tuberías de la shell de UNIX .
Ejemplos de transformaciones recursivas
La técnica de "copia con recursión" permite, modificando pequeñas porciones de código, generar una salida completamente nueva y diferente, filtrando o actualizando la entrada. Al comprender la "identidad por recursión", podemos entender los filtros.
Usando XSLT
El ejemplo más citado de la transformación de identidad (para XSLT versión 1.0) es la transformación "copy.xsl" tal como se expresa en XSLT . Esta transformación utiliza el comando xsl:copy [ 1 ] para realizar la transformación de identidad:
<xsl:stylesheet version= "1.0" xmlns:xsl= "http://www.w3.org/1999/XSL/Transform" > <xsl:template match= "@*|node()" > <xsl:copy> <xsl:apply-templates select= "@*|node()" /> </xsl:copy> </xsl:template> </xsl:stylesheet>Esta plantilla funciona haciendo coincidir todos los atributos ( @* ) y otros nodos ( node() ), copiando cada nodo coincidente y luego aplicando la transformación de identidad a todos los atributos y nodos hijos del nodo de contexto. Esto recorre recursivamente el árbol de elementos y genera todas las estructuras con la misma estructura en la que se encontraron en el archivo original, dentro de las limitaciones de la información considerada significativa en el modelo de datos XPath . Dado que node() coincide con texto, instrucciones de procesamiento, raíz y comentarios, así como con elementos, se copian todos los nodos XML.
Una versión más explícita de la transformación identidad es:
<xsl:stylesheet version= "1.0" xmlns:xsl= "http://www.w3.org/1999/XSL/Transform" > <xsl:template match= "@*|*|processing-instruction()|comment()" > <xsl:copy> <xsl:apply-templates select= "*|@*|text()|processing-instruction()|comment()" /> </xsl:copy> </xsl:template> </xsl:stylesheet>Esta versión es equivalente a la primera, pero enumera explícitamente los tipos de nodos XML que copiará. Ambas versiones copian datos innecesarios para la mayoría de los usos de XML (por ejemplo, comentarios).
XSLT 3.0
XSLT 3.0 [ 2 ] especifica un atributo on-no-match de la xsl:modeinstrucción que permite declarar la transformación de identidad en lugar de implementarla como una regla de plantilla explícita. Específicamente:
<xsl:stylesheet version= "3.0" xmlns:xsl= "http://www.w3.org/1999/XSL/Transform" > <xsl:mode on-no-match= "shallow-copy" /> </xsl:stylesheet>es esencialmente equivalente a las reglas de plantilla anteriores. Consulte la descripción de la copia superficial del estándar XSLT 3.0 [ 3 ] para obtener más detalles.
Finalmente, tenga en cuenta que los detalles de marcado, como el uso de secciones CDATA o el orden de los atributos, no necesariamente se conservan en la salida, ya que esta información no forma parte del modelo de datos XPath . Para mostrar el marcado CDATA en la salida, la hoja de estilo XSLT que contiene la plantilla de transformación de identidad ( no la plantilla de transformación de identidad en sí) debe utilizar el xsl:outputatributo llamado cdata-section-elements.
cdata-section-elementsespecifica una lista de los nombres de los elementos cuyos nodos de texto secundarios deben generarse utilizando secciones CDATA. [ 1 ] Por ejemplo:
<xsl:output method= "xml" encoding= "utf-8" cdata-section-elements= "element-name-1 element-name-2" />Uso de XQuery
XQuery permite definir funciones recursivas. El siguiente ejemplo de función XQuery copia la entrada directamente a la salida sin modificarla.
declare function local:copy ( $ element as element ()) { element { node-name ( $ element )} { $ element / @* , for $ child in $ element / node () return if ( $ child instance of element ()) then local:copy ( $ child ) else $ child } };La misma función también se puede lograr utilizando una transformación de tipo typeswitch.
Versión de xquery "1.0" ;(: copia la entrada a la salida sin modificaciones :) declare function local:copy ( $ input as item () * ) as item () * { for $ node in $ input return typeswitch ( $ node ) case document-node () return document { local:copy ( $ node / node ()) } case element () return element { name ( $ node )} {(: muestra cada atributo en este elemento :) para $ att en $ nodo / @* devuelve atributo { nombre ( $ att )} { $ att } , (: muestra todos los subelementos de este elemento recursivamente :) para $ hijo en $ nodo devuelve local:copy ( $ hijo / nodo ())} (: de lo contrario, pásalo. Se usa para text(), comentarios e PI :) valor predeterminado devuelve $ nodo };En ocasiones, la transformación typeswitch es preferible, ya que se puede modificar fácilmente simplemente añadiendo una sentencia case para cualquier elemento que necesite un procesamiento especial.
Transformaciones no recursivas
Dos transformaciones sencillas e ilustrativas de "copiar todo".
Usando XSLT
<xsl:stylesheet version= "1.0" xmlns:xsl= "http://www.w3.org/1999/XSL/Transform" > <xsl:template match= "/" > <xsl:copy-of select= "." /> </xsl:template> </xsl:stylesheet>Usando XProc
<p:pipeline name= "pipeline" xmlns:p= "http://www.w3.org/ns/xproc" > <p:identity/> </p:pipeline>Cabe destacar que, con respecto a la identidad XProc , es importante tener en cuenta que puede tomar como entrada un solo documento, como en este ejemplo, o una secuencia de documentos.
Ejemplos más complejos
Generalmente, la transformación identidad se utiliza como base sobre la cual se pueden realizar modificaciones locales.
Eliminar transformación de elemento con nombre
Usando XSLT
La transformación de identidad se puede modificar para copiar todo de un árbol de entrada a un árbol de salida, excepto un nodo determinado. Por ejemplo, lo siguiente copiará todo de la entrada a la salida, excepto el número de seguro social:
<xsl:template match= "@*|node()" > <xsl:copy> <xsl:apply-templates select= "@*|node()" /> </xsl:copy> </xsl:template><!-- eliminar todos los números de seguro social --> <xsl:template match= "PersonSSNID" />Uso de XQuery
declare function local:copy-filter-elements ( $ element as element (), $ element-name as xs:string * ) as element () { element { node-name ( $ element ) } { $ element / @* , for $ child in $ element / node ()[ not ( name (.) = $ element-name )] return if ( $ child instance of element ()) then local:copy-filter-elements ( $ child , $ element-name ) else $ child } };Llamar a este uno añadiría:
$ filtered-output := local:copy-filter-elements ( $ input , 'PersonSSNID' )Usando XProc
<p:pipeline name= "pipeline" xmlns:p= "http://www.w3.org/ns/xproc" > <p:identity/> <p:delete match= "PersonSSNID" /> </p:pipeline>Véase también
Lecturas adicionales
- Libro de cocina XSLT , O'Reilly Media, Inc., 1 de diciembre de 2002, por Sal Mangano, ISBN 0-596-00372-2
- Priscilla Walmsley, XQuery , O'Reilly Media, Inc., Capítulo 8 Funciones – Funciones recursivas – página 109