2011-08-01 14 views
5

Soy un programador experimentado, pero un principiante con XSLT y lo encuentro bastante desconcertante. Me disculpo si esta es una pregunta que se ha hecho antes, pero estoy tan frustrado con XSLT que ni siquiera estoy seguro de qué buscar ...seleccionando uno de varios elementos que difieren en el atributo

Tengo un problema que si un determinado elemento XML aparece solo una vez, quiero que se emita su contenido, pero si ocurre más de una vez, solo quiero el contenido de aquellos que tienen cierto atributo.

Por ejemplo, supongamos que tengo un archivo XML (lo llaman "archivo 1") que contiene

<food> 
    <snack>Chips</snack> 
    <snack type="nuts">Peanuts</snack> 
</food> 

y otro archivo XML ("archivo 2") que contiene

<food> 
    <snack>Cheese puffs</snack> 
</food> 

I Necesito un XSLT que muestre solo "Cacahuetes" (pero no "Chips") al procesar el archivo 1, pero sigue produciendo "Chispas de queso" para el archivo 2 (es decir, no puedo seleccionar solo aquellos elementos que tienen un atributo "tipo", Eso sería demasiado fácil).

Ésta es probablemente simple, pero estoy atascado ...

+0

Buena pregunta, +1. Vea mi respuesta para una solución completa, breve y fácil basada en los patrones de diseño XSLT más fundamentales y potentes: la anulación de la regla de identidad. Explicación también se proporciona. –

Respuesta

1

Esta transformación:

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

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

<xsl:template match= 
    "*[snack/@type]/snack[not(@type)]"/> 
</xsl:stylesheet> 

produce los resultados deseados en ambos casos.

Explicación:

  1. La regla de identidad/copias de la plantilla cada nodo "tal cual".

  2. La segunda plantilla es reemplazar la plantilla de identidad para cualquier elemento snack sin un atributo type que ha de hermanos snack elementos que tienen un atributo type. Esta plantilla tiene un cuerpo vacío, que efectivamente "elimina" el elemento coincidente de (se está copiando) el resultado.

+0

¡Brillante! ¡Funciona genial! Gracias. Nunca en mis más alocadas imaginaciones habría pensado en resolver el problema con 2 plantillas: una que hace casi lo contrario de lo que quiero, y la otra que literalmente no hace nada. ¿Por qué los modismos XSLT tienen que ser tan contra-intuitivos :-) – NumerousHats

0

si un determinado elemento XML aparece sólo una vez, quiero su salida contenidos, pero si ocurre más de una vez, quiero sólo el contenido de aquellas que tienen un determinado atributo.

una traducción directa de que sería

if (count(snack) = 1) then snack else snack[@type='nuts'] 

que es XPath válida sintaxis 2.0 - si es necesario hacerlo en 1,0 entonces se traduce de manera bastante directa (aunque más detallados) en un XSL equivalente: elegir .

Si quieres algo aún más concisa que la anterior, también puede escribir en XPath 2,0

(snack[@type='nuts'], snack)[1] 

que construye una lista que contiene en primer lugar los bocadillos con type = 'nueces', entonces todos los aperitivos, y luego selecciona el primer elemento de esta lista.

Cuestiones relacionadas