3 votes

Groupement XSLT 2.0 avec <xsl:for-each-group>

J'essaie de regrouper des éléments en utilisant xsl:for-each dans XSLT 2.0.

Voici une illustration de ma contribution :

<root>
     <chapter>
           <heading> heading text </heading>
           <title> title </title>
           <p> 1111 </p>
           <p> 2222 </p>
           <center> text </center>
           <p> 3333 </p>
           <title>  another title </title>
           <p> 4444 </p>
           <center> text </center>
           <p> 5555 </p>
     </chapter>
     <chapter>
          <heading> heading text </heading>
          <title>  another title </title>
          <p> 6666 </p>
          <p> 7777 </p>
          <title>  another title </title>
          <p> 8888 </p>
          <p> 9999 </p>
     </chapter>
<root>

J'essaie de regrouper ce document en faisant correspondre sur chacun d'eux <title> et en regroupant tous les éléments suivants jusqu'à l'élément suivant. <title> en un élément <section> . Voici ce à quoi je veux que ma sortie ressemble :

<root>
     <chapter>
          <heading> Heading text </heading>
          <section>
               <title>  title </title>
               <p> 1111 </p>
               <p> 2222 </p>
               <center> text </center>
               <p> 3333 </p>
          </section>
          <section>
               <title>  title </title>
               <p> 4444 </p>
               <center> text </center>
               <p> 5555 </p>
          </section>
          <section>
               <title>  title </title>
               <p> 6666 </p>
               <p> 7777 </p>
               <center> text </center>
               <p> 8888 </p>
               <p> 9999 </p>
          </section>
     <chapter>
<root>

Mon modèle actuel qui ne fonctionne pas :

<xsl:template match="chapter">
    <chapter>
      <xsl:for-each-group select="*" group-starting-with="title">
             <section>
                <xsl:copy-of select="current-group()" />
             </section>
      </xsl:for-each-group>
    </chapter>             
</xsl:template>

La feuille de style ci-dessus regroupe les sections comme je le souhaite, mais elle regroupe également chaque section de la liste. <heading> dans son propre élément <section> pour une raison quelconque. Des suggestions ?

Merci d'avance.

4voto

Sean B. Durkin Points 7723

J'utiliserais...

<xsl:stylesheet version="2.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="/*">
  <root>
    <xsl:for-each-group select="chapter" group-by="heading">
      <chapter>
        <xsl:copy-of select="current-group()[1]/heading" />
        <xsl:for-each-group select="current-group()/(* except heading)"
                            group-starting-with="title">
          <section>
            <xsl:copy-of select="current-group()" />
          </section>
        </xsl:for-each-group>
      </chapter>
    </xsl:for-each-group>
  </root>
</xsl:template>

</xsl:stylesheet>

4voto

Michael Kay Points 52194

J'utilise généralement un xsl:choose dans le corps du for-each-group pour distinguer les groupes qui commencent réellement avec l'élément group-starting-with du "leading rump" avant le premier "vrai groupe". On vous a donné un certain nombre d'autres solutions qui fonctionnent bien si vous savez que le "groupe de tête" ne contiendra qu'un élément d'en-tête. Une autre solution plus générale (parce qu'elle ne fait pas d'hypothèses sur le contenu de la croupe), mais qui va dans le même sens, est la suivante :

<xsl:copy-of select="title[1]/preceding-sibling::*">
<xsl:for-each-group select="title[1]/(., following-sibling::*)">
  <section>
     <xsl:copy-of select="current-group()"/>
  </section>
</xsl:for-each-group>

3voto

Ian Roberts Points 59836

Vous voulez probablement

<xsl:copy-of select="current-group()" />

plutôt que value-of . Pour les titres, si vous savez que chaque chapitre n'aura qu'un seul titre heading élément alors vous pourriez dire

<xsl:template match="chapter">
      <xsl:copy-of select="heading" />
      <xsl:for-each-group select="*[not(self::heading)]" group-starting-with="title">
             <section>
                <xsl:copy-of select="current-group()" />
             </section>
      </xsl:for-each-group>             
</xsl:template>

c'est-à-dire sortir l'intitulé séparément et l'exclure ensuite de l'ensemble des éléments à regrouper.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X