2010-10-28 4 views
2

En essayant de convertir un document en texte brut en document html en utilisant xslt, je suis aux prises avec des listes non ordonnées.Conversion de texte brut en listes de style html en utilisant xstl, ou regroupement d'éléments en fonction de leur contenu et de leur position en utilisant xslt

J'ai:

<item>some text</item> 
<item>- a list item</item> 
<item>- another list item</item> 
<item>more plain text</item> 
<item>more and more plain text</item> 
<item>- yet another list item</item> 
<item>even more plain text</item> 

Ce que je veux:

<p>some text</p> 
<ul> 
    <li>a list item</li> 
    <li>another list item</li> 
</ul> 
<p>more plain text</p> 
<p>more and more plain text</p> 
<ul> 
    <li>yet another list item</li> 
</ul> 
<p>even more plain text</p> 

Je regardais le Muenchian groupant mais il combinerait tous les éléments de la liste dans un groupe et tous les éléments de texte brut dans une autre . Ensuite, j'ai essayé de ne sélectionner que les éléments dont le premier élément précédent est différent de son premier caractère. Mais quand j'essaie de tout combiner, je reçois tout le li dans un ul.

Avez-vous des conseils pour moi?

+0

Bonne question, +1. Voir ma réponse pour une solution complète et efficace. –

Répondre

2

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:strip-space elements="*"/> 

<xsl:key name="kFollowing" 
    match="item[contains(., 'list')] 
      [preceding-sibling::item[1][contains(.,'list')]]" 
    use="generate-id(preceding-sibling::item 
         [not(contains(.,'list'))] 
         [1] 
         /following-sibling::item[1] 
        )"/> 

<xsl:template match="item[contains(.,'list')] 
       [preceding-sibling::item[1][not(contains(.,'list'))]]"> 

    <ul> 
    <xsl:apply-templates mode="list" 
     select=".|key('kFollowing',generate-id())"/> 
    </ul> 
</xsl:template> 

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

<xsl:template match="item[not(contains(.,'list'))]"> 
    <p><xsl:value-of select="."/></p> 
</xsl:template> 

<xsl:template match="item[contains(.,'list')] 
       [preceding-sibling::item[1][contains(.,'list')]]"/> 
</xsl:stylesheet> 

lorsqu'il est appliqué sur le document XML fourni (corrigé à partir sévèrement malformés dans un document XML bien formé):

<t> 
<item>some text</item> 
<item>- a list item</item> 
<item>- another list item</item> 
<item>more plain text</item> 
<item>more and more plain text</item> 
<item>- yet another list item</item> 
<item>even more plain text</item> 
</t> 

produit le voulait , résultat correct:

<p>some text</p> 
<ul> 
    <li>- a list item</li> 
    <li>- another list item</li> 
</ul> 
<p>more plain text</p> 
<p>more and more plain text</p> 
<ul> 
    <li>- yet another list item</li> 
</ul> 
<p>even more plain text</p> 
+0

Nous avons un petit malentendu que je voulais distinguer par le «-». Mais ce n'est pas un problème car je peux facilement remplacer le contains (., 'List') avec starts-with (., '-'). – Jan

+0

Mais j'ai un autre gros problème. L'ensemble de nœuds que je veux traiter est dans une variable. Je peux faire un . Mais comment mettre mes données dans la clé xsl:? – Jan

+0

@Jan, Cette question devient trop longue et confuse après vos commentaires. Par souci de clarté, posez simplement une nouvelle question pour savoir comment appliquer les clés d'un document XML dans une variable - c'est facile à répondre et il serait plus utile à tout le monde si cette connaissance utile n'est pas enterré à l'intérieur d'une autre question. S'il vous plaît, informez-moi quand vous avez posé la nouvelle question, de sorte que je vous répondrais bientôt. –

1

Cette feuille de style:

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 
    <xsl:output indent="yes"/> 
    <xsl:strip-space elements="*"/> 
    <xsl:template match="node()"> 
     <xsl:apply-templates select="node()[1]|following-sibling::node()[1]"/> 
    </xsl:template> 
    <xsl:template match="item"> 
     <p> 
      <xsl:value-of select="."/> 
     </p> 
     <xsl:apply-templates select="following-sibling::node()[1]"/> 
    </xsl:template> 
    <xsl:template match="item[starts-with(.,'- ')]"> 
     <ul> 
      <xsl:call-template name="open"/> 
     </ul> 
     <xsl:apply-templates 
      select="following-sibling::node() 
         [not(self::item[starts-with(.,'- ')])][1]"/> 
    </xsl:template> 
    <xsl:template match="node()" mode="open"/> 
    <xsl:template match="item[starts-with(.,'- ')]" mode="open" name="open"> 
     <li> 
      <xsl:value-of select="substring-after(.,'- ')"/> 
     </li> 
     <xsl:apply-templates select="following-sibling::node()[1]" mode="open"/> 
    </xsl:template> 
</xsl:stylesheet> 

Sortie:

<p>some text</p> 
<ul> 
    <li>a list item</li> 
    <li>another list item</li> 
</ul> 
<p>more plain text</p> 
<p>more and more plain text</p> 
<ul> 
    <li>yet another list item</li> 
</ul> 
<p>even more plain text</p> 

Remarque: C'est comme emballage adjacents. Ussing traversal à grain fin.

+0

Pour être honnête, je ne comprends pas complètement votre solution. Après avoir défini mon nœud dans une variable, j'ai utilisé pour exécuter votre solution. Le résultat commence bien, mais tous les éléments sont traités plusieurs fois. Peut-être que je devrais comprendre la solution complètement. Les modèles traitent leur texte et appellent activement leur frère suivant. Mais alors le frère suivant sera toujours dans le jeu de nœuds, ou pas? – Jan

+0

@Jan: Utiliser 'exslt: ensemble de noeuds ($ items)/item [1]'. Le processus de traversée à grains fins nœud par nœud: d'abord le premier enfant et ensuite le premier frère suivant. –

Questions connexes