Xmlstarlet, exemples d'utilisation

Le fichier xml utilisé pour ces exemples est disponible ici et composé de données rassemblées depuis le site de l'Union des Villes et Communes de Wallonie. Ses éléments sont de la forme

 <commune>
  <id>Aiseau-Presles</id>
  <adresse>Rue Président John Kennedy, 150 6250 Aiseau-Presles</adresse>
  <arrondissement>Charleroi</arrondissement>
  <coalition>PS</coalition>
  <entite>
    <id>Aiseau</id>
    <postcode>6250</postcode>
  </entite>
  <entite>
    <id>Pont-de-Loup</id>
    <postcode>6250</postcode>
  </entite>
  <entite>
    <id>Presles</id>
    <postcode>6250</postcode>
  </entite>
  <entite>
    <id>Roselies</id>
    <postcode>6250</postcode>
  </entite>
  <fax>071/26.06.09</fax>
  <fiches></fiches>
  <latitude>50.41839</latitude>
  <longitude>4.570227</longitude>
  <mail>info@aiseau-presles.be</mail>
  <occupation></occupation>
  <population>10731 habitants</population>
  <province>Hainaut</province>
  <receveur>Mme Nathalie Coelst</receveur>
  <secretaire>M. Xavier Lefèvre</secretaire>
  <site>http://www.aiseau-presles.be</site>
  <superficie>2300 ha</superficie>
  <tel>071/26.06.11</tel>
  <titre>Commune</titre>
 </commune>

Afficher la structure du document, les éléments étant triés et affichés de manière unique:

  $ xmlstarlet el -u liste_communes.xml
  communes
  communes/commune
  communes/commune/adresse
  communes/commune/arrondissement
  communes/commune/coalition
  communes/commune/entite
  communes/commune/entite/id
  communes/commune/entite/postcode
  communes/commune/fax
  communes/commune/fiches
  communes/commune/id
  communes/commune/latitude
  communes/commune/longitude
  communes/commune/mail
  communes/commune/occupation
  communes/commune/population
  communes/commune/province
  communes/commune/receveur
  communes/commune/secretaire
  communes/commune/site
  communes/commune/superficie
  communes/commune/tel
  communes/commune/titre
  communes/title

Obtenir le nom de chaque commune, puis chacune de ses entités, avec une indentation pour distinguer celles-ci:

  $ xmlstarlet sel -t -m "//commune"  # les éléments correspondants à 'commune'
                                      # quel que soit le niveau ds l'arborescence 
                              -v id   # renvoie la valeur l'élément id 
                                 -n   # insère un saut de ligne
                        -m "entite"   # les éléments correspondants ds le chemin
                                      # en cours 
                            -o "  "   # renvoie une chaîne de caractères de manière littérale
                              -v id   # voir plus haut 
                                 -n   # idem
                 liste_communes.xml
 Aiseau-Presles
   Aiseau
   Pont-de-Loup
   Presles
   Roselies
 Amay
   Amay
   Ampsin
   Flône
   Jehay
   Ombret
 Amel (Amblève)
   Amel (Amblève)
   Heppenbach
   Meyrode
 (etc.)

Extrait de la feuille de style correspondante:

 <xsl:template match="/">
   <xsl:call-template name="t1"/>
 </xsl:template>
 <xsl:template name="t1">
   <xsl:for-each select="//commune">
     <xsl:value-of select="id"/>
     <xsl:value-of select="'&#10;'"/>
     <xsl:for-each select="entite">
       <xsl:value-of select="'  '"/>
       <xsl:value-of select="id"/>
       <xsl:value-of select="'&#10;'"/>
     </xsl:for-each>
   </xsl:for-each>
 </xsl:template>

Compter le nombre d'entités que comprend chaque commune:

  $ xmlstarlet sel -t -m "//commune" -v id -o ":" -v "count(entite)" -n liste_communes.xml
  [...]
  Wasseiges:4
  Waterloo:1
  Wavre:3
  Welkenraedt:2
  Wellin:5
  Yvoir:9

Extrait de la feuille de style générée:

 <xsl:template name="t1">
   <xsl:for-each select="//commune">
     <xsl:value-of select="id"/>
     <xsl:value-of select="':'"/>
     <xsl:value-of select="count(entite)"/>
     <xsl:value-of select="'&#10;'"/>
   </xsl:for-each>
 </xsl:template>

Inversément, afficher toutes les entités par ordre alphabétique, suivies de la communes à laquelle elles appartiennent. Il faut donc sélectionner le noeud parent:

  $ xmlstarlet sel  -t -m "//entite"  #
                         -s A:T:- id  # tri Ascendant, en mode Texte, en laissant
                                      # la casse par défaut, en fonction de l'élément id
                               -v id  # affichage de l'élément entite/id
                              -o ":"  # on insère un séparateur littéral
                      -m "parent::*"  # matching sur le parent du noeud en cours 
                               -v id  # 
               -n liste_communes.xml
 Abolens:Hannut
 Abée:Tinlot
 Achet:Hamois
 Achène:Ciney
 Acosse:Wasseiges
 Acoz:Gerpinnes
 Agimont:Hastière
 Aineffe:Faimes
 Aische-en-Refail:Eghezée
 (etc.)

Extrait de la feuille de style générée:

 <xsl:template name="t1">
   <xsl:for-each select="//entite">
     <xsl:sort order="ascending" data-type="text" case-order="upper-first" select="id"/>
     <xsl:value-of select="id"/>
     <xsl:value-of select="':'"/>
     <xsl:for-each select="parent::*">
       <xsl:value-of select="id"/>
       <xsl:value-of select="'&#10;'"/>
     </xsl:for-each>
   </xsl:for-each>
 </xsl:template>

Ceci aboutit au même résultat:

  $ xmlstarlet sel -t -m "//entite" -s A:T:- id  -v "concat(id,':',../id)" -n liste_communes.xml

et engendre une feuille de style incluant:

 <xsl:template name="t1">
   <xsl:for-each select="//entite">
     <xsl:sort order="ascending" data-type="text" case-order="upper-first" select="id"/>
     <xsl:value-of select="concat(id,':',../id)"/>
     <xsl:value-of select="'&#10;'"/>
   </xsl:for-each>
 </xsl:template>