Traductions pour la plateforme Java

Générer, analyser et ingurgiter du XML

Article d'origine: 

Manipulation de XML sans peine

Résumé: 

Voyez comme il est facile de manipuler dans tous les sens du XML avec Groovy. Dans ce volet de Groovy par la pratique, l'auteur Scott Davis démontre que, soit que vous vouliez créer du XML avec MarkupBuilder et StreamingMarkupBuilder, soit que vous vouliez analyser du XML avec XmlParser et XmlSlurper, Groovy offre des outils convaincants pour traiter ce format de données très courant.

On a l'impression que XML a toujours existé. En fait, XML a célébré son dixième anniversaire en 2008 (voir les Ressources). Comme le langage Java™ précède XML de quelques années seulement, on peut dire que pour les développeurs Java, XML a toujours existé.

Sun Microsystems, l'inventeur du langage Java, a été un fervent partisan de XML depuis le tout début. Après tout, la promesse faite par XML de permettre l'indépendance de la plateforme est bien en phase avec le slogan du langage Java "écrit une fois, exécuté partout". Etant donné que les deux technologies partagent la même sensibilité, on pourrait penser que le langage Java et XML cohabiteraient mieux qu'ils ne le font. En fait, analyser et générer du XML en Java parait bizarrement étranger et alambiqué.

Heureusement, Groovy introduit de meilleurs moyens pour créer et traiter du XML. A l'aide de quelques exemples (tous disponibles en téléchargement), cet article vous montrera de quelle manière Groovy rend l'écriture et l'analyse de XML d'une simplicité rafraichissante.

Comparer l'analyse XML avec Java et avec Groovy

A la fin de l'article "Enrichir for each", j'ai introduit un document XML simple rappelé au Listing 1. (J'ai ajouté l'attribut type cette fois pour rendre les choses un peu plus intéressantes).

Listing 1. Un document XML listant les langages que je connais

<langs type="current">
  <language>Java</language>
  <language>Groovy</language>
  <language>JavaScript</language>
</langs>

L'analyse de ce document XML trivial est incontestablement complexe en Java, comme vous le voyez dans le Listing 2. Il faut 30 lignes de code pour analyser un fichier XML de cinq lignes.

Listing 2. Analyser un fichier XML en Java

import org.xml.sax.SAXException;
import org.w3c.dom.*;
import javax.xml.parsers.*;
import java.io.IOException;

public class ParseXml {
  public static void main(String[] args) {
    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    try {
      DocumentBuilder db = dbf.newDocumentBuilder();
      Document doc = db.parse("src/languages.xml");

      //afficher l'attribut "type"
      Element langs = doc.getDocumentElement();
      System.out.println("type = " + langs.getAttribute("type"));

      //afficher les éléments "language"
      NodeList list = langs.getElementsByTagName("language");
      for(int i = 0 ; i < list.getLength();i++) {
        Element language = (Element) list.item(i);
        System.out.println(language.getTextContent());
      }
    }catch(ParserConfigurationException pce) {
      pce.printStackTrace();
    }catch(SAXException se) {
      se.printStackTrace();
    }catch(IOException ioe) {
      ioe.printStackTrace();
    }
  }
}

Comparez cela avec le code Groovy correspondant du Listing 3:

Listing 3. Analyser un fichier XML en Groovy

def langs = new XmlParser().parse("languages.xml")
println "type = ${langs.attribute("type")}"
langs.language.each{
  println it.text()
}

//sortie:
type = current
Java
Groovy
JavaScript

Le plus intéressant avec ce code Groovy n'est pas qu'il soit significativement plus court que son équivalent Java - bien que ses cinq lignes pour analyser cinq lignes de XML parlent clairement en sa faveur. Ce que j'apprécie le plus dans ce code Groovy est qu'il est de loin plus expressif. Quand j'écris langs.language.each, c'est comme si je travaillais directement avec le XML. Dans la version Java, le XML a complètement disparu.

Variables de type String et XML

Le bénéfice du travail avec XML en Groovy devient encore plus évident quand on stocke le XML dans une variable de type String au lieu d'un fichier. Les triples quotes de Groovy (couramment appelées HereDoc dans d'autres langages) permettent un stockage sans douleur du XML en interne, comme le montre le Listing 4. Le seul changement à apporter à l'exemple Groovy du Listing 3 est de modifier l'appel de la méthode parse() de XmlParser (qui s'occupe des Files, InputStreamss, Readers, et des URIs) en celui de parseText().

Listing 4. Stocker du XML en interne avec Groovy

def xml = """
<langs type="current">
  <language>Java</language>
  <language>Groovy</language>
  <language>JavaScript</language>
</langs>
"""

def langs = new XmlParser().parseText(xml)
println "type = ${langs.attribute("type")}"
langs.language.each{
  println it.text()
}

Notez que les triples quotes gèrent le document XML multilignes sans problème. La variable xml est réellement une java.lang.String classique - vous pouvez ajouter println xml.class pour le vérifier vous-même. Les triples quotes gèrent également les doubles quotes internes de type="current" sans vous forcer à les échapper manuellement avec un caractère antislash comme vous le feriez en Java.

Mettez en contraste l'élégance du code Groovy du Listing 4 avec le Java correspondant au Listing 5:

Listing 5. Stocker du XML en interne avec Java

import org.xml.sax.SAXException;
import org.w3c.dom.*;
import javax.xml.parsers.*;
import java.io.*;

public class ParseXmlFromString {
  public static void main(String[] args) {
    String xml = "<langs type=\"current\">\n" +
            "  <language>Java</language>\n" +
            "  <language>Groovy</language>\n" +
            "  <language>JavaScript</language>\n" +
            "</langs>";

    byte[] xmlBytes = xml.getBytes();
    InputStream is = new ByteArrayInputStream(xmlBytes);

    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    try {
      DocumentBuilder db = dbf.newDocumentBuilder();
      Document doc = db.parse(is);

      //afficher l'attribut "type"
      Element langs = doc.getDocumentElement();
      System.out.println("type = " + langs.getAttribute("type"));

      
      //afficher les éléments "language"
      NodeList list = langs.getElementsByTagName("language");
      for(int i = 0 ; i < list.getLength();i++) {
        Element language = (Element) list.item(i);
        System.out.println(language.getTextContent());
      }
    }catch(ParserConfigurationException pce) {
      pce.printStackTrace();
    }catch(SAXException se) {
      se.printStackTrace();
    }catch(IOException ioe) {
      ioe.printStackTrace();
    }
  }
}

Remarquez que la variable xml est polluée avec des caractères d'échappement pour les quotes internes et les sauts de ligne. Cependant, le plus gênant est d'avoir à convertir la String en tableau de byte, puis de devoir passer cela à un ByteArrayInputStream, avant qu'elle puisse être analysée. Curieusement, le DocumentBuilder ne fournit pas de méthode directe pour analyser une simple String en tant que XML.

Générer du XML avec MarkupBuilder

La plus large victoire de Groovy sur Java arrive quand vous voulez créer un document XML. Le Listing 6 montre les 50 lignes de code Java nécessaires à la création d'un fichier XML de cing lignes:

Listing 5. Générer du XML avec Java

import org.w3c.dom.*;
import javax.xml.parsers.*;
import javax.xml.transform.*;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;
import java.io.StringWriter;

public class CreateXml {
  public static void main(String[] args) {
    DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
    try {
      DocumentBuilder db = dbf.newDocumentBuilder();
      Document doc = db.newDocument();

      Element langs = doc.createElement("langs");
      langs.setAttribute("type", "current");
      doc.appendChild(langs);

      Element language1 = doc.createElement("language");
      Text text1 = doc.createTextNode("Java");
      language1.appendChild(text1);
      langs.appendChild(language1);

      Element language2 = doc.createElement("language");
      Text text2 = doc.createTextNode("Groovy");
      language2.appendChild(text2);
      langs.appendChild(language2);

      Element language3 = doc.createElement("language");
      Text text3 = doc.createTextNode("JavaScript");
      language3.appendChild(text3);
      langs.appendChild(language3);

      // Output the XML
      TransformerFactory tf = TransformerFactory.newInstance();
      Transformer transformer = tf.newTransformer();
      transformer.setOutputProperty(OutputKeys.INDENT, "yes");
      StringWriter sw = new StringWriter();
      StreamResult sr = new StreamResult(sw);
      DOMSource source = new DOMSource(doc);
      transformer.transform(source, sr);
      String xmlString = sw.toString();
      System.out.println(xmlString);
    }catch(ParserConfigurationException pce) {
      pce.printStackTrace();
    } catch (TransformerConfigurationException e) {
      e.printStackTrace();
    } catch (TransformerException e) {
      e.printStackTrace();
    }
  }
}

Je sais que certains d'entre vous vont crier "Erreur !" à cet instant précis. Beaucoup de librairies tierces peuvent rendre ce code plus lisible - JDOM et dom4j en étant deux exemples populaires. Mais aucune des librairies Java ne s'approche de la simplicité d'utilisation du MarkupBuilder de Groovy, comme le démontre le Listing 7:

Listing 7. Générer du XML avec Groovy

def xml = new groovy.xml.MarkupBuilder()
xml.langs(type:"current"){
  language("Java")
  language("Groovy")
  language("JavaScript")
}

Notez que nous revenons à peu près à un ratio 1:1 entre le code et le XML. Plus important, je peux visualiser à nouveau le XML. Bien sûr, les caractères "<" et ">" sont remplacés par des accolades, et les attributs utilisent le double-point (la notation Groovy pour les HashMap) au lieu du signe égal, mais la structure de base est reconnaissable que ce soit en Groovy ou en XML. C'est presque comme un DSL destiné à générer du XML, n'est-ce-pas ?

Le Builder peut réaliser ce genre de choses magiques parce que Groovy est un langage dynamique. Le langage Java, par contre, est statique: le compilateur Java s'assure que toutes les méthodes existent avant que vous ne les appeliez. (Le code Java ne compilera même pas, sans parler d'exécution, si vous essayez d'appeler une méthode inexistante). Mais le Builder de Groovy démontre que ce qui est un bug pour un langage est une fonctionnalité pour un autre. Si vous examinez la documentation des APIs de MarkupBuilder, vous ne trouverez pas de méthode langs(), de méthode language(), ou tout autre nom d'élément. Heureusement, Groovy peut traiter ces appels à des méthodes qui n'existent pas et faire quelque chose d'utile avec. Dans le cas d'un MarkupBuilder, il prend les appels à des méthodes fantômes et génère du XML bien formé.

Le Listing 8 développe l'exemple basique de MarkupBuilder que nous venons de voir. Si vous voulez récupérer le XML généré dans une String, passez un StringWriter au constructeur du MarkupBuilder. Si vous voulez ajouter d'autres attributs à langs, passez les simplement en paramètres, séparés par des virgules. Notez que le contenu de l'élément language est défini par une valeur sans nom. Vous pouvez ajouter des attributs et un contenu par le biais d'une liste dont le séparateur est la virgule également.

Listing 8. Un exemple plus poussé de MarkupBuilder

def sw = new StringWriter()
def xml = new groovy.xml.MarkupBuilder(sw)
xml.langs(type:"current", count:3, mainstream:true){
  language(flavor:"static", version:"1.5", "Java")
  language(flavor:"dynamic", version:"1.6.0", "Groovy")
  language(flavor:"dynamic", version:"1.9", "JavaScript")
}
println sw

//sortie:
<langs type='current' count='3' mainstream='true'>
  <language flavor='static' version='1.5'>Java</language>
  <language flavor='dynamic' version='1.6.0'>Groovy</language>
  <language flavor='dynamic' version='1.9'>JavaScript</language>
</langs>

Avec ces quelques trucs sur MarkupBuilde en poche, on peut commencer à faire des choses intéressantes. Par exemple, vous pouvez rapidement générer un document HTML bien formé et l'écrire dans un fichier. Le Listing 9 montre le code:

Listing 9. Générer du HTML avec un MarkupBuilder

def sw = new StringWriter()
def html = new groovy.xml.MarkupBuilder(sw)
html.html{
  head{
    title("Links")
  }
  body{
    h1("Here are my HTML bookmarks")
    table(border:1){
      tr{
        th("what")
        th("where")
      }
      tr{
        td("Groovy Articles")
        td{
          a(href:"http://ibm.com/developerworks", "DeveloperWorks")
        }
      }
    }
  }
}

def f = new File("index.html")
f.write(sw.toString())

//sortie:
<html>
  <head>
    <title>Links</title>
  </head>
  <body>
    <h1>Here are my HTML bookmarks</h1>
    <table border='1'>
      <tr>
        <th>what</th>
        <th>where</th>
      </tr>
      <tr>
        <td>Groovy Articles</td>
        <td>
          <a href='http://ibm.com/developerworks'>DeveloperWorks</a>
        </td>
      </tr>
    </table>
  </body>
</html>

La Figure 1 montre l'affichage par un navigateur du HTML généré par le Listing 9:

Figure 1. Rendu du HTML

Rendu du HTML

Génération de XML avec StreamingMarkupBuilder

MarkupBuilder fonctionne très bien pour générer des documents XML de manière synchrone. Pour créer des documents XML plus avancés, Groovy offre StreamingMarkupBuilder. Il permet de générer toutes sortes de fonctionnalités de XML, comme les instructions de traitement, les espaces de nom et le texte sans échappement (parfait pour les sections CDATA) avec l'aide de l'objet mkp. Le Listing 10 donne un aperçu des fonctionnalités intéressantes de StreamingMarkupBuilder:

Listing 10. Générer du XML avec StreamingMarkupBuilder

def comment = "<![CDATA[<!-- address is new to this release -->]]>"
def builder = new groovy.xml.StreamingMarkupBuilder()
builder.encoding = "UTF-8"
def person = {
  mkp.xmlDeclaration()
  mkp.pi("xml-stylesheet": "type='text/xsl' href='myfile.xslt'" )
  mkp.declareNamespace('':'http://myDefaultNamespace')
  mkp.declareNamespace('location':'http://someOtherNamespace')
  person(id:100){
    firstname("Jane")
    lastname("Doe")
    mkp.yieldUnescaped(comment)
    location.address("123 Main")
  }
}
def writer = new FileWriter("person.xml")
writer << builder.bind(person)

//sortie:
<?xml version="1.0" encoding="UTF-8"?>
<?xml-stylesheet type='text/xsl' href='myfile.xslt'?>
<person id='100'
        xmlns='http://myDefaultNamespace'
        xmlns:location='http://someOtherNamespace'>
  <firstname>Jane</firstname>
  <lastname>Doe</lastname>
  <![CDATA[<!-- address is new to this release -->]]>
  <location:address>123 Main</location:address>
</person>

Notez que StreamingMarkupBuilder ne produit pas de XML jusqu'à ce que la méthode bind() soit appelée, en passant en paramètre la fermeture qui contient le balisage et toutes les instructions. Ceci permet de construire les différentes parties du document XML de manière asynchrone et de tout générer d'un seul coup. (Voir les Ressources pour plus d'informations).

Comprendre XmlParser

Groovy vous donne deux moyens de produire du XML - MarkupBuilder et StreamingMarkupBuilder - ayant chacun ses propres atouts. Ceci est vrai aussi pour l'analyse du XML. Vou pouvez utiliser soit XmlParser soit XmlSlurper.

XmlParser offre une vision plus orientée programmeur du document XML. Si vous n'avez aucun mal à imaginer le document en termes de Lists et de Maps (respectivement pour les Elements et les Attributes), alors vous devriez être à l'aise avec XmlParser. Le Listing 11 dévoile un peu plus les rouages de XmlParser:

Listing 11. Examen plus poussé de XmlParser

def xml = """
<langs type='current' count='3' mainstream='true'>
  <language flavor='static' version='1.5'>Java</language>
  <language flavor='dynamic' version='1.6.0'>Groovy</language>
  <language flavor='dynamic' version='1.9'>JavaScript</language>
</langs>
"""

def langs = new XmlParser().parseText(xml)
println langs.getClass()
// class groovy.util.Node

println langs
/*
langs[attributes={type=current, count=3, mainstream=true};
      value=[language[attributes={flavor=static, version=1.5};
                      value=[Java]],
             language[attributes={flavor=dynamic, version=1.6.0};
                      value=[Groovy]],
             language[attributes={flavor=dynamic, version=1.9};
                      value=[JavaScript]]
            ]
]
*/

Remarquez que la méthode XmlParser.parseText() retourne un groovy.util.Node - dans ce cas, le noeud racine du document XML. Quand on exécute println langs , la méthode Node.toString() est appelée, retournant une sortie de débuggage. Pour récupérer les données réelles, il faudrait appeler soit Node.attribute() soit Node.text().

Récupérer les attributs avec XmlParser

Comme vous l'avez vu précédemment, vous pouvez récupérer la valeur d'un attribut particulier en appelant Node.attribute("key"). Si vous appelez Node.attributes(), vous obtiendrez une HashMap  qui contient les valeurs de tous les attributs. En utilisant la fermeture each que vous avez découvert dans "Enrichir for each", parcourir les attributs n'est pas compliqué. Voyez le Listing 12 pour en avoir un exemple. (Consultez les Ressources pour avoir l'API de groovy.util.Node).

Listing 12. XmlParser traite les attributs comme une HashMap

def langs = new XmlParser().parseText(xml)

println langs.attribute("count")
// 3

langs.attributes().each{k,v->
  println "-" * 15
  println k
  println v
}

//output:
---------------
type
current
---------------
count
3
---------------
mainstream
true

Aussi agréable le travail avec les attributs soit-il, XmlParser fournit un aide encore plus efficace pour travailler avec les éléments.

Accéder aux éléments avec XmlParser

Avec XmlParser, il est possible de requêter les éléments de manière intuitive au moyen des GPath (implémentation Groovy de XPath). Par exemple, le Listing 13 démontre que la structure langs.language que j'ai utilisée précédemment retourne une groovy.util.NodeList contenant le résultat de la requête. NodeList étend java.util.ArrayList, c'est donc à la base une List qui aurait reçu les super pouvoirs de GPath.

Listing 13. Requêtage avec GPath et XmlParser

def langs = new XmlParser().parseText(xml)

// Syntaxe de requêtage raccourcie
// sur une NodeList anonyme
langs.language.each{
  println it.text()
}

// Séparation de la requête
// et de la fermeture each
def list = langs.language
list.each{
  println it.text()
}

println list.getClass()
// groovy.util.NodeList

GPath est bien sûr le pendant de MarkupBuilder. Il utilise la même astuce en appelant des méthodes sans existence réelle, mais cette fois ce mécanisme est utilisé pour requêter le XML existant au lieu de le générer à la volée.

Sachant que le résultat d'une requête GPath est une List, on peut rendre le code encore plus concis. Groovy possède l'opérateur spread-dot (ndT: *.). En une seule ligne de code, il itère dans la liste, exécute l'appel de méthode sur chaque élément et retourne une List de résultats. Par exemple, si votre seul objectif est d'appeler la méthode Node.text() sur chaque élément du résultat de la requête, le Listing 14 vous montre comment le faire en une seule ligne de code:

Listing 14. Combiner l'opérateur spread-dot avec GPath

// la manière longue d'obtenir un résultat
def results = []
langs.language.each{
  results << it.text()
}

// la manière courte utilisant l'opérateur spread-dot
def values = langs.language*.text()
// [Java, Groovy, JavaScript]

// obtenir rapidement toutes les valeurs de l'attribut version
def versions = langs.language*.attribute("version")
// [1.5, 1.6.0, 1.9]

Mais si XmlParser est à la fois élégant et puissant, XmlSlurper se situe encore un cran au-dessus.

Analyse XML avec XMLSlurper

Quand j'ai introduit le Listing 1, j'ai dit que Groovy me donnait l'impression de travailler directement avec le XML. XmlParser a beaucoup de qualités, mais il faut tout de même traiter le XML par programmation. On vous retourne des Lists de Nodes et des HashMaps d' Attributes, et vous êtes obligés d'appeler des méthodes telles que Node.attribute() et Node.text() pour accéder aux données de base. XmlSlurperefface les derniers vestiges d'appels de méthodes, vous laissant avec l'agréable illusion que vous êtes en prise directe avec le XML.

Pour parler technique, XmlParser retourne des Nodes et des NodeLists, tandis que XmlSlurper retourne un groovy.util.slurpersupport.GPathResult. Mais maintenant que vous êtes au courant, je veux que vous oubliiez que j'ai jamais mentionné les détails d'implémentation de XmlSlurper. Vous apprécierez bien davantage la magie si vous ne gâchez pas l'effet en regardant derrière le rideau.

Le Listing 15 montre XmlParser et XmlSlurper côte-à-côte:

Listing 15. XmlParser et XmlSlurper

def xml = """
<langs type='current' count='3' mainstream='true'>
  <language flavor='static' version='1.5'>Java</language>
  <language flavor='dynamic' version='1.6.0'>Groovy</language>
  <language flavor='dynamic' version='1.9'>JavaScript</language>
</langs>
"""

def langs = new XmlParser().parseText(xml)
println langs.attribute("count")
langs.language.each{
  println it.text()
}

langs = new XmlSlurper().parseText(xml)
println langs.@count
langs.language.each{
  println it
}

Notez que XmlSlurper élimine toute notion d'appel de méthode. Au lieu d'appeler langs.attribute("count"), vous appelez langs.@count. Le signe @ est emprunté à XPath, mais le résultat donne l'illusion que l'on travaille directement avec l'attribut, impression que ne produit pas un appel à la méthode attribute(). Plutôt que d'appeler it.text(), vous appelez simplement it. On part de l'hypothèse que vous voulez travailler directement avec le contenu de l'élément.

XMLSlurper dans le monde réel

Pour aller plus loin que langs et language, voici un exemple tiré du monde réel montrant XmlSlurper en action. Yahoo! met à disposition sous forme de flux RSS la météo actuelle pour un code ZIP donné. RSS est évidemment un dialecte spécialisé. Entrez http://weather.yahooapis.com/forecastrss?p=80020 dans un navigateur web. Sentez-vous libre de modifier le code ZIP de Broomfield dans le Colorado pour mettre le vôtre (ndT: pour ma ville, le code est par exemple FRXX0110). Le Listing 16 montre une version simplifiée du flux RSS résultant:

Listing 16. Flux RSS de Yahoo! pour avoir la météo actuelle

<rss version="2.0"
     xmlns:yweather="http://xml.weather.yahoo.com/ns/rss/1.0"
     xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#">
  <channel>
    <title>Yahoo! Weather - Broomfield, CO</title>
    <yweather:location city="Broomfield" region="CO"   country="US"/>
    <yweather:astronomy sunrise="6:36 am"   sunset="5:50 pm"/>

    <item>
      <title>Conditions for Broomfield, CO at 7:47 am MST</title>
      <pubDate>Fri, 27 Feb 2009 7:47 am MST</pubDate>
      <yweather:condition text="Partly Cloudy"
                          code="30"  temp="25"
                          date="Fri, 27 Feb 2009 7:47 am MST" />
    </item>
  </channel>
</rss>

La première chose à faire est de mettre la main sur ce RSS par programmation. Créez un fichier nommé weather.groovy et ajoutez-y le code du Listing 17:

Listing 17. Accéder au RSS par programmation

def baseUrl = "http://weather.yahooapis.com/forecastrss"

if(args){
  def zip = args[0]
  def url = baseUrl + "?p=" + zip
  def xml = url.toURL().text
  println xml
}else{
  println "USAGE: weather zipcode"
}

Entrez  en ligne de commande pour vérifier que vous pouvez visualiser le RSS brut.

La partie la plus importante de ce script est url.toURL().text. la variable url est une String bien formée. Toutes les Strings se voient ajouter par Groovy la méthode toURL() qui les transforme en java.net.URL. En contrepartie, Groovy ajoute également à toutes les URLs une méthode getText() qui exécute une requête HTTP GET et retourne le résultat sous forme de String.

Maintenant que l'on dispose du RSS stocké dans la variable xml, ajoutons une pincée de XmlSlurper pour sélectionner les portions intéressantes, comme dans le Listing 18:

Listing 18. Utiliser XmlSlurper pour analyser du RSS

def baseUrl = "http://weather.yahooapis.com/forecastrss"

if(args){
  def zip = args[0]
  def url = baseUrl + "?p=" + zip
  def xml = url.toURL().text

  def rss = new XmlSlurper().parseText(xml)
  println rss.channel.title
  println "Sunrise: ${rss.channel.astronomy.@sunrise}"
  println "Sunset: ${rss.channel.astronomy.@sunset}"
  println "Currently:"
  println "\t" + rss.channel.item.condition.@date
  println "\t" + rss.channel.item.condition.@temp
  println "\t" + rss.channel.item.condition.@text
}else{
  println "USAGE: weather zipcode"
}

//sortie:
Yahoo! Weather - Broomfield, CO
Sunrise: 6:36 am
Sunset: 5:50 pm
Currently:
   Fri, 27 Feb 2009 7:47 am MST
   25
   Partly Cloudy

Vous avez vu comme il parait naturel de travailler avec XML en utilisant XmlSlurper ? Vous affichez l'élément <title> en y faisant directement référence - rss.channel.title. Vous traitez l'attribut temp avec un simple rss.channel.item.condition.@temp. On n'a pas l'impression de programmer, mais de travailler directement avec le XML.

Avez-vous remarqué que XmlSlurper ignore même les espaces de noms ? On peut activer la prise en compte des espaces de noms dans le constructeur, mais je le fais rarement. Par défaut, XmlSlurper permet de manipuler XML avec une facilité déconcertante.

Conclusion

Pour être un développeur efficace à notre époque, il est nécessaire d'avoir des outils qui rendent aisée l'utilisation de XML. Les MarkupBuilder et StreamingMarkupBuilder de Groovy font que créer du XML à la volée est une sinécure. XmlParser est parfait pour manipuler des Lists d'Elements et des HashMaps d'Attributes, et XmlSlurper fait disparaitre complètement le code, vous laissant l'agréable illusion que vous travaillez directement sur le XML.

Une bonne partie de cette puissance dans le traitement du XML serait impossible sans les possibilités dynamiques de Groovy. Dans le prochain article, nous explorerons plus en détail la nature dynamique de Groovy. Vous apprendrez comment fonctionne la métaprogrammation avec Groovy, depuis les sympathiques méthodes ajoutées aux classes standard du JDK (comme String.toURL() et List.each()) jusqu'aux méthodes personnalisées que vous ajouterez vous-mêmes. En attendant, j'espère que vous trouverez beaucoup d'utilisations pratiques de Groovy.