Table des matières

TP BDAV: XQuery

Interface XPath/XQuery

Pour lancer l'interface XQuery, cliquer sur le lien si dessus. Dans le cas où le navigateur vous demande avec quoi ouvrir le fichier, choisir “Java Web Start” ou javaws.exe. Voir le TP XPath pour plus de détails ou si JavaWS ne fonctionne pas.

Voici quelques liens sur XPath et XQuery:

FLWOR

Donner une expression FLWOR correspondant à chacune des requêtes suivantes:

  1. Documents Collection et Collection 2: Pour chaque série, créer un élément serie avec un attribut titre contenant le nom de la série et un attribut editeur contenant le nom de son éditeur (la valeur de l'attribut editeur est “” s'il n'y a pas d'éditeur pour la série).
    Correction:
    for $s in //serie
    return
    <serie titre="{$s/@nom}" editeur="{$s/editeur/@nom}"/>
  2. Documents Collection et Collection 2: pour chaque tome de la collection donner son numero, le nom de sa serie et son titre sous forme d'attributs.
    Correction:
    for $tome in //tome
    return 
    <tome serie="{$tome/../@nom}" titre="{$tome/titre/text()}">
      {$tome/@numero}
    </tome>
  3. Même question mais en ordonnant les résultats par titre.
    Correction:
    for $tome in //tome
    let $titre := $tome/titre
    order by $titre
    return 
    <tome serie="{$tome/../@nom}" titre="{$titre/text()}">
      {$tome/@numero}
    </tome>
  4. Document Database: pour chaque fichier créer un élément a contenant un attribut href indiquant l'url du document et ayant pour enfant du texte qui indique le nom du document. On pourra utiliser la fonction string(.) pour récupérer la valeur d'un attribut sous forme de texte.
    Correction:
    for $f in //file
    return 
    <a href="{$f/@url}">{string($f/@name)}</a>
  5. Transformer la requête précédente de manière à obtenir une liste html contenant les liens vers les fichiers. (On rappelle qu'une liste html est constituée par un élément ol ou ul contenant un ensemble d'éléments li dont le contenu correspond aux différents “items” de la liste.)
    Correction:
    <ul>
    {for $f in //file
    return 
    <li><a href="{$f/@url}">{string($f/@name)}</a></li>
    }
    </ul>
  6. Transformer à nouveau la requête précédente de façon à ce que:
    • Les urls des liens soient absolues (i.e. commence bien par http://liris.cnrs.fr/~ecoquery/files/). On pourra utiliser la fonction concat(.,.).
    • Le résultat forme un document XML. On pourra utiliser le modèle ci-dessous
      <html>
        <head>
          <title>Titre du document</title>
        </head>
        <body> 
          Contenu du document
        </body>
      </html>
    • Copier coller le résultat dans un bloc note et l'enregistrer avec l'extension .html. Ouvrir le fichier avec un navigateur et vérifier que les liens marchent (si le navigateur a du mal, essayer sans la première ligne du résultat).
      Correction:
      <html>
        <head>
          <title>Documents de la base</title>
        </head>
        <body> 
          <ul>
          {for $f in //file
          return 
            <li><a href="{concat('http://liris.cnrs.fr/~ecoquery/files/',$f/@url)}">{string($f/@name)}</a></li>
          }
          </ul>
        </body>
      </html>
  7. Document Bookmarks: donner pour chaque catégorie son nom et ses bookmarks (y compris ceux des sous-catégories). Le resultat devra être trié par nom ou titre, que ce soit pour les categories ou pour les bookmarks.
    Correction:
    for $cat in //categorie
    let $nom := $cat/@nom
    order by $nom
    return 
    <categorie>
      {$nom}
      {
        for $bm in $cat//bookmark
        order by $bm/title
    
        return $bm
      }
    </categorie>

Fonctions XQuery

Voir le résumé pour la syntaxe des fonctions.

  1. Document Bookmarks: écrire une fonction de présentation simple des bookmarks: elle prend un argument un noeud bookmark et donne un paragraphe correspondant au titre qui sera un lien (si le titre est absent, mettre l'url à la place du titre) et un paragraphe contenant sa description (ou rien s'il n'y a pas de description). On regroupera ces deux paragraphes dans une élément div.
    Utiliser la fonction pour générer une page web contenant une liste des bookmarks que vous testerez comme précédement. On pourra utiliser la construction if ( test ) then expr1 else expr2. () peut être utilisé pour renvoyer un ensemble d'éléments vide.
    Note: si une expression de chemin est utilisée à la place d'un booléen, on considère qu'elle vaut vrai si son résultat n'est pas vide.
    Correction:
    declare function local:pres-bookmarks($bm as element(bookmark)) 
    {
      <div>
        <p>
          <a href="{$bm/@url}">
            {
              if ($bm/title)
              then $bm/title/text()
              else string($bm/@url)
            }
          </a>
        </p>
        {
          for $desc in $bm/description
          return
            <p>
              {$desc/text()}
            </p>
        }
      </div>
    };
    
    
    <html>
      <head>
        <title>Bookmarks</title>
      </head>
      <body>
        <ul>
          {
            for $b in //bookmark
            return 
              <li>{local:pres-bookmarks($b)}</li>
          }
        </ul>
      </body>
    </html>
  2. On reprend la question précédente, mais en affichant à l'aide d'une fonction récursive les catégories avec leur bookmarks. Une catégorie sera représentée par un élément div dans lequel on mettra un paragraphe donnant le nom de la catégorie, un paragraphe regroupant toutes ses descriptions et enfin une liste html qui correspondra à l'ensemble des bookmarks et des catégories qui sont des enfants de la catégorie considérée. On utilisera la fonction précédente pour le formatage des bookmarks. Dans un premier temps on pourra éventuellement mettre en premier les sous-catégories, suivies des bookmarks. Dans un deuxième temps, on conservera l'ordre donné dans le document Bookmarks.
    Correction:
    (: Dans cette version on garde l'ordre :)
    
    declare function local:pres-bookmarks($bm as element(bookmark)) 
    {
      <div>
        <p>
          <a href="{$bm/@url}">
            {
              if ($bm/title)
              then $bm/title/text()
              else string($bm/@url)
            }
          </a>
        </p>
        {
          for $desc in $bm/description
          return
            <p>
              {$desc/text()}
            </p>
        }
      </div>
    };
    
    declare function local:pres-categorie($cat as element(categorie))
    {
      <div>
        <p>{string($cat/@nom)}</p>
        { if ($cat/description) then <p>{$cat/description/text()}</p> else () }
        <ul>
        {
          for $sub in $cat/*[self::categorie or self::bookmark]
          return 
            <li>
            {
              if ($sub[self::categorie])
              then local:pres-categorie($sub)
              else local:pres-bookmarks($sub)
            }
            </li>
        }
        </ul>
      </div>
    };
    
    
    <html>
      <head>
        <title>Bookmarks</title>
      </head>
      <body>
        <ul>
          {
            for $i in /bookmarks/categorie
            return local:pres-categorie($i)
          }
        </ul>
      </body>
    </html>
  3. Document Pieces: dans ce document, chaque pièce a un identifiant id, un nom et optionnellement l'identifiant d'une pièce dont elle constitue une partie. Écrire une fonction récursive permettant d'obtenir une hierachie de pièces représentant la composition d'une pièce. Attention, on ne peut pas utiliser un chemain XPath commençant par / dans une fonction. Utiliser cette fonction pour représenter de manière hierachique le document Pieces.
    Correction:
    declare function local:mkpc($pc as element(piece))
    {
      <piece>
        {$pc/@nom}
        {$pc/@id    (: note: cet attribut ne sert plus à présent :) }
        {
          for $sub in $pc/../piece[@used-in = $pc/@id]
          return local:mkpc($sub)
        }
      </piece>
    };
    
    <pieces>
    {
      for $pc in /pieces/piece[not(@used-in)]
      return local:mkpc($pc)
    }
    </pieces>