Groovy est un langage particulièrement adapté lorsqu’il s’agit de traiter des fichiers plats. Pour rédiger le 500ème billet du blog, j’ai exporté au format WXR (WordPress eXtended RSS) l’ensemble des billets. Cela donne un gros fichier XML de 75 762 lignes que vous pouvez télécharger ici.

Lire un fichier XML avec Groovy

Pour ouvrir et lire un fichier XML avec Groovy, rien de plus simple. Il existe 2 classes principales : XmlSlurper et XmlParser. Aujourd’hui nous ne verrons que le premier.
La structure du fichier XML utilise le format WXR (WordPress eXtended RSS format). J’ai dû adapter et corriger quelques coquilles pour que le fichier puisse être parsé correctement.

Voyons tout d’abord comment lire un fichier XML en Groovy :

def file = new File("wordpress.2010-02-14.xml")
def root=new XmlSlurper().parse(file)

Plutôt simple non ?

Si nous prenons cette structure XML par exemple :

<rss version="2.0"
	xmlns:excerpt="http://wordpress.org/export/1.0/excerpt/"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:wp="http://wordpress.org/export/1.0/"
>

<channel>
	<title>Le Touilleur Express</title>
        ...
        <item>
            // un article
        </item>
        <item>
            // un article
        </item>
</channel>
</rss>

L’accès à un attribut est très simple en Groovy. Voici comment afficher le titre du blog et comment afficher le nombre d’items de la balise channel:

def file = new File("wordpress.2010-02-14.xml")
def root=new XmlSlurper().parse(file)

println "Blog title : "+root.channel['title']

println "Number of RSS items : "+root.channel.item.size()

nicolas@localhosr> groovy readXml.groovy
Blog title : Le Touilleur Express
Number of RSS items : 805

Itérer des noeuds

L’itération des noeuds XML s’effectue à l’aide de closure. La structure RSS de l’ensemble des articles est construite autour du noeud « item ». WordPress y ajoute un ensemble d’attributs, ce qui permet de distinguer les articles publiés des brouillons, de distinguer les images téléchargées des pages, etc.

Prenons cet exemple de code :

def file = new File("wordpress.2010-02-14.xml")
def root=new XmlSlurper().parse(file)

root.channel.item.each{it->
	if(it.post_type.text().equals("post")){
		if(it.status.text().equals("publish")){
			println (it.title.text(),"UTF-8")
		}
	}
}

L’élément CHANNEL est constitué d’une collection d’ITEM. Pour chacun de ces ITEMs je récupere la valeur de l’attribut TITLE. Enfin l’accesseur text() permet de récupérer le titre de l’article du Touilleur Express.
Le format d’entrée est UTF-8. Lors de l’exécution sur Mac, l’encoding de la plateforme étant par défaut MacRoman, les caractères accentués entre autre ne sont pas correctement affichés. Nous verrons tout à l’heure comment spécifier le format de sortie.

Générer un nouveau fichier au format HTML

Maintenant que vous savez lire un fichier XML, itérer des noeuds, pouvez-vous m’écrire quelques lignes pour générer une page HTML avec la liste des articles, un lien vers l’article et la date de publication ?

Voici le fichier d’entrée :

<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:excerpt="http://wordpress.org/export/1.0/excerpt/"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:wp="http://wordpress.org/export/1.0/"
>

<channel>
	<title>Le Touilleur Express</title>
		<item>
			<title>Article classique</title>
			<wp:post_type>post</wp:post_type>
			<wp:status>publish</wp:status>
			<link>http://www.touilleur-express.fr/2003/11/22/pourquoi-java-sappelle-java/</link>
			<pubDate>Sat, 22 Nov 2003 09:28:40 +0000</pubDate>
		</item>
		<item>
			<title>Article de brouillon</title>
			<wp:post_type>post</wp:post_type>
			<wp:status>draft</wp:status>
			<link>http://www.touilleur-express.fr/</link>
			<pubDate>Sat, 22 Nov 2003 09:28:40 +0000</pubDate>
		</item>
		<item>
			<title>Page wordpress</title>
			<wp:post_type>page</wp:post_type>
			<wp:status>publish</wp:status>
			<link>http://www.touilleur-express.fr/</link>
			<pubDate>Sat, 22 Nov 2003 09:28:40 +0000</pubDate>
		</item>
	</channel>
</rss>

Votre script Groovy doit parser le fichier XML ci-dessus, et générer ce fichier HTML :

<html>
<head>
<title>Le Touilleur Express articles</title>
<meta http-equiv='Content-Type' content='text/html; charset=UTF-8'/>

<body>
<a href='http://www.touilleur-express.fr/2003/11/22/pourquoi-java-sappelle-java/' target='new'>Article classique</a> publié le Sat, 22 Nov 2003 09:28:40 +0000<br/>

</body>
</html>

Allez au boulot, à vous de travailler. Je vous posterai la réponse un peu plus tard.

3 réflexions sur « Traitement du XML en Groovy »

  1. Woops, ça ne le fait pas du tout les balises html dans les commentaires 🙁

    Désolé pour le spam, j’essaye de reposter en échappant les balises :

    Salut !

    Je débute en groovy, mais voilà comment j’aurais fait :
    (mais il y a surement plus groovy …)

    
    def file = new File("/home/raf/test.xml")
    def root=new XmlSlurper().parse(file)
    
    def title = root.channel['title']
    
    println "<html>"
    println "<head>"
    println "<title> $title articles </title>"
    println "<meta  http-equiv='Content-Type' content='text/html; charset=UTF-8'/>\n"
    println "<body>"
    
    // Les articles
    root.channel.item.each{it->
        if(it.post_type.text.equals("post")){
            if(it.status.text.equals("publish")){
                href = it.link
                title = it.title
                date = it.pubDate
                println "<a href='$href' target='new'>$title</a> publié le $date</br>"
            }
        }
    }
    
    println "</body>"
    println "</html>"
    
  2. C’est pas du très beau code mais cela devrait faire l’affaire (in.xml contient évidemment le xml proposé en entrée) :

    
    import groovy.xml.MarkupBuilder
    
    def file = new File("in.xml")
    def root=new XmlSlurper().parse(file)
    
    def writer = new StringWriter()
    def xml = new MarkupBuilder(writer)
    
    xml.html {
        head {
            title('Le Touilleur Express articles')
            meta("http-equiv":'Content-Type', content:'text/html; charset=UTF-8')
        }
        body {
            root.channel.item.each{currentItem->
                    if(currentItem.post_type.text().equals("post")){
                            if(currentItem.status.text().equals("publish")){
                                    a(href:currentItem.link.text(), target:'new', currentItem.title.text())
                                    mkp.yield(' publié le ' + currentItem.pubDate.text())
                                    br()
                            }
                    }
            }
        }
    }
    
    println writer.toString()
    
  3. @Stephane ta technique est la plus groovy, celle de Raphael est légèrement plus rapide. Bravo les gars !

Les commentaires sont fermés.