2011-01-25 8 views
5

hi Tengo un documento XML mapa del sitio que se ve algo como estoXSLT copia de sin hijos

<pagenode title="home" url="~/" fornavbar="true"> 
<pagenode title="admin" url="~/admin" fornavbar="false"> 
    <pagenode title="users" url="~/admin/users" fornavbar="false"/> 
    <pagenode title="events" url="~/admin/events" fornavbar="true"/> 
</pagenode> 
<pagenode title="catalog" url="~/catalog" fornavbar="true"/> 
<pagenode title="contact us" url="~/contactus" fornavbar="false"/> 
</pagenode> 

ahora quiero recuperar un documento XML para la barra de navegación, que incluye todos los pagenodes que tienen fornavbar = cierto. ¿Cómo se puede hacer esto?

lo más cerca que era capaz de conseguir hasta el momento era 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:template match="pagenode[@fornavbar='true']"> 
    <xsl:copy-of select="."/> 
</xsl:template> 
</xsl:stylesheet> 

el problema con esto es que incluye todos los hijos de nada coincidentes como barra de navegación

sólo quiero copiar todos los atributos , no todos los niños

pero si intento

<?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="pagenode[@fornavbar='true']"> 
    <pagenode title="{@title}" url="{@url}"/> 
    <xsl:apply-templates/> 
</xsl:template> 
</xsl:stylesheet> 

entonces tengo 2 problemas

  1. yo podría escribir a máquina por separado cada atributo, y tengo unos cuantos por página y ayúdales propensos a cambiar con el tiempo
  2. pierde la jerarquía. todo se vuelve plano uno tras otro

agradecería a todos y cualquier ayuda en la materia.

gracias!

EDIT: salida de la muestra que le gusta ver Identificación del

<pagenode title="home" url="~/" fornavbar="true"> 
<pagenode title="events" url="~/admin/events" fornavbar="true"/> 
<pagenode title="catalog" url="~/catalog" fornavbar="true"/> 
</pagenode> 
+0

Buena pregunta, +1. Vea mi respuesta para una solución completa pero muy corta que aprovecha al máximo el patrón de diseño XSLT más fundamental. :) –

Respuesta

2

se puede iterar sobre los atributos de un nodo mediante xsl:foreach select="@*" de esta manera usted no tiene que copiar los atributos con la mano. si llama al xsl:apply-templates dentro de su elemento pagenode, debería obtener el resultado deseado.

<?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="pagenode[@fornavbar='true']"> 
     <pagenode> 
      <xsl:for-each select="@*"> 
       <xsl:attribute name="{name(.)}"><xsl:value-of select="."/></xsl:attribute> 
      </xsl:for-each> 
      <xsl:apply-templates/> 
     </pagenode> 
    </xsl:template> 
</xsl:stylesheet> 

hace

<?xml version="1.0"?> 
<pagenode title="home" url="~/" fornavbar="true"> 
    <pagenode title="events" url="~/admin/events" fornavbar="true"/> 
    <pagenode title="catalog" url="~/catalog" fornavbar="true"/> 
</pagenode> 
+1

'' es mucho más sucinto –

+0

¡gracias un millón! ¡funciona exactamente lo que necesitaba! eres excelente! –

1

XSLT debería tener este aspecto:

<?xml version="1.0" encoding="ISO-8859-1"?> 
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0"> 
    <xsl:template match="pagenode[@fornavbar='true']"> 
    <pagenode> 
     <xsl:copy-of select="@*"/> 
     <xsl:apply-templates/> 
    </pagenode> 
    </xsl:template> 
</xsl:stylesheet> 
+0

Deben ser restos de mi prueba. – akond

+0

+1 Para la corrección más simple. –

3

Esta es probablemente la solución más corta y la más pura XSLT:

<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="*[@fornavbar = 'false']"> 
    <xsl:apply-templates/> 
</xsl:template> 
</xsl:stylesheet> 

cuando se aplica esta transformación en el documento XML proporcionado:

<pagenode title="home" url="~/" fornavbar="true"> 
    <pagenode title="admin" url="~/admin" fornavbar="false"> 
     <pagenode title="users" url="~/admin/users" fornavbar="false"/> 
     <pagenode title="events" url="~/admin/events" fornavbar="true"/> 
    </pagenode> 
    <pagenode title="catalog" url="~/catalog" fornavbar="true"/> 
    <pagenode title="contact us" url="~/contactus" fornavbar="false"/> 
</pagenode> 

se produce el resultado deseado, correcta:

<pagenode title="home" url="~/" fornavbar="true"> 
    <pagenode title="events" url="~/admin/events" fornavbar="true"/> 
    <pagenode title="catalog" url="~/catalog" fornavbar="true"/> 
</pagenode> 

Explicación:

  1. La regla de identidad (plantilla) copia cada nodo "tal cual". Usando identity rule y anulando, es el patrón de diseño XSLT más fundamental.

  2. Hay una sola plantilla que anula la regla de identidad - para los elementos cuyo atributo es fornavbar"false". Aquí la acción especificada es apply-templates en los elementos secundarios del elemento actual.

+1

+1 Buena respuesta. Solo por lógica semántica e inversa de una sola solución de reglas, usaría '* [not (self :: pagenode/@ fornavbar = 'true')]' –

+0

@Alejandro: Thanks. ¿Qué quieres decir? –

+0

Quiero decir que la regla de omisión coincidirá con cualquier elemento que tenga un atributo '@ fornavbar' con un valor de cadena' 'false'', por lo que la regla de identidad coincidirá con ** cualquier elemento ** que no tenga un atributo '@ fornavbar' con'' falso '' valor de cadena, en lugar de 'elementos' pagenode' ** solo ** que tiene un atributo '@ fornavbar' con valor de cadena' 'true''. –