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 attributws:emptytag="<foo color='blueish' price='expensive'/>"
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="<foo color='blueish' price='expensive'/>"></foo>
serait retransformé en<foo color='blueish' price='expensive'/>
(grâce à la valeur de l'attributws:emptytag
) tandis que s'il a été transformé, disons, en<foo color="blueish" price="inexpensive" ws:emptytag="<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'attributws: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:A→B et une
injection g:B→A 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.)