L’humain, et le développeur en particulier, a une fâcheuse tendance à vouloir construire des choses compliquées qui supportent tous les cas d’utilisation possibles et imaginables. En fin de compte, cela conduit très souvent à des usines à gaz avec lesquelles même le plus simple des cas d’utilisation est difficile à mettre en œuvre. Le format de balisage XML en est une parfaite illustration.
XML est un langage de balisage qui permet d’écrire sous forme de texte des données structurées. XML est extensible – comme le rappelle son acronyme eXtensible Markup Language – dans l’objectif de repousser au maximum les limites de son domaine d’utilisation. C’est un langage très connu des développeurs. Il est énormément utilisé, même si sa popularité tend peu à peu à diminuer au profit d’autres langages de balisage plus simples.
Une complexité importante
Une lisibilité douteuse
En terme de lisibilité, XML n’est pas le format de représentation le plus lisible par un humain qu’on ait connu. Lorsqu’un document XML est écrit sans indentation et retour à la ligne, il n’est tout simplement pas lisible par un humain. Heureusement il existe de nombreux outils de formatage qui rendent de précieux services.
Après tout, on peut ne pas trop en tenir rigueur, la plupart du temps ce ne sont pas des humains qui lisent et écrivent des documents XML. Le principal finalement c’est que le format soit facilement lisible par du code. Malheureusement, on ne peut pas dire que ce soit le cas…
En effet, quand on essaie d’exploiter un document XML avec du code, les ennuis commencent vite. Il n’existe pas de manière de lire un document XML de manière indexée (je voudrais l’élément truc qui est dans l’élément bidule). On se retrouve à lire l’arbre DOM nœud par nœud. Pour corser le tout, il y a des nœuds qui sont des éléments et d’autres non. Il est souvent nécessaire de regarder le nom de la balise correspondant à un élément pour en connaître sa sémantique. Mais parfois il faut aller chercher la valeur d’un attribut, d’autres fois c’est le contenu de la balise. Bref, c’est compliqué. Et ça l’est encore plus lorsqu’on lit le document en SAX même si c’est l’acronyme de Simple API for XML.
De plus, XML est un format plutôt verbeux, notamment à cause du fait que le nom des balises est répété à l’ouverture et à la fermeture. Dans certains cas d’utilisation la verbosité n’a pas vraiment d’importance, mais lorsqu’il s’agit par exemple de web services qui envoient du XML à un téléphone connecté en 3G précaire, il est plutôt intéressant d’éviter tout caractère superflu. Heureusement que la compression du corps des requêtes en HTTP permet de rattraper plutôt bien le coup.
Des données structurées, oui mais à quel prix ?
XML est un format très ouvert qui propose une multitude de façons de représenter un même concept. Mais si on souhaite faire lire et écrire du XML à une machine, il faut impérativement fixer une structure. Pour ce faire il existe les DTD (Document Type Definition) qui permettent de définir la structure d’un document comme on décrirait une grammaire. Malheureusement, les DTD ne permettent pas de décrire des contraintes appliquées sur les valeurs des attributs et de contenu des balises. Pas de problème, il existe XSD qui remplace (presque) DTD ! D’accord, mais alors, DTD ou XSD ? D’ailleurs, est-ce vraiment utile d’associer un document à un schéma ? Définir la structure d’un document permet tout de même de simuler une sorte de typage statique et d’avoir par exemple une autocomplétion et une validation à la volée dans un IDE. Mais c’est cher payé. D’autant plus qu’on ne peut pas s’en servir pour documenter le format des documents, c’est trop difficile à lire par un humain.
De plus, un document XML est lié à son schéma par un identifiant, souvent sous la forme d’URL. Lorsqu’on lit un document on est tenté de vérifier sa validité en comparant sa structure par rapport au schéma qui est censé le décrire. On ne sait jamais vraiment si on doit le faire ou pas, sachant que ça peut coûter du temps. Surtout lorsque le parser doit aller récupérer ces fichiers sur le réseau. C’est d’ailleurs parfois problématique lorsque la machine est hors ligne puisqu’elle n’est pas à même de résoudre les schémas. Dites-donc, c’est pas un peut compliqué tout ça ?
Des outils pour simplifier
XML appartient à une grande famille. En dehors des outils de structuration de documents comme DTD ou XSD, il existe de nombreux outils qui permettent de travailler avec des documents XML.
Un des plus connus et également des plus populaire est XPath. Et en effet, on lui doit une fière chandelle, il rend de précieux services lorsqu’on a à lire ou plus généralement manipuler un document XML, surtout lorsque sa structure est un peu compliquée. Son expressivité assez puissante permet de cibler directement des éléments XML (nœuds, attributs, …) en écrivant une requête sous forme de chaîne de caractères. Cela évite de lire le document élément par élément dans du code. Même si XPath est un outil appréciable quand on fait du XML, je considère que son existence et sa popularité sont un aveu d’échec face à la complexité du format.
Il existe tout un tas d’autres outils qui gravitent autour de XML, certains étant plus utilisés que les autres. On peut citer par exemple XQuery qui est une sorte de XPath enrichi, mais qui semble être en concurrence avec XSLT qui lui est assez populaire.
Des espaces de noms pour en rajouter une couche
Si il n’y avait que ce que j’ai décrit jusqu’à présent, XML ne serait pas un si mauvais langage de description. Mais c’est sans compter sur les espaces de noms qui rajoutent une importante couche de complexité, celle-ci étant d’ailleurs assez transverse parce qu’elle concerne XML lui-même mais aussi plein d’autres outils comme XPath.
En gros les espaces de noms permettent de classer les éléments XML dans différentes familles qu’on pourrait appeler vocabulaires. L’idée étant d’éviter les conflits de nommage lorsqu’on mixe différents vocabulaires, par exemple si deux vocabulaires utilisés dans un même document ont une balise qui porte le même nom, les espaces de noms permettent de leur donner une sémantique différente.
Heureusement il n’est pas obligatoire d’utiliser les espaces de noms, un espace de noms par défaut est utilisé si rien n’est précisé. Je ne sais pas si c’est pour se protéger, mais les espaces de noms sont très fréquemment utilisés. Et là c’est assez vite pénible. Il faut préciser l’espace de noms lorsqu’on crée un élément et faire attention qu’il soit correct lorsqu’on lit un élément. C’est encore plus douloureux lorsqu’on écrit des expressions XPath.
<ns:root xmlns:ns="urn:hello:world"> <ns:element>Hello world</ns:element> </ns:root>
En prenant ce morceau de XML en exemple et souhaitant écrire le XPath permettant d’accéder à Hello world, on a tendance à penser spontanément que l’expression suivante suffit : /root/element/text(). Mais c’est sans compter sur ce satané espace de noms. Il faut le préciser dans l’expression XPath, comme ceci : /ns:root/ns:element/text(). Mais attention, cela ne fonctionne pas si on n’indique pas en parallèle de cette expression les espaces de noms utilisés ainsi que leurs préfixes. ns n’est ici qu’un préfixe, un nom qu’on lui donne à l’intérieur du document XML pour simplifier l’écriture mais qui n’a aucune signification sémantiquement parlant ; il représente son espace de noms. C’est la raison pour laquelle il faut à nouveau déclarer les espaces de noms utilisés en plus de l’expression XPath. Ce qui est juste pénible pour un développeur qui en a l’habitude est une horreur pour celui qui n’est pas familier avec tous ces concepts.
Mais au fait, ça sert à quoi les espaces de noms ? A-t-on vraiment besoin de mixer plusieurs vocabulaires dans un même document ? Vraiment ? Personnellement je ne l’ai jamais fait et ça ne m’a jamais manqué.
Des fondations parfaites pour une usine à gaz
Il existe tout un tas de technologies basées sur XML. Beaucoup sont au moins aussi compliquées que XML. Je pense à SOAP par exemple. J’ai récemment intégré une authentification via le protocole SAML et là encore on se demande pourquoi ils ont encore fait une usine à gaz alors qu’il existe en face des alternatives tellement simples (OAuth par exemple). Il en va de même pour SKOS et plus généralement RDF XML. Décidément, le W3C et OASIS sont passés maîtres en conception d’usines à gaz. Pourquoi tant de haine envers les développeurs ?
Support dans les différents langages
La complexité de XML et des outils qui l’entourent fait qu’il existe peu d’implémentations qui supportent l’ensemble des spécifications.
Python en est une parfaite illustration. La documentation de l’API XML fournie dans le SDK indique par exemple que le support de XPath n’est pas complet. C’est ainsi que les développeurs utilisent fréquemment lxml qui n’est autre qu’une surcouche à libxml2 écrite en C, une des rares implémentations complètes de XML. Cette page présente les différences et surtout les apports de lxml par rapport à l’API de base. Dommage d’être obligé de passer par une librairie native…
Dans un contexte différent qu’est le monde du web, le support de XML est très peu complet dans les navigateurs. C’est pourtant paradoxal parce que les navigateurs savent parfaitement manipuler du HTML. Même si certains navigateurs ont un support assez correct des fonctionnalités de base de XML, d’autres ne supportent par exemple pas les espaces de noms dans les expressions XPath. La morale c’est qu’en Javascript dans un navigateur il faut oublier l’utilisation de XML.
Malgré tout utile parfois
Pour ne pas dire que du mal de ce format, il est clair que la liberté qu’il offre est bien pratique dans certains contextes. C’est par exemple le cas dans la modélisation d’une page web, qui utilise les mêmes concepts DOM même si il s’agit d’un langage et d’une syntaxe légèrement différente. On est bien contents de pouvoir écrire le code suivant :
<p>Du texte <strong>en gras</strong> et <em>en italique</em></p>
Dans cet exemple, le paragraphe contient une succession de texte et de balises. C’est quelque chose qui est naturel en XML / HTML mais qui ne l’est pas forcément dans d’autres formats. Malheureusement, même si c’est facile et pratique à écrire, ça l’est nettement moins à lire pour le navigateur par exemple, et ce n’est pas plus facile lorsqu’on souhaite modifier un arbre DOM en Javascript. C’est d’ailleurs la raison d’être de jQuery qui vient de manière très élégante et puissante masquer une bonne partie de la complexité du DOM.
Des formats alternatifs
Il existe de nombreux formats alternatifs permettant d’apporter des solutions simples et adaptés à différents cas d’utilisation. En voici quelques uns.
JSON
Si les données qu’on cherche à sérialiser ne sont lues et écrites que par des machines, JSON est sans doute le format le plus adapté aujourd’hui. C’est d’ailleurs un format très populaire, et notamment dans le monde du web dont il est originaire (son nom est l’acronyme de JavaScript Object Notation).
JSON a la particularité d’être très facile à manipuler via du code. JSON est issu de la syntaxe de représentation de données en Javascript, il est donc calqué sur des concepts qui sont les bases de la programmation. Un document JSON est en effet un arbre composé de scalaires (nombres, chaînes de caractères, …), de collections et d’objets. Cette structure proche des paradigmes de programmation rend d’ailleurs très accessible la possibilité de sérialiser et désérialiser directement des structures de données comme des classes en orienté objet, ceci de manière automatique. C’est par exemple ce que propose Jackson en Java.
XML est accompagné de nombreux outils tels que XPath ou XSLT. On ne peut pas dire que ce soit le cas de JSON. En fait, sa simplicité fait que ces outils ne sont pas nécessaires. Il existe JsonPath qui est le XPath de JSON, mais il est très peu utilisé, simplement parce qu’il est facile de lire un document JSON avec un langage de programmation. Son utilité principale est de décrire le chemin qui mène à une valeur pour l’externaliser par exemple dans une configuration. De la même manière, un équivalent de XSLT n’est pas vraiment nécessaire. Modifier un document JSON est même d’une simplicité enfantine avec un langage dynamique comme Javascript ou Python. Aussi, en JSON, la notion de schéma (XSD ou DTD) n’existe pas de manière officielle et elle ne manque vraiment pas.
JSON est nettement moins verbeux que XML grâce à une syntaxe plus compacte. En revanche, comme en XML, un gros fichier JSON peut être très difficile à lire par un humain, surtout si il est écrit sans indentation dans un souci de compacité. Heureusement, il existe de nombreux outils aidant à la lecture du JSON.
YAML
Dans les cas où il s’agit de partager des données entre des humains et des machines et donc que la lisibilité a une vraie importance, YAML est une bonne alternative à JSON. Ils partagent avec JSON les mêmes concepts et la même structure. YAML propose en revanche une syntaxe bien plus visuelle dans laquelle l’indentation et les retours à la ligne ont une véritable importance, de manière assez similaire à la syntaxe de Python. Ce langage de description est particulièrement adapté pour les fichiers de configuration qui visent à représenter des données ayant une structure complexe.
Et bien d’autres
Il existe bien d’autres formats. Pour des fichiers de configuration très simples (clés-valeurs par exemple), certains formats comme ini ou properties de Java sont aussi à considérer.
Conclusion
Bien qu’étant encore beaucoup utilisé, c’est un langage à éviter absolument compte-tenu de sa forte complexité. Il est intéressant à tout point de vue d’utiliser des formats alternatifs qui sont bien plus simples et tout aussi supportés en terme d’outillage. XML a fait souffrir de nombreux développeurs et cela continuera tant qu’il sera utilisé.
Il se pourrait que quelques inexactitudes se soient glissées dans mes propos. Je connais les bases de XML mais c’est une technologie que je suis loin de maîtriser. J’ai évité tant que possible de m’en servir. Et même en l’utilisant tous les jours je ne sais pas si on peut vraiment le maîtriser. Dans tous les cas, on ne devrait pas pouvoir maîtriser que partiellement un langage de formatage de données, présenter des données n’étant pas une problématique compliquée. C’est une preuve de plus de sa trop grande complexité.
Les concepteurs du format ne sont cependant pas les seuls coupables dans cette histoire. Ils ont créé une usine à gaz. Certes. Mais nous, développeurs, sommes autant fautifs de l’avoir utilisé pour des fichiers de configuration par exemple.
Je termine cet article par cette phrase, habituellement utilisée pour les expressions régulières, mais qui convient également parfaitement à XML :
Si vous essayez de régler un problème avec XML vous finirez avec deux problèmes.
L’image d’en-tête provient de Flickr.
Benoit, je t’ai connu plus précis 🙂
Loin de moi la volonté d’aller à contre-courant, XML a bien des défauts, j’en conviens. Par contre, je veux te challenger un peu sur certains points où je trouve que tu prends des GROS raccourcis (l’avocat du diable :)):
– « Il n’existe pas de manière de lire un document XML de manière indexée (je voudrais l’élément truc qui est dans l’élément bidule). On se retrouve à lire l’arbre DOM nœud par nœud. »
en quoi ecrire quelque chose comme:
for truc_node in root.xpath(« //bidule/truc »):
do something with truc_node
est-il un problème? Je n’ai pas parcouru du DOM.
– « Il est souvent nécessaire de regarder le nom de la balise correspondant à un élément pour en connaître sa sémantique. »
Je ne te suis pas, en SQL il faut bien lire le nom de la colonne pour comprendre ce qu’elle fait? En JSON, il faut bien lire le tag pour comprendre ce qu’il fait? En quoi est-ce particulier en XML?
– « il faut aller chercher la valeur d’un attribut, d’autres fois c’est le contenu de la balise »
Ok avec ça, les attributs ça n’aide pas 🙂
– « c’est compliqué. Et ça l’est encore plus lorsqu’on lit le document en SAX »
La je en suis pas d’accord, avec du XML écrit intelligemment, un parseur SAX , par sa conception à base d’événements, peut être redoutable d’efficacité. Tous les XML ne se traitent pas efficacement en SAX, il faut choisir le bon outils pour le bon XML. Si on choisit une tenaille pour enfoncer un clou, C’est certain qu’on se s’aide pas , mais ça ne rend pas la tenaille complexe 🙂
– « XML est un format plutôt verbeux, notamment à cause du fait que le nom des balises est répété à l’ouverture et à la fermeture. »
OK! 🙂 Avec toutes tes raisons de reseau également, imparable.
– Pour la structure, tu prend encore des raccourcis. XSD ou DTD sont optionelles. On est pas obligé d’en faire et c’est facile de désactiver l’auto-validation. Pour garantir la validité d’un flux pour un intégrateur, fournir une DTD/XSD est un atout. Exemple, j’ai des souvenirs d’un WebService qui s’appelait « search » (ca te parle? ;)) dont régulièrement le JSON en sortie changeait, et on ne s’en rendait compte qu’en intégration. Pour la sortie XML, un test unitaire passait les XSD et validait le flux. Pour moi, c’est un avantage indéniable pour le XML sur ce point. D’autre part pour l’aspect hors-ligne, les catalogues XML sont là pour ça:
http://en.wikipedia.org/wiki/XML_Catalog
– Les espace de noms, j’admet c’est complexe. Ca part du bon principe d’un nom de package permet d’éviter les conflits de nommage. Je peux faire un exemple pire que le tien:
<ns:root xmlns:ns="urn:hello:world">
<element xmlns="urn:ns:rule">
<ns:text xmlns:ns="urn:yet:another">Hello world</ns:text>
</element>
</ns:root>
Bon courage pour parser celui-là…
– « Mais au fait, ça sert à quoi les espaces de noms ? A-t-on vraiment besoin de mixer plusieurs vocabulaires dans un même document ? Vraiment ? Personnellement je ne l’ai jamais fait et ça ne m’a jamais manqué. »
Ca arrive régulièrement dans le Web Semantique (hybride RDF/SKOS/OWL). Ca peut servir dans les WebServices à « container » qui servent des données non-maitrisées (exemple, un WebService avec un ns « afs » contenant du html, du RDF, etc.). DocBook s’en sert, c’est un aggregat de plusieurs normes. Je vois les ns comme des bibliothèques des langages type Java/Python (j’utilise le modèle d’image de OAI, les labels de SKOS, la structure de DocBook, etc.).
D’autre part, dans le cadre du LinkedData où les données connectées sont vraiment nombreuses, la désambiguïsation apportée me semble importante.
Mais ok pour les bannir sur des petits usages non exposés.
– « Il existe tout un tas de technologies basées sur XML. […] Il en va de même pour SKOS et plus généralement RDF XML. »
Argh… SKOS et RDF sont des modèles de graphes mathématiques. L’une des sérialisations possibles est le XML, parmi d’autre (N3, turtle,etc.). Même JSON http://en.wikipedia.org/wiki/JSON-LD
Tu peux penser que le modèle de graphe RDF est une usine à gaz, mais c’est un autre débat. Tu peux aussi penser que la façon dont a été décidé de sérialiser en XML le RDF est une usine à gaz, c’est aussi un autre débat.
– « Il se pourrait que quelques inexactitudes se soient glissées dans mes propos. Je connais les bases de XML mais c’est une technologie que je suis loin de maîtriser. »
Je prend ça pour autorisation à mon commentaire 🙂
– « Les concepteurs du format ne sont cependant pas les seuls coupables dans cette histoire. Ils ont créé une usine à gaz. Certes. Mais nous, développeurs, sommes autant fautifs de l’avoir utilisé pour des fichiers de configuration par exemple. »
Dans un contexte historique d’il y a 15 ans, je pense là encore que tu prends un raccourci :). Mais OK pour dire *qu’actuellement* il y a d’autres alternatives pour la configuration et certaines pour le Web.
Merci pour ton billet, au plaisir de te lire 😉
Salut Laurent. J’ai mis du temps à répondre, je suis très occupé en ce moment et la lecture de ton commentaire à peu près aussi long que l’article m’a pris un peu de temps 🙂 En tout cas je m’attendais à une réponse de ta part sur un sujet qui fait partie de ton domaine d’expertise.
Pour les points 1 et 2, je voulais simplement dire qu’il faut utiliser XPath pour lire un document. Sans ça c’est vraiment pas cool parce que tu n’as pas un accès indexé, d’où l’histoire de devoir regarder le nom de la balise.
Pour SAX, j’en ai très peu fait, mais le fait de devoir faire une machine à état n’est pas souvent signe de simplicité. Ceci dit, je vois ce que tu veux dire quand tu parles de certains documents qui ont une structure appropriée.
Pour la structure avec DTD ou XSD, dans certains cas je pense que ça a en effet un intérêt. Mais c’est quand même pas simple tout ça. Il existe effectivement les catalogues mais ça complique encore un peu…
Pour ce qui concerne les espaces de nom, ton exemple est en effet encore plus vicieux que le mien… Il y a vraiment des gens qui font ça ?
Pour le RDF, je parlais bien de RDF XML, soit le format d’exportation en XML du RDF. Pour SKOS, c’est également à SKOS XML que je faisais référence. J’en ai de très mauvais souvenirs. Heureusement que c’est Sesame qui s’en occupait, mais à l’œil ça n’avait rien de joli. J’ai dû écrire des XPath pour lire des valeurs dans une export XML d’un triple store (si ça te rappelle quelque chose), je me souviens d’en avoir bavé pour trouver comment accéder à la valeur qui m’intéressait.
Comme je l’ai dit je suis mauvais en XML et donc tout n’est pas juste, et merci pour tes retours qui viennent rétablir un peu de vérité. J’accepte bien évidemment tous les commentaires !
Et sinon tu as bien raison sur l’aspect historique du XML. Il y a 10 ans il n’y avait pas grand chose d’autre pour structurer les données. Quoi qu’il en soit, aujourd’hui, il me semble nécessaire de bien se poser la question avant de choisir XML.
Merci pour tes retours. J’ai au moins un lecteur assidu !
Je suis entièrement d’accord avec l’article !
Je ne suis pas un expert en programmation mais au boulot, on encense XML et je n’ai jamais compris pourquoi… on me dit qu’il y a plein d’outils pour traiter/parser de l’XML, mais alors avec quelle lourdeur pour récupérer/écrire un champ ou une valeur !!!