2011-04-26 21 views
6

Tengo una cantidad de archivos XML que contienen muchos sobrecargas. Deseo mantener solo unos 20 elementos específicos y filtrar cualquier otra cosa. Conozco todos los nombres de los elementos que quiero conservar, también sé si son elementos secundarios y quiénes son sus padres. Estos elementos que deseo conservar después de la transformación aún deben tener su ubicación jerárquica original.XSLT - Cómo mantener solo los elementos necesarios de XML

E.g. Quiero mantener sólo

<ns:currency>

en;

<ns:stuff> 
<ns:things> 
    <ns:currency>somecurrency</ns:currency> 
    <ns:currency_code/> 
    <ns:currency_code2/> 
    <ns:currency_code3/> 
    <ns:currency_code4/> 
</ns:things> 
</ns:stuff> 

Y que se vea así;

<ns:stuff> 
<ns:things> 
    <ns:currency>somecurrency</ns:currency> 
</ns:things> 
</ns:stuff> 

¿Cuál sería la mejor manera de construir un XSLT para lograr esto?

+1

duplicado posible de [Cómo eliminar elementos de XML mediante XSLT con la hoja de estilo y xsltproc?] (Http://stackoverflow.com/questions/321860/how-to-remove-elements-from-xml-using -xslt-with-stylesheet-and-xsltproc) – MarcoS

+0

En ese ejemplo usted especifica qué elementos omitir, necesito especificar los elementos para dejar y filtrar cualquier otra cosa. – cc0

+0

Estoy de acuerdo con MarcoS. Es un duplicado La respuesta aceptada es más o menos lo que necesita –

Respuesta

12

Esta transformación general:

<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
xmlns:ns="some:ns"> 
<xsl:output omit-xml-declaration="yes" indent="yes"/> 
<xsl:strip-space elements="*"/> 

<ns:WhiteList> 
    <name>ns:currency</name> 
    <name>ns:currency_code3</name> 
</ns:WhiteList> 

<xsl:template match="node()|@*"> 
    <xsl:copy> 
     <xsl:apply-templates select="node()|@*"/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match= 
    "*[not(descendant-or-self::*[name()=document('')/*/ns:WhiteList/*])]"/> 
</xsl:stylesheet> 

cuando se aplica en el documento XML proporcionado (con la definición de espacio de nombres agregado para hacerlo bien formado):

<ns:stuff xmlns:ns="some:ns"> 
    <ns:things> 
     <ns:currency>somecurrency</ns:currency> 
     <ns:currency_code/> 
     <ns:currency_code2/> 
     <ns:currency_code3/> 
     <ns:currency_code4/> 
    </ns:things> 
</ns:stuff> 

produce el resultado deseado (elementos de la lista blanca y sus relaciones estructurales se conservan):

<ns:stuff xmlns:ns="some:ns"> 
    <ns:things> 
     <ns:currency>somecurrency</ns:currency> 
     <ns:currency_code3/> 
    </ns:things> 
</ns:stuff> 

Explicación:

  1. La regla de identidad/copias de molde todos los nodos "tal cual ".

  2. La hoja de estilo contiene un elemento de nivel superior <ns:WhiteList> cuyos hijos <name> especificar nombres de todos los elementos de una lista blanca - los elementos que van a ser conservados con sus relaciones estructurales en el documento.

  3. El elemento <ns:WhiteList> es la mejor mantenida en un documento separado de manera que no tendrá que ser editado con nuevos nombres de la hoja de estilo actual. Aquí la lista blanca está en la misma hoja de estilo solo por conveniencia.

  4. Una sola plantilla está anulando la plantilla de identidad. No procesa (elimina) ningún elemento que no esté en la lista blanca y no tiene ningún descendiente que esté en la lista blanca.

+0

¿Qué 'nodo() | @ *' coincide exactamente? – snoofkin

+2

@ soulSurfer2010: cada 'nodo()' (elemento, texto, instrucción de procesamiento de comentarios) y cada atributo. –

+0

+1 Mejor semántica. Aunque también se debería probar el URI del espacio de nombres, y para esta pregunta bastaría un '' [[descendiente-o-uno :: ns: divisa)] 'más simple. –

4

En XSLT por lo general no elimina los elementos que desee a la baja, pero se copian los elementos que desea mantener:

<?xml version="1.0" encoding="UTF-8"?> 
<xsl:stylesheet 
    xmlns:xsl="http://www.w3.org/1999/XSL/Transform" 
    xmlns:ns="http://www.example.com/ns#" 
    version="1.0"> 

    <xsl:output method="xml" indent="yes" omit-xml-declaration="no"/> 

    <xsl:template match="/ns:stuff"> 
     <xsl:copy> 
      <xsl:apply-templates select="ns:things"/> 
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="ns:things"> 
     <xsl:copy> 
      <xsl:apply-templates select="ns:currency"/> 
      <xsl:apply-templates select="ns:currency_code3"/>     
     </xsl:copy> 
    </xsl:template> 

    <xsl:template match="ns:currency"> 
     <xsl:copy-of select="."/> 
    </xsl:template> 

    <xsl:template match="ns:currency_code3"> 
     <xsl:copy-of select="."/> 
    </xsl:template> 

</xsl:stylesheet> 

El ejemplo anterior sólo copias currency y currency_code3. La salida es la siguiente:

<?xml version="1.0" encoding="UTF-8"?> 
<ns:stuff xmlns:ns="http://www.example.com/ns#"> 
    <ns:things> 
     <ns:currency>somecurrency</ns:currency> 
     <ns:currency_code3/> 
    </ns:things> 
</ns:stuff> 

Nota: He añadido una declaración de espacio de nombres para su prefijo ns.

Si desea copiar todo excepto unos pocos elementos, es posible que vea este answer

+0

Perfecto, gracias! – cc0

+0

Puede que le interese ver una solución más general, incluida en mi respuesta. –

+0

-1 Esto no produce la salida deseada. –

Cuestiones relacionadas