Première rédaction de cet article le 9 octobre 2006
Dernière mise à jour le 19 novembre 2008
On trouve sur le Web beaucoup plus de textes expliquant comment analyser du XML que de textes expliquant comment le produire depuis un programme. D'un côté, c'est logique : produire le XML est bien plus facile et ne mérite pas forcément de longues documentations. D'un autre côté, cela pousse certains programmeurs à ne pas faire attention et à écrire des programmes qui finissent par produire du XML mal formé.
La méthode la plus évidente pour produire du XML est d'exploiter le fait que XML est un format basé sur le texte et d'écrire donc simplement (les exemples ici sont en Python et en C mais le raisonnement est valable pour tous les autres langages de programmation) :
print "<foo>%i</foo>" % val
Cela fonctionne, mais cela présente plusieurs inconvénients :
print "<foo>%i<foo>" % val
passera inaperçu si on ne vérifie pas le XML produit (ce
qui serait de toute façon une très bonne idée).
val
est
%i
, ce qui se limite aux nombres. Mais si c'était
%s
, qui permet n'importe quelle chaîne de
caractères, on pourrait avoir des problèmes si la chaîne contenait un
caractère utile à XML comme le <
ou bien un
caractère non ASCII qu'il faudrait penser à
encoder proprement, en conformité avec la déclaration XML.Il est donc en général préférable de produire le XML à partir d'une structure de donnés de plus haut niveau que la chaîne de caractères. Une méthode évidente est d'utiliser DOM, ici pour produire du XHTML :
from xml.dom.ext.reader import Sax2 from xml.dom.ext import PrettyPrint from xml import xpath from xml.dom import getDOMImplementation ... blurb = u"<attention aux caractères spéciaux" ... html_result = getDOMImplementation().createDocument( None, "html", getDOMImplementation().createDocumentType( "html", "-//W3C//DTD XHTML 1.0 Strict//EN", "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd")) head = html_result.documentElement.appendChild(html_result.createElement('head')) title = head.appendChild(html_result.createElement('title')) title.appendChild(html_result.createTextNode("My site: %s" % \ (blurb))) ... PrettyPrint(html_result)
On crée un mémoire un arbre DOM et on l'affiche avec
PrettyPrint
. Par construction, il sera bien formé
(mais pas forcément valide). Et DOM se chargera de l'échappement des
caractères spéciaux XML. Les caractères non-ASCII seront proprement
représentés (PrettyPrint
semble imposer
UTF-8 en sortie mais d'autres méthodes DOM
comme toprettyxml()
permettent d'autres
représentations).
DOM n'est pas très pythonien. Cette norme
est en effet conçue pour être indépendante du langage de programmation
utilisé et certaines constructions sont donc plutôt déroutantes en
Python, par exemple, pour créer un simple attribut, ici
href
:
link = html_result.createElement("a") url = html_result.createAttribute("href") url.nodeValue = "http://www.ietf.org/rfc/rfc%i.txt" % int(rfcnum) link.setAttributeNode(url) link.appendChild(html_result.createTextNode("RFC %i" % int(rfcnum)))
.
ElementTree peut donc être préféré. ElementTree, désormais intégré à la bibliothèque standard de Python, permet de manipuler (lire et écrire) du XML de manière plus pythonesque et donc plus natutrelle au programmeur Python. En contrepartie, il n'a rien de standard, contrairement à DOM et il faudra donc tout réapprendre si on passe à un autre langage comme Perl.
Voici un exemple analogue en ElementTree :
blurb = u"<attention aux caractères spéciaux" import elementtree.ElementTree as ET html = ET.Element("html") head = ET.SubElement(html, "head") title = ET.SubElement(head, "title") title.text = "Mon site: %s" % blurb body = ET.SubElement(html, "body") link = ET.SubElement(body, "a") link.text = "Internet Engineering Task Force" link.attrib["href"] = "http://www.ietf.org/" print ET.tostring(html, encoding="UTF-8") # elementtree.SimpleXMLWriter is an alternative, if we just want to # write the XML. See http://effbot.org/zone/xml-writer.htm
Il existe bien sûr d'autres méthodes (par exemple, pour Python) mais je crois avoir déjà couvert trois possibilités intéressantes.
Et pour C ? Voici un
exemple avec la libxml. On
n'utilise pas une seule fois la syntaxe XML, c'est la routine
xmlDocDumpFormatMemory
qui se chargera de
produire du XML légal :
#include <libxml/parser.h> int main(void) { xmlNodePtr root, node; xmlDocPtr doc; xmlChar *xmlbuff; int buffersize; /* Create the document. */ doc = xmlNewDoc(BAD_CAST "1.0"); root = xmlNewNode(NULL, BAD_CAST "root"); /* Create some nodes */ node = xmlNewChild(root, NULL, BAD_CAST "node", NULL); node = xmlNewChild(node, NULL, BAD_CAST "inside", NULL); node = xmlNewChild(root, NULL, BAD_CAST "othernode", NULL); /* Put content in a node: note there are special characters so encoding is necessary! */ xmlNodeSetContent(node, xmlEncodeSpecialChars(doc, BAD_CAST "text con&tent and <tag>")); xmlDocSetRootElement(doc, root); /* Dump the document to a buffer and print it for demonstration purposes. */ xmlDocDumpFormatMemory(doc, &xmlbuff, &buffersize, 1); printf((char *) xmlbuff); }
Compilé avec gcc -Wall -I/usr/include/libxml2 -c create-xml.c && gcc -lxml2 -o create-xml create-xml.o
, ce programme va afficher :
% ./create-xml <?xml version="1.0"?> <root> <node> <inside/> </node> <othernode>text con&tent and <tag></othernode> </root>
Un programme C qui produit du XML plus complexe ? Il y a par exemple mon implémentation du RFC 5388.
Version PDF de cette page (mais vous pouvez aussi imprimer depuis votre navigateur, il y a une feuille de style prévue pour cela)
Source XML de cette page (cette page est distribuée sous les termes de la licence GFDL)