HervéRenault.fr

Logo de XSLT

Ajouter une balise avec XSLT

C'est la version XSLT de cette page que j'avais faite à propos de sed.

J'avais donc des blocs de ce style :

    <p>bidule</p>
    <ul>
        <li>foo</li>
        <li>baaaar</li>
    </ul>

Que je voulais transformer comme ça :

    <div>
        <p>bidule</p>
        <ul>
            <li>foo</li>
            <li>baaaar</li>
        </ul>
    </div>

Pour pimenter l'exemple, je ne veux faire cette transformation que pour la première occurence de ce bloc à l'intérieur du <body>. Pour ça, je dois utiliser [1] comme ceci :

<?xml version="1.0" encoding="UTF-8"?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:output method="html" indent="yes"/>

    <!-- le template "à l'identique" pour recopier tout tel quel -->
    <xsl:template match="node()|@*">
        <xsl:copy>
            <xsl:apply-templates select="node()|@*"/>
        </xsl:copy>
    </xsl:template>

    <!-- je suppose que le bloc que je cherche se trouve dans le body -->
    <xsl:template match="body">
        <xsl:copy>
            <xsl:copy-of select="p[1]/preceding-sibling::*"/>
            <div>
                <xsl:copy-of select="p[1]|ul[1]"/>
            </div>
            <xsl:copy-of select="ul[1]/following-sibling::*"/>
        </xsl:copy>
    </xsl:template>

</xsl:stylesheet>

Ça se complique…

Une autre fois, j'ai eu besoin d'ajouter une balise <ul> autour d'un lot de <li class="machin">. Je ne pouvais pas savoir combien j'avais de <li> mais ce n'est pas un problème pour XSLT

J'avais donc des blocs de ce style :

<ul>
    <li>foo</li>
    <li class="machin">bar</li>
    <li class="machin">truc</li>
    <li class="machin">bidule</li>
    <li>chose</li>
</ul>

Que je voulais transformer comme ça :

<ul>
    <li>foo</li>
    <ul>
        <li class="machin">bar</li>
        <li class="machin">truc</li>
        <li class="machin">bidule</li>
    </ul>
    <li>chose</li>
</ul>

Je ne sais pas si c'est la façon de faire la plus simple, mais elle fonctionne :

<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">

    <xsl:output method="html" indent="yes"/>

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

    <!-- on empêche le traitement "recopie tout tel quel" des li, sans quoi les li class="machin" seront dupliqués -->
    <xsl:template match="li" />

    <!-- les li qui n'ont pas class="machin", on les laisse tels quels -->
    <xsl:template match="li[not(@class='machin')]">
        <xsl:call-template name="recopie-tout-tel-quel"/>
    </xsl:template>

    <!-- quand on a un li class="machin" qui n'est pas précédé d'un li class="machin" -->
    <xsl:template match="li[@class='machin'][preceding-sibling::*[1][not(self::li[@class='machin'])]]">
        <!-- ouvre le ul -->
        <ul>
            <!-- traite les li class="machin" avec un mode particulier -->
            <xsl:apply-templates select="self::li[@class='machin']" mode="copie"/>
        <!-- ferme le ul -->
        </ul>
    </xsl:template>

    <!-- le traitement particulier (avec un paramètre mode) appelé depuis le template ci-dessus -->
    <xsl:template match="li" mode="copie">
        <!-- on met le li tel quel -->
        <xsl:call-template name="recopie-tout-tel-quel"/>
        <!-- puis on rappelle ce template particulier si l'élément suivant est un li class="machin" -->
        <xsl:apply-templates select="following-sibling::*[1][self::li[@class='machin']]" mode="copie"/>
        <!-- si l'élément suivant n'est pas un li class="machin", ce traitement s'arrête là -->
    </xsl:template>

</xsl:stylesheet>