David Madore's WebLog: Comment travailler sur du XML en conservant le formatage ?

[Index of all entries / Index de toutes les entréesLatest entries / Dernières entréesXML (RSS 1.0) • Recent comments / Commentaires récents]

↓Entry #2246 [older| permalink|newer] / ↓Entrée #2246 [précédente| permalien|suivante] ↓

(lundi)

Comment travailler sur du XML en conservant le formatage ?

Je ne suis certainement pas le premier à me poser cette question, et ça m'étonnerait un peu qu'il n'y ait pas déjà une solution, mais je ne trouve pas — il faut dire que je ne sais pas bien quoi chercher comme mots-clés.

Voici mon problème :

J'ai des fichiers XML que je voudrais traiter avec des outils XML, par exemple appliquer une feuille de style XSLT (qui laissera la grande majorité du document inchangé, se contentant d'ajouter des attributs ici ou là, ou peut-être quelques balises). Néanmoins, je voudrais préserver, dans la mesure du raisonnable, le formatage du document d'origine : par formatage dans cette phrase, je veux dire la manière dont les balises et les attributs sont écrits/sérialisés (par exemple, <foo color="blueish" price="expensive" /> et <foo price='expensive' color='blueish'/> sont deux formatages différents de la même balise, de même que des changements possibles du whitespace, et plus généralement tout ce qui conduit au même XML canonique — on peut d'ailleurs considérer ça comme la définition du formatage : deux documents XML diffèrent uniquement par le formatage lorsqu'ils ont le même XML canonique). Concrètement, je veux que le diff de mon document après traitement (par une feuille de style XSLT qui ne change que quelques attributs ou balises) soit en gros aussi faible que possible avec celui avant traitement (parmi tous les formatages possibles de la sortie XML du traitement).

Éclaircissement/redite : Comme je semble avoir été mal compris, je vais essayer de redire différemment ce que je cherche à faire. Je ne cherche pas à reformater du XML, au contraire, je cherche à le modifier sans le reformater : je cherche à traiter du XML par des outils XML en changeant le moins possible le XML en sortie (et notamment, sans changer le formatage des balises qui n'auront pas du tout été modifiées). Concrètement, j'ai du XML écrit à la main, je veux faire des changements automatisés dessus tout en préservant les idiosyncrasies du formatage à la main (notamment : l'ordre des attributs, le whitespace dans les balises ouvrantes et fermantes, les sections CDATA, les entités, ou le fait d'écrire parfois certains caractères Unicode sous forme de références de caractères).

Y a-t-il des outils pour réaliser ça ?

Je pensais à l'idée suivante : inventer un namespace ad hoc qui sert à refléter le formatage XML. Autrement dit, partant d'un document XML sous un certain format texte, on aurait des outils qui ajoutent des attributs et balises de ce namespace servant à stocker tous les détails du formatage (l'ordre des attributs, le type de guillemets les représentant, le whitespace partout où il n'est pas significatif, etc.), et capables, inversement, d'interpréter (et retirer) ces attributs et balises pour recréer le document exactement tel qu'il était, même s'il a été reformaté entre temps (par exemple remplacé par son XML canonique). On pourrait alors travailler en trois étapes : ajouter les attributs et balises représentant le formatage, travailler avec XSLT sur le document ainsi enrichi (la feuille de style XSLT ignorerait typiquement les éléments de formatage), puis réappliquer le formatage sauvegardé dans les attributs et balises spécifiques (dans certains cas l'information de formatage serait incomplète ou non directement applicable, bien sûr, vu que des attributs ou balises ont pu être ajoutés, supprimés ou changés par le XSLT, mais le reformateur ferait « au mieux » dans un sens pas très important).

Ça ne doit pas être horriblement compliqué d'écrire des outils comme ça de sauvegarde/sérialisation et restauration/désérialisation du formatage, mais ça m'arrangerait de ne pas être celui qui invente la roue surtout si quelqu'un l'a fait avant moi. Quelqu'un connaît-il des choses dans ce sens ?

Ajout () : J'envisage essentiellement trois pistes pour résoudre mon problème :

  • La méthode générale exposée ci-dessus pourrait ressember à ceci : un premier outil transformerait le XML fourni en entrée en ajoutant des entités et éléments représentant sa syntaxe concrète. Par exemple <foo color='blueish' price='expensive'/> serait transformé en lui ajoutant un attribut ws:emptytag="&lt;foo color='blueish' price='expensive'/&gt;" servant à représenter la syntaxe concrète de la totalité de la balise sur une balise vide. Puis ce XML enrichi serait transformé par le XSLT. Enfin, un autre outil tenterait de réappliquer la syntaxe concrète, en vérifiant qu'elle correspond toujours à l'arbre XML (et en la supprimant dans le cas contraire) : du coup, par exemple, le XML canonique <foo color="blueish" price="expensive" ws:emptytag="&lt;foo color='blueish' price='expensive'/>"></foo> serait retransformé en <foo color='blueish' price='expensive'/> (grâce à la valeur de l'attribut ws:emptytag) tandis que s'il a été transformé, disons, en <foo color="blueish" price="inexpensive" ws:emptytag="&lt;foo color='blueish' price='expensive'/>"></foo> (par changement d'un attribut) alors il deviendrait simplement <foo color="blueish" price="expensive"></foo> (en supprimant purement et simplement l'attribut ws:emptytag qui n'a plus la bonne valeur).
  • Une deuxième approche consisterait à essayer simplement de faire des modifications avec perl, mais en ayant marqué les emplacements à modifier avec des outils XML. Voici donc une question plus simple que ma question générale ci-dessus : y a-t-il des outils qui permettent, donné un fichier XML et une expression XPath, de retourner le numéro de ligne (et éventuellement le numéro de colonne dans la ligne) où commence (la syntaxe concrète de) l'élément désigné par le XPath ? (Il y a une question apparentée par exemple ici. Je suppose que je dois pouvoir m'en sortir en construisant l'arbre DOM avec un parseur SAX et en annotant chaque élément par son numéro de ligne.)
  • Une troisième approche, qui est certainement la plus simple, mais évidemment aussi la moins générale : canoniser mon document XML, appliquer la transformation XSLT sur le document canonisé (et canoniser la sortie), faire le diff entre les deux, et essayer d'appliquer ce patch au fichier XML de départ, en priant pour qu'il s'applique sans mal (ce qui, pour ce que je veux faire, est tout de même hautement probable).

J'avais réfléchi à plusieurs occasions à ce problème et à des questions adjacentes, et je m'étais dit qu'il faudrait développer une petite théorie formelle des encodages, réencodages et transcodages de l'information : notamment, je pense que le théorème de Cantor-Schröder-Bernstein a son mot à dire dans l'histoire du round-trip encoding (je rappelle qu'il s'agit du théorème qui affirme que si on a une injection f:AB et une injection g:BA dans des sens opposés entre deux ensembles, alors on a une bijection entre A et B), et que sa démonstration (constructive !) pourrait fournir des conventions en la matière. (Je ne prétends pas qu'il s'agisse du même problème que celui évoqué ci-dessus, mais qu'il s'agit de problématiques du même genre ; on pourra par exemple réfléchir à la question suivante : si j'appelle f la fonction qui envoie tout arbre (DOM) XML abstrait sur son XML canonique, et g la fonction qui envoie un document texte sur l'arbre DOM XML qui a une unique balise text contenant tout le texte, alors à quoi ressemble la bijection entre fichiers texte et arbres XML que produit une démonstration constructive standard du théorème de Cantor-Schröder-Bernstein à partir de ces deux injections ? Même question si on remplace g par une injection des documents XML bien-formés dans les arbres DOM XML obtenue en ajoutant des balises de formatage comme je le suggère ci-dessus.)

↑Entry #2246 [older| permalink|newer] / ↑Entrée #2246 [précédente| permalien|suivante] ↑

[Index of all entries / Index de toutes les entréesLatest entries / Dernières entréesXML (RSS 1.0) • Recent comments / Commentaires récents]