2010-01-29 19 views
17

Sto tentando di scrivere XSLT che eseguirà una for-one sui seguenti siblings seguenti ma si fermerà quando viene raggiunto un altro tag (h1).XSLT: selezionare sibling successivo fino a raggiungere un tag specificato

Ecco il XML Fonte:

<?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> 

Ecco il 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> 

Ecco il risultato corrente:

<?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> 

Ecco il risultato atteso:

<?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, anche se siamo in grado di ottenere una soluzione per XSLT avrei preferito suggerire di modificare il formato XML per

prova

test: p 1

prova: p 2

test 2

Test2: P 1

Test2: p 2

Test2: p 3

Che ha più senso ed è leggibile, è anche facile eseguire una query in xslt. – Ravisha

risposta

25

Prova questo: (Invece di chiedere per tutto il p del chiediamo per tutti h1 il cui più recente precedente del p è in corso.)

<?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

Appena provato questo e funziona perfettamente. Grazie mille. – Tim

+0

Se funziona, accetta la soluzione. –

+0

Risposta accettata. – Tim

4

La risposta accettata ha un effetto collaterale male ed è un pò male.

Inoltre in questo post, vi spiegherò il vero confronto della seguente dichiarazione essenziale e perché può e sarà fallire.


riassunto/analizzare la situazione pur essendo in template <xsl:template match="h1">:

  • attuale nodo del contesto è un qualsiasi h1 dalla corrispondenza <xsl:template>.
  • variabile denominata header contiene un duplicato del mio nodo di contesto corrente.

L'affermazione essenziale che è male/male:

seguente-sibling :: p [preceding-sibling :: h1 [1] = $ intestazione]

  • select tutti i seguenti fratelli p del mio nodo di contesto | following-sibling::p
  • filtro questi p dove il primo (il più vicino) che precede, fratello di nome h1"è" la stessa variabile $header | ...[preceding-sibling::h1[1] = $header].

!! In XSLT 1.0 il confronto di un nodo con un nodo sarà fatto dal suo valore !!


Vedere in un esempio.Consente di fingere l'XML di input è come questo [<h1> contiene due volte lo stesso valore 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 SBAGLIATO! verrà creato risultato:

<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> 

corretta confrontare

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

Utilizzare la funzione generate-id() per ottenere l'unico (almeno nel documento corrente) ID di un nodo e confrontare ora il nodo vs nodo! Anche se usi questa tecnica con <xsl:key>, devi usare generate-id!

+0

Perché non basta modificare la soluzione accettata e aggiungere un commento? –

Problemi correlati