2010-01-29 15 views
17

Estoy intentando escribir XSLT que ejecutará un for-each en los hermanos siguientes seleccionados pero se detendrá cuando se alcance otra etiqueta (h1).XSLT: Seleccione siguiente hermano hasta alcanzar una etiqueta específica

Aquí está el origen de XML:

<?xml version="1.0"?> 
<html> 
    <h1>Test</h1> 
    <p>Test: p 1</p> 
    <p>Test: p 2</p> 
    <h1>Test 2</h1> 
    <p>Test2: p 1</p> 
    <p>Test2: p 2</p> 
    <p>Test2: p 3</p> 
</html> 

aquí está el XSLT:

<?xml version="1.0"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="xml" indent="yes"/> 

    <xsl:template match="/"> 
     <content> 
      <xsl:apply-templates/> 
     </content> 
    </xsl:template> 

    <xsl:template match="h1"> 
     <section> 
      <sectionHeading> 
       <xsl:apply-templates/> 
      </sectionHeading> 
      <sectionContent> 
       <xsl:for-each select="following-sibling::p"> 
        <paragraph> 
         <xsl:value-of select="."/> 
        </paragraph> 
       </xsl:for-each> 
      </sectionContent> 
     </section> 
    </xsl:template> 

    <xsl:template match="p"/> 
</xsl:stylesheet> 

Aquí está el resultado actual:

<?xml version="1.0" encoding="UTF-8"?> 
<content> 
    <section> 
     <sectionHeading>Test</sectionHeading> 
     <sectionContent> 
      <paragraph>Test: p 1</paragraph> 
      <paragraph>Test: p 2</paragraph> 
      <paragraph>Test: p 3</paragraph> 
      <paragraph>Test2: p 1</paragraph> 
      <paragraph>Test2: p 2</paragraph> 
     </sectionContent> 
    </section> 
    <section> 
     <sectionHeading>Test 2</sectionHeading> 
     <sectionContent> 
      <paragraph>Test2: p 1</paragraph> 
      <paragraph>Test2: p 2</paragraph> 
     </sectionContent> 
    </section> 
</content> 

Aquí está el resultado esperado:

<?xml version="1.0" encoding="UTF-8"?> 
<content> 
<section> 
    <sectionHeading>Test</sectionHeading> 
    <sectionContent> 
     <paragraph>Test: p 1</paragraph> 
     <paragraph>Test: p 2</paragraph> 
     <paragraph>Test: p 3</paragraph> 
    </sectionContent> 
</section> 
<section> 
    <sectionHeading>Test 2</sectionHeading> 
    <sectionContent> 
     <paragraph>Test2: p 1</paragraph> 
     <paragraph>Test2: p 2</paragraph> 
    </sectionContent> 
</section> 
</content> 
+0

@ Tim, aunque podemos obtener una solución para XSLT yo preferiría sugerir que cambie el formato XML para

prueba

prueba: p 1

prueba: p 2

Prueba 2

Test2: p 1

Test2: p 2

Test2: p 3

Lo que tiene más sentido y es legible, también es fácil de consultar en xslt. – Ravisha

Respuesta

25

Prueba esto: (En lugar de pedir todo el de p nos preguntamos para todos h1 cuya más reciente precedente de la p es actual.)

<?xml version="1.0"?> 
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output method="xml" indent="yes"/> 

    <xsl:template match="/"> 
     <content> 
      <xsl:apply-templates/> 
     </content> 
    </xsl:template> 

    <xsl:template match="h1"> 
     <xsl:variable name="header" select="."/> 
     <section> 
      <sectionHeading> 
       <xsl:apply-templates/> 
      </sectionHeading> 
      <sectionContent> 
       <xsl:for-each select="following-sibling::p[preceding-sibling::h1[1] = $header]"> 
        <paragraph> 
         <xsl:value-of select="."/> 
        </paragraph> 
       </xsl:for-each> 
      </sectionContent> 
     </section> 
    </xsl:template> 

    <xsl:template match="p"/> 
</xsl:stylesheet> 
+0

Acabo de probar esto y está funcionando perfectamente. Muchas gracias. – Tim

+0

Si funciona, acepte la solución. –

+0

Respuesta aceptada. – Tim

4

La respuesta aceptada tiene un efecto secundario malo y es un poco mal.

Además en este post, voy a explicar la verdadera comparación de la siguiente declaración esencial y por eso se puede y se fallar.


recapitulación/analizar la situación mientras se está en la plantilla <xsl:template match="h1">:

  • nodo de contexto actual es cualquier h1 de la <xsl:template> a juego.
  • variable llamada header contiene un duplicado de mi nodo de contexto actual.

La declaración esencial que es malo/incorrecto:

following-sibling :: p [anterior-sibling :: h1 [1] = $ encabezado]

  • seleccione todos los hermanos siguientes p de mi nodo de contexto | following-sibling::p
  • filtrar estos p donde la primera (la más cercana) que precede-hermano nombrado h1"es" lo mismo que la variable $header | ...[preceding-sibling::h1[1] = $header].

!! En XSLT 1.0, la comparación de un nodo con un nodo se realizará por su valor.


Véalo en un ejemplo.Vamos a pretender el xml de entrada es como esto [<h1> contiene dos veces el mismo valor Test]:

<html> 
    <h1>Test</h1> 
    <p>Test: p 1</p> 
    <p>Test: p 2</p> 
    <h1>Test</h1> 
    <p>Test2: p 1</p> 
    <p>Test2: p 2</p> 
    <p>Test2: p 3</p> 
</html> 

Un MAL! resultado será creado:

<content> 
    <section> 
    <sectionHeading>Test</sectionHeading> 
    <sectionContent> 
     <paragraph>Test: p 1</paragraph> 
     <paragraph>Test: p 2</paragraph> 
     <paragraph>Test2: p 1</paragraph> <-- should be only in 2. section 
     <paragraph>Test2: p 2</paragraph> <-- should be only in 2. section 
     <paragraph>Test2: p 3</paragraph> <-- should be only in 2. section 
    </sectionContent> 
    </section> 
    <section> 
    <sectionHeading>Test</sectionHeading> 
    <sectionContent> 
     <paragraph>Test2: p 1</paragraph> 
     <paragraph>Test2: p 2</paragraph> 
     <paragraph>Test2: p 3</paragraph> 
    </sectionContent> 
    </section> 
</content> 

comparar correcta

.... 
<xsl:variable name="header" select="generate-id(.)"/> 
.... 
<xsl:for-each select="following-sibling::p[generate-id(preceding-sibling::h1[1]) = $header]"> 
.... 

Utilice la función generate-id() para obtener el único (al menos en el documento actual) ID de un nodo y comparar ahora nodo vs ¡nodo! Incluso si usa esta técnica con <xsl:key>, ¡tiene que usar generate-id!

+0

¿Por qué no edita la solución aceptada y agrega un comentario? –

Cuestiones relacionadas