2010-10-12 9 views
-1

les gars, je pense que cela est une question délicate ...Comment créer une liste html à partir du fichier xml plat en utilisant XSLT

Je cherche un moyen propre à faire l'utilisation de XSLT suivante:

Convertir cette source:

<para>blah blah</para> 
<list>num1</list> 
<list>num2</list> 
<list>num3</list> 
<para>blah blah</para> 
<list>num1</list> 
<list>num2</list> 
<para>blah blah blah blah blah</para> 

Pour cette sortie:

<p>blah blah</p> 
<ol> 
<li>num1</li> 
<li>num2</li> 
<li>num3</li> 
</ol> 
<p>blah blah</p> 
<ol> 
<li>num1</li> 
<li>num2</li> 
</ol> 
<p>blah blah blah blah blah</p> 

Gardez à l'esprit, je ne sais pas exactement comment l'homme y <list> il y aura.

Jusqu'à présent, j'ai ceci:

<xsl:template match="para"> 
<p><xsl:value-of select="." /></p> 
</xsl:template> 

<xsl:template match="list"> 
<ol><li><xsl:value-of select="." /></li></ol> 
</xsl:template> 

Mais ma sortie ressemble à ceci:

<p>blah blah</p>  
<ol><li>num1</li></ol> 
<ol><li>num2</li></ol> 
<ol><li>num3</li></ol> 
<p>blah blah</p> 
<ol><li>num1</li></ol> 
<ol><li>num2</li></ol> 
<p>blah blah blah blah blah</p> 

Je sais pourquoi je reçois en double <ol> éléments, mais je ne sais pas comment l'arrêter . Tout un casse-tête.

Toute aide serait grandement appréciée.

+2

Beaucoup, beaucoup de doublons: http://stackoverflow.com/questions/3813978/wrap-certain-nodes-with-xsl http://stackoverflow.com/questions/3776789/using-xslt-to-interpret-flat-xml -into-imbriqué-xhtml http://stackoverflow.com/questions/3831326/group-a-non-nested-xml-structure-to-a-xml-tree-structure http://stackoverflow.com/questions/3853452/grouping-of-similer-nodes –

Répondre

1

XSLT 2.0 dispose d'outils spécialement pour ce genre d'opérations:

<xsl:stylesheet version="2.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:template match="xml"> 
     <xsl:for-each-group select="*" group-adjacent="boolean(self::list)"> 
      <xsl:choose> 
       <xsl:when test="current-grouping-key()"> 
        <ol> 
         <xsl:apply-templates select="current-group()"/> 
        </ol> 
       </xsl:when> 
       <xsl:otherwise> 
        <xsl:apply-templates select="current-group()"/> 
       </xsl:otherwise> 
      </xsl:choose> 
     </xsl:for-each-group> 
    </xsl:template> 
    <xsl:template match="para"> 
     <p> 
      <xsl:apply-templates/> 
     </p> 
    </xsl:template> 
    <xsl:template match="list"> 
     <li> 
      <xsl:apply-templates/> 
     </li> 
    </xsl:template> 
</xsl:stylesheet> 

Avec ce XML:

<xml> 
    <para>blah blah</para> 
    <list>num1</list> 
    <list>num2</list> 
    <list>num3</list> 
    <para>blah blah</para> 
    <list>num1</list> 
    <list>num2</list> 
    <para>blah blah blah blah blah</para> 
</xml> 

Vous obtiendrez la sortie désirée:

<p>blah blah</p> 
<ol> 
    <li>num1</li> 
    <li>num2</li> 
    <li>num3</li> 
</ol> 
<p>blah blah</p> 
<ol> 
    <li>num1</li> 
    <li>num2</li> 
</ol> 
<p>blah blah blah blah blah</p> 

Vous devriez lire sur pour chaque groupe à http://www.w3.org/TR/xslt20/#xsl-for-each-group

+0

Merci! Cela ressemble à un excellent moyen de le faire. – joe

+0

+1 bonne réponse. Mais je pense que ce n'est pas bon d'utiliser de telles règles de modèle "brique". –

0

Cette transformation:

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

<xsl:key name="kFollowing" match="list" 
    use="generate-id(preceding-sibling::para[1])"/> 

<xsl:template match="node()|@*" name="identity"> 
    <xsl:copy> 
    <xsl:apply-templates select="node()|@*"/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="para"> 
    <p> 
    <xsl:apply-templates/> 
    </p> 
    <xsl:variable name="vFol" 
    select="key('kFollowing',generate-id())"/> 
    <xsl:if test="$vFol"> 
     <ol> 
     <xsl:apply-templates mode="copy" 
      select="key('kFollowing',generate-id())"/> 
     </ol> 
    </xsl:if> 
</xsl:template> 

<xsl:template match="list" mode="copy"> 
    <li><xsl:value-of select="."/></li> 
</xsl:template> 
<xsl:template match="list"/> 
</xsl:stylesheet> 

lorsqu'il est appliqué sur le document XML suivant (enveloppant l'entrée fournie en un seul élément supérieur):

<t> 
    <para>blah blah</para> 
    <list>num1</list> 
    <list>num2</list> 
    <list>num3</list> 
    <para>blah blah</para> 
    <list>num1</list> 
    <list>num2</list> 
    <para>blah blah blah blah blah</para> 
</t> 

produit le désiré, correct résultat:

<t> 
    <p>blah blah</p> 
    <ol> 
     <li>num1</li> 
     <li>num2</li> 
     <li>num3</li> 
    </ol> 
    <p>blah blah</p> 
    <ol> 
     <li>num1</li> 
     <li>num2</li> 
    </ol> 
    <p>blah blah blah blah blah</p> 
</t> 

UPDATE: L'OP a indiqué dans un commentaire que maintenant il veut une solution où tout élément non list peut délimiter un groupe de list adjacents frères et sœurs.

Voici la solution à la question modifiée:

<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:key name="kFollowing" match="list" 
    use="generate-id(preceding-sibling::*[not(self::list)][1])"/> 

<xsl:template match="node()|@*" name="identity"> 
    <xsl:copy> 
    <xsl:apply-templates select="node()|@*"/> 
    </xsl:copy> 
</xsl:template> 

<xsl:template match="*[not(self::list) and following-sibling::*[1][self::list]]"> 
    <xsl:call-template name="identity"/> 
    <xsl:variable name="vFol" 
    select="key('kFollowing',generate-id())"/> 
    <xsl:if test="$vFol"> 
     <ol> 
     <xsl:apply-templates mode="copy" 
      select="key('kFollowing',generate-id())"/> 
     </ol> 
    </xsl:if> 
</xsl:template> 

<xsl:template match="list" mode="copy"> 
    <li><xsl:value-of select="."/></li> 
</xsl:template> 
<xsl:template match="list"/> 
</xsl:stylesheet> 

Lorsque cette transformation est appliquée sur le document XML suivant (Notez que les éléments de séparation ont des noms maintenant au hasard):

<t> 
    <bara>blah blah</bara> 
    <list>num1</list> 
    <list>num2</list> 
    <list>num3</list> 
    <vara>blah blah</vara> 
    <list>num1</list> 
    <list>num2</list> 
    <dara>blah blah blah blah blah</dara> 
</t> 

le résultat désiré, correct est produit:

<t> 
    <bara>blah blah</bara> 
    <ol> 
     <li>num1</li> 
     <li>num2</li> 
     <li>num3</li> 
    </ol> 
    <vara>blah blah</vara> 
    <ol> 
     <li>num1</li> 
     <li>num2</li> 
    </ol> 
    <dara>blah blah blah blah blah</dara> 
</t> 
2

Ce XSLT 1.0 stylesheet:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:template match="node()"> 
     <xsl:apply-templates select="node()[1]|following-sibling::node()[1]"/> 
    </xsl:template> 
    <xsl:template match="para"> 
     <p> 
      <xsl:value-of select="."/> 
     </p> 
     <xsl:apply-templates select="following-sibling::node()[1]"/> 
    </xsl:template> 
    <xsl:template match="list[preceding-sibling::node()[1][not(self::list)]]"> 
     <ol> 
      <xsl:call-template name="makeList"/> 
     </ol> 
     <xsl:apply-templates select="following-sibling::node() 
               [not(self::list)][1]"/> 
    </xsl:template> 
    <xsl:template match="list" name="makeList"> 
     <li> 
      <xsl:value-of select="."/> 
     </li> 
     <xsl:apply-templates select="following-sibling::node()[1] 
               [self::list]"/> 
    </xsl:template> 
</xsl:stylesheet> 

Sortie:

<p>blah blah</p> 
<ol> 
     <li>num1</li> 
     <li>num2</li> 
     <li>num3</li> 
</ol> 
<p>blah blah</p> 
<ol> 
     <li>num1</li> 
     <li>num2</li> 
</ol> 
<p>blah blah blah blah blah</p> 

Note: traversal à grains fins.

Édition: Code compact.

+0

Merci pour l'aide c'est une approche possible. Mais cette approche n'est-elle pas difficile à maintenir? Parce que je vais devoir ajouter le suivant-frère sélectionner sur chaque élément de haut niveau sur lequel je fais correspondre. – joe

+0

@joe: Cette feuille de style a quatre règles: une traversée à grain fin par défaut, une règle pour 'p', une règle pour' ol' et une règle pour 'li'. Donc, c'est une transformation en un à un. Je ne vois pas le problème * difficile à maintenir *. Vous avez demandé à Dimitre: * que faire si j'ai un élément H1 avant la liste *. Eh bien, vous devez déclarer waht à faire avec «H1» alors. Maintenant, c'est contourné. Donc, deux solutions: copier tout ce que vous ne voulez pas transformer ou ajouter une règle pour 'H1'. –

+0

Ce que je veux dire, c'est si j'ajoute

. Je devrai mettre dans le match aussi. – joe

Questions connexes