2009-11-24 11 views
17

Aquí está la muestra de datos:Expresión de XPath para seleccionar todos los nodos secundarios XML excepto una lista específica?

<catalog> 
    <cd> 
     <title>Empire Burlesque</title> 
     <artist>Bob Dylan</artist> 
     <country>USA</country> 
       <customField1>Whatever</customField1> 
       <customField2>Whatever</customField2> 
       <customField3>Whatever</customField3> 
     <company>Columbia</company> 
     <price>10.90</price> 
     <year>1985</year> 
    </cd> 
    <cd> 
     <title>Hide your heart</title> 
     <artist>Bonnie Tyler</artist> 
     <country>UK</country> 
       <customField1>Whatever</customField1> 
       <customField2>Whatever</customField2> 
     <company>CBS Records</company> 
     <price>9.90</price> 
     <year>1988</year> 
    </cd> 
    <cd> 
     <title>Greatest Hits</title> 
     <artist>Dolly Parton</artist> 
     <country>USA</country> 
       <customField1>Whatever</customField1> 
     <company>RCA</company> 
     <price>9.90</price> 
     <year>1982</year> 
    </cd> 
</catalog> 

decir que quiero para seleccionar todo excepto los elementos de precio y año. Esperaría escribir algo como el siguiente, que obviamente no funciona.

<?xml version="1.0" encoding="ISO-8859-1"?> 
<xsl:stylesheet version="1.0" 
xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 

<xsl:template match="/"> 
    <html> 
    <body> 
    <xsl:for-each select="//cd/* except (//cd/price|//cd/year)"> 
    Current node: <xsl:value-of select="current()"/> 
    <br /> 
    </xsl:for-each> 
    </body> 
    </html> 
</xsl:template> 
</xsl:stylesheet> 

Ayúdeme a encontrar la manera de excluir ciertos elementos secundarios.

Respuesta

37
<xsl:for-each select="//cd/*[not(self::price or self::year)]"> 

Pero en realidad esto es malo e innecesariamente complicado. Mejor:

<xsl:template match="catalog"> 
    <html> 
    <body> 
     <xsl:apply-templates select="cd/*" /> 
    </body> 
    </html> 
</xsl:template> 

<!-- this is an empty template to mute any unwanted elements --> 
<xsl:template match="cd/price | cd/year" /> 

<!-- this is to output wanted elements --> 
<xsl:template match="cd/*"> 
    <xsl:text>Current node: </xsl:text> 
    <xsl:value-of select="."/> 
    <br /> 
</xsl:template> 

Evite <xsl:for-each>. Casi todo el tiempo es una herramienta incorrecta y debe ser sustituido por <xsl:apply-templates> y <xsl:template>.

Lo anterior funciona debido a la especificidad de expresión de coincidencia. match="cd/price | cd/year" es más específico que match="cd/*", por lo que es la plantilla preferida para los elementos cd/price o cd/year. No intente excluir nodos, déjelos venir y manipúlelos descartándolos.

+2

Gracias por la explicación. –

9

me gustaría empezar a experimentar con algo así como

"//cd/*[(name() != 'price') and (name() != 'year')]" 

O simplemente hacer comparación de plantillas normales recursiva con <xsl:apply-templates/>, y luego tener plantillas vacías para <price/> y <year/> elementos:

<xsl:template match="price"/> 
<xsl:template match="year"/> 
Cuestiones relacionadas