Par Benoît Valiron <benoit.valiron [at] monoidal.net> et Jean Baptiste FADOUL <jean-baptiste.faddoul [at] xrce.xerox.com>
Ce TP reprend en grande partie le TD 7.
Téléchargez le Document 1. En TD nous avons trouvé des expressions XPath pour déterminer les points suivant :
les éléments acteur ;
/child::liste_acteurs/child::acteur /liste_acteurs/acteur /descendant::acteur //acteur
le nombre d'acteur décrit dans le document XML ;
ount(/child::liste_acteurs/child::acteur) count(/liste_acteurs/acteur) count(/descendant::acteur) count(//acteur)
tous les noeuds "film"
//film
la liste des films nommés dans la biographie de Hilary Swant
//acteur[@id="hilary"]//film /list_acteurs/acteur[nom="Swant"]//film /list_acteurs/acteur/nom[text()="Swant"]/..//film
le premier noeud fils du premier noeud acteur ;
/descendant::acteur[position()=1]/*[position()=1] //acteur[1]/*[1]
le premier noeud fils du deuxième noeud acteur ;
/descendant::acteur[position()=2]/*[position()=1] //acteur[2]/*[1]
les deux premiers éléments fils de chaque acteur ;
/descendant::acteur/*[position()=1 or position()=2] //acteur/*[position()<=2]
le dernier élément fils de chaque acteur ;
/descendant::acteur/*[position()=last()] //acteur/*[last()]
l'acteur dont l'identifiant est clint ;
/descendant::acteur[attribute::id='clint'] //acteur[@id='clint']
l'acteur dont le prénom est Clint ;
/descendant::acteur[child::prenom/text()='Clint'] //acteur[prenom='Clint']
les noms des acteurs dont la biographie contient exactement deux pgraphes ;
//acteur/biographie/p[last()=2]/../../nom/text() //acteur/nom/text()[count(../../biographie/p)=2]
Téléchargez le Document 2. L'exercice 2 du TD (que nous avons sauté) demandait des expressions XPath déterminant
le nombre de films disponibles ;
count(//film)
les acteurs du deuxième film ;
//film[2]//acteur
les titres des films dont la fiche est en anglais ;
//film[@lang="en"]/titre/text()
le nom du personnage dont l'identifiant est lukemonfils ;
//acteur[@id="lukemonfils"]/@personnage
le titre des films sortis en 1981 ;
//film[annee/text()="1981"]/titre/text()
le nombre de références faites au personnage dont l'identifiant est indy ;
count(//perso[@ref="indy"])
les films sans acteur ;
//film[count(.//acteur)=0]
les films avec plusieurs réalisateurs ;
//film[contains('realisateur',',')]
les titres des films dont le synopsis contient le mot believe.
//film[contains(synopsis,"believe")]/titre/text()
Cet exercice ré-utilise le Document 2. Utilisez l'outil XSLT sur le site du cours pour faire les exercices.
Continuez la feuille de style suivante :
<stylesheet version="1.0" xmlns="http://www.w3.org/1999/XSL/Transform"> <template match="/"> ..... ..... ..... </template> </stylesheet>
Afin d'obtenir le résultat suivant :
Sylvester Stallone joue rocky Talia Shire joue adrian ...
<stylesheet version="1.0" xmlns="http://www.w3.org/1999/XSL/Transform"> <template match="/films"> <for-each select="film/casting/acteur"> <value-of select="." /> joue <value-of select="@id" /> <text> </text> </for-each> </template> </stylesheet>
Que fait (et comment résoudre le problème) :
<stylesheet version="1.0" xmlns="http://www.w3.org/1999/XSL/Transform"> <template match="/films/film/casting/acteur"> <value-of select="text()" /> joue <value-of select="@id" /> <text> </text> </template> </stylesheet>
Souvenez-vous qu'il y a des template par défaut qui sont toujours présent. Le comportement est le suivant : On par de la racine. Si on rencontre un noeud élément, on suit ses fils et on itère. Si on rencontre un noeud texte, on écrit le texte.
Ce template affiche en plus du texte qui ne devrait pas être là. Pour résoudre le problème, il faut ajouter le template
<template match="text()"> </template>
Le template qui gère les noeuds texte peut être réécrit en utilisant
<template match="text()"> NOUVEAU TEMPLATE </template>
Remplacez NOUVEAU TEMPLATE par
et par rien, et voyez ce qui se passe. Pouvez-vous interpreter ?
Écrire une feuille de style XSLT qui construit un document XML sous la forme suivante :
<liste> <film> <acteur>NOM_ACTEUR</acteur> <titre>NOM_DU_FILM</titre> </film> <film> <acteur>NOM_ACTEUR</acteur> <titre>NOM_DU_FILM</titre> </film> ... </liste>
Si vous voulez que ça fonctionne, il faut placer un préfixe sur les éléments du langage XSLT : remplacer le xmlns de l'élément stylesheet par xmlns:x et appliquez les préfixes aux bons endroits.
<x:stylesheet version="1.0" xmlns:x="http://www.w3.org/1999/XSL/Transform"> <x:template match="/"> <liste> <x:for-each select="/films/film/casting/acteur"> <film> <acteur> <x:value-of select="." /> </acteur> <titre> <x:value-of select="../../titre" /> </titre> </film> </x:for-each> </liste> </x:template> </x:stylesheet>
Que fait la feuille de style suivante ?
<stylesheet version="1.0" xmlns="http://www.w3.org/1999/XSL/Transform"> <template match="/films/film"> <for-each select="synopsis/*|synopsis/text()"> <if test="@ref"> <variable name="x" select="@ref" /> <value-of select="../../casting/acteur[@id=$x]/@personnage" /> </if> <value-of select="." /> </for-each> </template> </stylesheet>
Écrivez une feuille de style XSLT qui produise le résultat suivant :
rocky apparait 14 fois dans le synopsis adrian apparait 5 fois dans le synopsis paulie apparait 0 fois dans le synopsis creed apparait 3 fois dans le synopsis ...
Le premier mot est le @id de chaque acteur et le chiffre est le nombre d'apparition de l'identifiant dans les balises <perso ...> du synopsis.
<stylesheet version="1.0" xmlns="http://www.w3.org/1999/XSL/Transform"> <template match="/films/film"> <for-each select="synopsis/*|synopsis/text()"> <if test="@ref"> <variable name="x" select="@ref" /> <value-of select="../../casting/acteur[@id=$x]/@personnage" /> </if> <value-of select="." /> </for-each> </template> </stylesheet>
Question supplémentaire : vous verrez apparaitre une ligne
apparait 0 fois dans le document
sans premier mot. Quel est le problème, et pouvez-vous le résoudre ?
<stylesheet version="1.0" xmlns="http://www.w3.org/1999/XSL/Transform"> <template match="/films/film"> <for-each select="casting/acteur"> <variable name="x" select="@id" /> <if test="$x"> <value-of select="$x" /> apparait <value-of select="count(//perso[@ref=$x])" /> fois dans le document </if> </for-each> </template> </stylesheet>
ou
<stylesheet version="1.0" xmlns="http://www.w3.org/1999/XSL/Transform"> <template match="/films/film"> <for-each select="casting/acteur[@id]"> <variable name="x" select="@id" /> <value-of select="$x" /> apparait <value-of select="count(//perso[@ref=$x])" /> fois dans le document </for-each> </template> </stylesheet>