3 Techniques et outils de transformation explicite

Nous présentons dans ce chapitre les techniques de transformation nécessitant une spécification additionnelle aux structures et aux instances de documents. Ces techniques regroupent les filtres qui utilisent une spécification implicite de la transformation et les systèmes de transformation explicites qui interprètent un ensemble de directives servant à paramétrer les transformations. Ces deux familles de transformations sont regroupées dans ce chapitre car il existe des similarités entre les techniques utilisées, comme on le verra plus loin.

La première section présente un exemple de transformation simple qui nous permet d'illustrer les techniques de transformation étudiées. Nous abordons ensuite les filtres de conversion, puis nous détaillons les systèmes de transformation explicite existant avant de présenter les transformations utilisées par Amaya.

3.1 Un exemple de transformation

Pour illustrer les différentes techniques de conversion, nous utiliserons un exemple de transformation de document structuré. Cet exemple nous sert dans ce chapitre à montrer la syntaxe utilisée. Il nous sert également à mettre en valeur les limites et les points forts de certains systèmes de transformation.

Nous avons choisi un exemple à la fois simple et représentatif de l'ensemble des transformations de documents structurés. Il met en oeuvre les opérations de transformation décrites dans le chapitre précédent (structuration, déplacement d'éléments, suppression et insertion de niveaux de structure, changement de type).

Cet exemple reprend la DTD mail présentée au chapitre précédent (et rappelée dans la figure 12) qui décrit la structure générique d'un message électronique. Un document mail (figure 13) comprend les éléments recipient, sender, subject et textbody correspondant respectivement aux destinataire, expéditeur, sujet et contenu du message. Le contenu est composé d'une suite de paragraphes eux-mêmes composés de texte et de citations identifiées par l'élément cite. L'élément mail porte l'attribut ref défini dans la DTD qui peut être utilisé par les applications pour référencer le message.

<!ELEMENT mail          (date, recipient, sender,
                         subject, textbody) >
<!ELEMENT date          (#PCDATA)           >
<!ELEMENT recipient     (#PCDATA)           >  
<!ELEMENT sender        (#PCDATA)           >
<!ELEMENT subject       (#PCDATA)           >
<!ELEMENT textbody      (p)+                >
<!ELEMENT p             (#PCDATA | cite)*   > 
<!ELEMENT cite          (#PCDATA)           >
<!ATTLIST mail    ref   CDATA   #REQUIRED  >   

Figure 12 - La DTD XML des documents mail

<mail ref="sb332">
 <date>30-07-1998</date>
 <recipient>Cecile.Roisin@inrialpes.fr</recipient>
 <sender>Stephane.Bonhomme@inrialpes.fr</sender>   
 <subject>littérature XML</subject>
 <textbody>
  <p>Bonjour Cécile,</p>
  <p>As-tu lu <cite>SGML, Java and the Future of the
Web</cite></p>
  <p>Stéphane.</p>
 </textbody>
</mail>

Figure 13 - Un document mail

Notre exemple consiste à transformer le document mail de la figure 13 en un document message dont la structure générique est décrite par la DTD de la figure 14. Les deux DTD diffèrent sur les 6 points suivants :

  1. Tous les noms des éléments changent entre les deux DTD.
  2. L'élément cite de la DTD mail n'a pas d'équivalent dans la DTD message, mais il doit être transformé sous forme d'un texte mis entre guillemets.
  3. La DTD message contient un niveau de structure supplémentaire : l'élément contenu, regroupant les éléments titre et corps correspondant respectivement aux éléments subject et textbody de la structure source.
  4. L'attribut ref de la DTD mail correspond à un élément référence dans la DTD message.
  5. L'élément date apparaît comme un attribut dans la DTD message.
  6. L'ordre des éléments destinataire et expéditeur est inversé par rapport aux éléments recipient et sender.

Tous les systèmes de transformation ne permettent pas de traiter tous les aspects de la transformation de mail en message. Nous donnerons, lors de la présentation des systèmes de transformation, l'ensemble de leur possibilités en référence à cette liste. Nous pourrons ainsi différencier les systèmes par leur capacité à réaliser les différents aspects de cette transformation.

<!ELEMENT message       (référence, expéditeur, 
                         destinataire, contenu)  >
<!ELEMENT référence     (#PCDATA)                >
<!ELEMENT expéditeur    (#PCDATA)                >
<!ELEMENT destinataire  (#PCDATA)                >
<!ELEMENT contenu       (titre, corps)           >
<!ELEMENT titre         (#PCDATA)                >
<!ELEMENT corps         (para)+                  >
<!ELEMENT para          (#PCDATA)                >
<!ATTLIST message      date   CDATA   #REQUIRED  >   

Figure 14 - La DTD XML des documents message

Le document que l'on désire obtenir à l'issue de la transformation est donné dans la figure 15.

<message date="30-07-1998">
 <référence>sb332</référence>
 <expéditeur>Stephane.Bonhomme@inrialpes.fr</expéditeur>
 <destinataire>Cecile.Roisin@inrialpes.fr</destinataire>
 <contenu>
  <titre>littérature XML</titre>
  <corps>
   <para>Bonjour Cécile,</para>
   <para>As-tu lu «SGML, Java and the Future of the
Web»</para>
   <para>Stéphane.</para>
  </corps>
 </contenu>
</message>

Figure 15 - Document message

3.2 Filtres de conversion

Un filtre est une application permettant de convertir un document d'un format donné dans un autre. Il existe des filtres permettant la transformation de documents entre toutes sortes de modes de représentation (traitement de texte, PostScript, PDF, LaTeX ou documents structurés). On peut citer les filtres de traduction de LaTeX vers HTML, de document formatés vers des documents SGML, conformes à des DTD particulières comme les DTD d'acquisition (TEI).

La caractéristique qui distingue les filtres de conversion des autres systèmes de transformation est la définition figée des transformations qu'ils permettent d'effectuer. Ces transformations sont définies lors du développement du filtre qui ne peut pas être paramétré pour effectuer des transformations différentes. Par exemple, un filtre permettant de traduire les documents mail en message comme montré dans notre exemple ne pourra effectuer que cette transformation et elle se fera toujours en suivant les mêmes règles.

Les filtres sont conçus pour répondre aux besoins spécifiques de certaines applications :

L'implémentation de filtres de conversion est très dépendante des formats des documents source. Si le format source est linéaire (contenu textuel et directives de formatage, comme c'est le cas pour les documents produits par les traitements de texte), le filtre parcourt le document, interprétant les directives de formatage pour produire leur équivalent dans le format cible.

[Here is a Drawing]

Figure 16 - Principe du filtre de conversion

Si le modèle des documents source est structuré (SGML, XML), le filtre intègre généralement un analyseur syntaxique (parser) permettant d'associer des actions - en l'occurrence la génération du document cible - aux débuts et fins d'éléments de la structure.

Certains des systèmes de transformation explicite présentés dans la section suivante permettent de programmer des filtres de conversion de documents de façon interactive (Chameleon [Mamrak 89]) ou en utilisant une spécification déclarative de la transformation (IDM [Digithome], XSL [Clark 98], DSSSL [ISO 94]).

Pour notre part, nous avons expérimenté la technique de conversion de documents par filtres lors de la création d'un nouveau schéma, nommé rapport, pour la classe de documents article définie dans l'éditeur Thot. Ce nouveau schéma se différencie du précédent principalement sur deux points :

D'autres différences mineures concernent les noms des types d'éléments et l'introduction de niveaux de structure supplémentaires dans la structure générique définie par le schéma rapport.

Notre filtre est programmé en utilisant l'API de Thot [Quint] qui fourni des primitives d'accès aux éléments du document source et des primitives de construction pour créer le document cible. La fonction de transformation crée l'équivalent d'un élément du document source passé en paramètre, cette fonction est ensuite appelée récursivement sur chacun des fils de l'élément source. L'arborescence ainsi obtenue est ensuite insérée dans la structure du document cible. De plus, la fonction de transformation effectue un traitement particulier sur les éléments appartenant à certains types (bibliographie, références) au lieu de traiter récursivement leur descendance.

Cette application nous a permis de nous familiariser avec la transformation de documents, mais nous a également montré que, bien qu'utilisée couramment par les membres du projet Opéra pour la transformation d'Articles en Rapports, une telle application n'a pas pu être ré-utilisée pour d'autres situations de transformation.

Les filtres de conversion ont pour atout leur efficacité car ils appliquent des algorithmes de transformation adaptés aux formats traités. Aucune information autre que le contenu du document ne doit être analysée ce qui accroît les performances de ces outils. Les filtres sont adaptés au traitement de collections importantes de documents suivant une méthode déterminée à l'avance et ne nécessitant donc pas d'interaction. Dans certains cas spécifiques, les filtres peuvent être utilisés dans les systèmes d'édition interactive, notamment lors de commandes d'édition précises portant sur des types d'élément déterminés.

La contrepartie de cette non-interactivité est que l'utilisateur ne peut pas guider le cours de la transformation. De plus, les filtres ne sont pas adaptables, c'est à dire que leur conception est dépendante des formats qu'ils manipulent, ils ne peuvent pas servir non plus à transformer les documents entre deux DTD quelconques.

Dans notre problématique, les filtres de conversion présentent un intérêt pour convertir des documents depuis des formats divers vers un format structuré sur lequel nous pouvons ensuite appliquer les techniques de transformation exposées plus loin.

3.3 Transformations explicites

Un système de transformation explicite s'appuie sur une information additionnelle aux documents et à leurs modèles, exprimant la façon dont un document doit être transformé. Cette information permet de paramétrer les transformations et par conséquent de les adapter aux besoins.

Les systèmes de transformation explicite prennent comme données un document source (ou une partie de document) et un ensemble de spécifications de transformation. Les spécifications de transformation sont interprétées puis utilisées pour convertir l'instance source en une instance cible (figure 17).

[Here is a Drawing]

Figure 17 - Architecture générale d'un système de transformation explicite

Ainsi, deux aspects sont considérés dans l'étude de ces systèmes : le langage de spécification des transformations et la mise en oeuvre de la conversion à partir de ces spécifications dans le moteur de transformation. Il faut noter que le langage dans lequel sont exprimées les transformations et le moteur qui les réalise sont dépendants l'un de l'autre.

Nous proposons dans la section 3.3.1 une classification des méthodes de transformation explicite. Les classes de langages utilisés par ces méthodes sont présentés dans la section 3.3.2. La section 3.3.3 est une revue des principaux systèmes utilisant la technique explicite. Un bilan des outils de transformation explicite est donné dans la section 3.3.4.

La section 3.4 est une étude particulière d'un travail réalisé dans le cadre de cette thèse, qui visait à évaluer la technique de transformation explicite dans un contexte d'édition interactive de documents structurés. Cette expérience à débouché sur la réalisation d'un système de transformations explicites pour l'éditeur Amaya.

3.3.1 Méthodes de transformation explicite

Les moteurs de transformation se différencient selon deux critères principaux :

L'ordre d'application des règles
  • Les transformations explicites peuvent être dirigées par la structure du document à transformer. Dans ce cas, une transformation est exprimée par des actions liées aux types des éléments du document source. Nous désignerons cette approche par le terme transformation dirigée par la source.
  • L'autre approche consiste à spécifier les transformations par identification dans le document source des éléments à composer pour produire le document . Nous appellerons cette méthode transformation par requêtes. Ces deux approches sont développées ci-dessous.
Le mode de génération du résultat
  • Le document résultant de la transformation peut être engendré en écrivant directement sur un flot de sortie du système de transformation ; la génération du document est alors dite linéaire.
  • Le document peut être construit sous la forme d'un arbre représentant sa structure avant de produire la forme de sortie ; cette approche est appelée génération arborescente.
3.3.1.1 Transformations dirigées par la source

Dans cette approche, une transformation est conduite par un parcours dans l'ordre préfixe de la structure du document source. Un ensemble de règles ou de primitives de génération du document cible est associé à un événement du parcours (début de document, début d'élément, fin d'élément, présence d'attribut, valeur d'attribut, etc.).

Dans certains formats de documents tels que MIF ou pdf, les éléments se sont pas ordonnés dans la forme stockée. Les documents apprtenant à de tels formats sont chargés par le système de transformation qui rétablit l'ordre dans lequel les éléments seront traité par la transformation.

La figure 18 illustre la génération des événements lors de la transformation d'un document de la classe message. L'événement de début d'élément message est généré, puis la descendance de cet élément est parcourue pour produire les événements qui y sont associés, l'événement fin d'élément message est produit lorsque toute sa descendance à été parcourue.

[Here is a Drawing]

Figure 18 - Production des événements lors de la transformation dirigée par la source.

Les transformations dirigées par la source permettent une sélection des événements en fonction du contexte dans lequel intervient l'élément de structure auquel est attaché cet événement. Ce contexte couvre les éléments qui ont été traités précédemment par le système au moment où il applique une règle : les ancêtres de l'élément courant, ses voisins de gauche et leurs descendants.

La transformation dirigée par la source permet une génération linéaire du document cible. Dans ce cas, les transformations ont la propriété de préserver l'ordre des éléments. La génération peut également être arborescente si le système de transformation fournit des fonctions de construction de structure comme la création, l'insertion ou la copie d'éléments.

L'approche des transformations dirigées par la source est proche du mécanisme d'un analyseur syntaxique et la plupart des outils proposant cette approche sont fondés sur des analyseurs de documents structurés (CoST 2 [English 96a], STIL [Schrod 95]). Ces systèmes bénéficient des fonctionalités de l'analyseur pour la production des événements et fournissent un mécanisme de génération de la structure cible.

3.3.1.2 Transformations par requêtes

Les transformations par requêtes permettent de construire le document cible par extraction d'éléments du document source. Une transformation est décrite par un ensemble de règles « requête-actions ». Une requête permet de sélectionner un sous-ensemble des éléments du document source sur lesquels doit être appliquée une (ou plusieurs) action(s) de transformation.

Le processus de transformation par requêtes se fait en deux phases :

  • La sélection d'une transformation parmi l'ensemble de transformations déclarées.
  • L'application d'un ensemble de règles de génération d'un document cible.

Des formes de requêtes différentes interviennent lors de ces deux phases : les requêtes utilisées par la première permettent la reconnaissance d'une structure particulière de l'instance source. Ces requêtes se comportent comme des filtres sur la structure du document. La seconde phase utilise des requêtes pour extraire l'information du document source pour l'intégrer dans le document cible.

Selon les systèmes de transformation, une importance différente est donnée à ces deux phases. Certains systèmes (IDM, Balise) ne proposent que la phase d'application des règles de génération, celle-ci se faisant de façon séquentielle et inconditionnelle. Si la génération se fait de manière linéaire, les déclarations sont ordonnées dans l'ordre de la structure du document produit. Une telle transformation peut être exprimée à l'aide du langage de script du système IDM présenté dans la section 3.3.3.1.

Si le système utilise les requêtes pour faire une sélection des règles à appliquer, l'ensemble des requêtes est évalué et les règles associées à celles retournant un résultat sont appliquées. L'ordre d'application de ces règles peut varier d'un système à l'autre. Cet ordre peut être :

  • donné dans l'expression : les règles priority-expression de DSSSL [ISO 94] permettent de définir un ordre de priorité sur les requêtes ; les expressions de transformation de Scrimshaw contiennent aussi l'ordre d'application dans leur description ;
  • implicite : XSL [Clark 98] applique en priorité les règles associées aux requêtes les plus spécifiques ;
  • celui de la structure du document source, comme dans le système de transformation d'Amaya (c.f. section 3.4.3).
  • celui de la structure du document à construire : les langages SgmlQL et Cost 2 permettent de décrire des transformations qui utilisent des requêtes sur le document source.

3.3.2 Langages de transformation

Les transformations explicites sont exprimées soit dans un langage spécifique soit dans un langage de programmation classique.

Les langages de transformation peuvent être de nature déclarative ou impérative :

  • Les systèmes se basant sur une expression déclarative ne proposent que le mode de transformation dirigé par la source. La conduite de la transformation est fixée par le moteur et ne peut pas être spécifiée par l'expression. En contrepartie, ces langages permettent une expression plus concise et plus lisible des transformations. C'est le cas du langage de script d'IDM [Digithome], de Chameleon [Mamrak 89] ou de XSL [Clark 98].
  • Les langages impératifs permettent de définir des procédures de transformation et de piloter le flot d'exécution de la transformation. Les systèmes basés sur de tels langages permettent de développer des transformations sur le modèle dirigé par la source (Balise [AIS 96], CoST 2 [English 96a]) ou sur le modèle par requêtes (SgmlQL [Le Maitre 98], Scrimshaw[Arnon 93]).

Certains systèmes utilisant une expression déclarative proposent une interface graphique pour spécifier les transformations. C'est le cas par exemple de Chameleon qui permet d'associer de manière interactive les types d'éléments d'une structure générique source avec ceux d'une structure cible.

3.3.3 Revue des systèmes de transformation explicite

Cette section décrit plusieurs systèmes de transformation explicite couvrant l'ensemble des méthodes et utilisant les formes de langages exposées précédemment. Nous illustrerons les langages associés à ces systèmes en donnant l'expression de la transformation des documents mail en documents message décrite au début de ce chapitre.

Nous présentons d'abord les systèmes de transformation utilisant des langages ayant une plus forte composante impérative. Puis nous décrirons des systèmes intégrant une approche plus déclarative.

Le tableau de la figure 19 recense les systèmes présentés dans la suite et les caractéristiques des méthodes de transformation qu'ils utilisent.

méthode de transformation
Systèmeordre
d'application des règles
génération
des éléments cibles
Langage
IDM source ou requêtes mixte impératif
Balise source ou requêtes mixte impératif
Cost / STIL source ou requêtes linéaire impératif
DSSSL requêtes arborescente fonctionnel
XSL requêtes arborescente déclaratif +
impératif
Chameleon source linéaire déclaratif
SgmlQL requêtes arborescente déclaratif
Scrimshaw requêtes linéaire déclaratif

Figure 19 - Caractéristiques des systèmes de transformation explicites

3.3.3.1 IDM

IDM (Intelligent Document Manager [Digithome]), développé par la société Digithome, est un environnement de manipulation de documents électroniques orienté vers la transformation de documents structurés. Cet environnement fournit une interface de programmation (API) permettant de programmer facilement des filtres de conversion de documents structurés vers des formats divers (HTML, LaTeX, Microsoft Windows Help).

L'API IDM permet de localiser des éléments de structure en utilisant des requêtes sur les ancêtres et les descendants d'un noeud, sur les voisins, sur la présence et la valeur des attributs, ou encore sur le contenu des éléments textuels. L'API permet d'implémenter des transformations procédurales et dirigées par la destination. Les primitives de l'API sont fournies par un ensemble de classes C++, dont la classe DI qui fournit les méthodes de sélection de noeud ou la classe IDM qui contient les méthodes de lecture du document source et d'écriture sur le flot de sortie.

L'exemple suivant montre la transformation du document mail en message et illustre ainsi la méthode de transformation par requêtes avec une génération linéaire des éléments cibles.

Les requêtes utilisent les méthodes de la classe DI préfixées par Move pour déplacer le noeud courant dans la structure. La méthode MoveB permet de déplacer la sélection courante vers son premier fils, MoveT permet de la déplacer sur le parent, MoveR et MoveL permet de la déplacer vers l'élément suivant ou précédent. La partie génération utilise les méthodes DI->GetData pour accéder au contenu des éléments et IDM->Progress pour écrire sur le flot de sortie le résultat de la transformation.

DI->MoveTT();                  // accès à
l'élément racine
DI->MoveB();                   // accès à
l'élément date
IDM->Progress ("<message date=\"%s\">", DI->GetData());

DI->MoveT();                   // accès à
l'élément mail
IDM->Progress
("<référence>%s</référence>\n",
               DI->GetAttrValue ("ref"));

DI->MoveB();                  //accès à
l'élément sender
DI->MoveR(); 
DI->MoveR();
IDM->Progress ("<expéditeur>%s</expéditeur>\n",
                DI->GetData());

DI->MoveL();                  //accès à
l'élément recipient
IDM->Progress ("<destinataire>%s</destinataire>\n",
                DI->GetData());

IDM->Progress ("<contenu>\n");

DI->MoveR();
DI->MoveR();                   // accès à
l'élément subject
IDM->Progress ("<titre>%s</titre>\n",
               DI->GetData());

DI->MoveR();                   // accès à
l'élément textbody
IDM->Progress ("<corps>\n");
DI->MoveB();
do
   if (DI->IsGI("cite") == IDTRUE)
       IDM->Progress ("« %s »", DI->GetData);
   else
       IDM->Progress ("%s", DI->GetData);
while (DI->MoveNext == IDTRUE)

Dans cet exemple nous supposons que la structure du document source est correcte et que tous les éléments de cette structure sont présents. Un traitement supplémentaire serait nécessaire pour vérifier l'existence de chacun de ces éléments.

IDM propose de plus un langage de script qui permet de spécifier des transformations dirigées par la source. La déclaration de la transformation est alors plus concise, mais ne permet pas de réaliser tous les aspects de la transformation de l'exemple : la spécification suivante ne remplit que les critères 1, 2 et 3 énoncés dans la section 3.1 :

START_mail
   Progress ("<message>")
END_mail
   Progress ("</message>")
START_recipient
   Progress ("<destinataire>")
END_recipient
   Progress ("</destinataire>")
START_sender
   Progress ("<expéditeur>")
END_sender
   Progress ("</expéditeur>")
START_subject
   Progress ("<contenu> <titre>")
END_subject
   Progress ("</titre>")
START_textbody
   Progress ("<corps>")
END_textbody
   Progress ("</corps> </contenu>")
START_cite
   Progress ("«")
END_cite
   Progress ("»")
!DATA 
   Progress ("$DATA")

Avec ce langage de script déclaratif, la génération de ce document est également linéaire. Par conséquent, la transformation dirigée par la source, spécifiée par le langage de script ne permet pas de modifier l'ordre des éléments (critères 4, 5 et 6).

Grâce à sa nature procédurale, IDM permet des transformations complexes de documents structurés entre DTD ainsi que vers de nombreux formats de documents. Néanmoins l'utilisation de cet outil requiert une bonne pratique de la programmation et de l'algorithmique pour mettre en oeuvre ces transformations. Le langage de script est très simple, mais ne permet d'effectuer que des transformations simples : la génération de l'instance cible est linéaire, et les traitements sont associés à un type d'élément indépendamment du contexte dans lequel ils apparaissent.

3.3.3.2 Balise

Balise [AIS 96] est un environnement de développement d'applications documentaires basées sur les standards SGML et XML. Cet environnement comprend un langage de programmation. Il est développé par la société AIS Berger-Levrault. Le langage Balise permet de manipuler la représentation arborescente des documents à travers des fonctions d'accès et de modification de la structure. Ces fonctions permettent soit de modifier la structure d'un document existant, comme montré ci-dessous, soit de générer un nouveau document en insérant les éléments créés dans une nouvelle arborescence comme le montre le deuxième exemple. Les instructions de contrôle du langage Balise sont les mêmes que celles d'un langage de programmation impératif classique (Pascal, C).

Ce langage fournit également des primitives de création et de copie d'éléments. Ces fonctions permettent de programmer un grand nombre de transformations. Une fonction transformant des documents mail en message s'écrit :

function Mail2Message (doc) {
  var elem = root (doc);         // accès à
l'élément racine
  changeGI (elem, "message");    // change le type du noeud
                                 // mail

  var reg = attr ("ref", elem);  // accès à l'attribut ref
  var newelem = Move (soc, "référence", ref);
  insertSubTree (elem, 1, newelem); //cree l'élément ref

  elem = firstChild (elem);      // accès à
l'élément date
  addAttr (root(doc), date, content (elem));
  
  elem = rightSibling (elem);    // accès à
l'élément recipient
  changeGI (elem, "destinataire");

  elem = rightSibling (elem);    // accès à
l'élément sender
  changeGI (elem, "expéditeur");
  CutSubTree (elem);             // déplace l'élément
                                 // expéditeur
  insertSubTree (root(doc), 1, elem);

  elem = rightSibling (elem);    // accès à
l'élément title
  changeGI (elem, "titre");
  var body = rightSibling (elem); //accès à
l'élément textbody
  cutSubtree (elem);             // déconnecte le noeud titre
  insertSubtree (body, 0, elem); // insère titre avant le
                                 // 1er fils de body
  changeGI (body, "contenu");    // change body en contenu
  elem = Node (doc, "corps");    // crée le noeud corps
  insertSubtree (body, 1, elem); // insère corps après le
                                 // 1er fils de contenu
  var elpar = rightSibling (body);
  while (elpar != nothing) {     // parcourt les éléments p
    cutSubtree (elpar);          // déplace chaque p dans 
    insertSubtree (elpar, -1, body) // l'élément corps 
    changeGI (elpar, Para);
    for elem in searchElemNodes (elpar, "cite") {
                                 // génère les guillemets
      changeContent (elem, format ("«%s»", content(elem)));
      flattenSubTree (elem);     // retire les éléments cite
    }
  }
}

L'algorithme utilisé dans cet exemple parcourt le document source en appliquant des traitements spécifiques aux éléments rencontrés. Ces traitements permettent d'implémenter les six aspects énoncés dans l'exemple. La nature impérative du langage Balise impose une description complète de la transformation. En particulier, pour ignorer les éléments cite, il faut explicitement les retirer (fonction flattenSubTree) ou rechercher leur contenu d'une manière spécifique.

Balise permet également de spécifier des transformations dirigées par la source. Pour cela, Balise permet d'associer des traitements aux événements de l'analyseur XML intégré. Des traitements sont associés aux événements de début et de fin pour les éléments, des clauses contextuelles peuvent être ajoutées à cette définition (par exemple : début des éléments de type p se trouvant à l'intérieur d'un élément textbody). Pour limiter l'occupation de la mémoire lors de la transformation, le contexte est restreint aux ancêtres et aux voisins précédents de l'élément concerné par l'événement. Nous donnons ci-dessous un extrait d'une transformation dirigée par la source exprimée dans le langage Balise. Cette spécification utilise le style déclaratif pour associer des traitements aux événements de l'analyseur, ces traitements utilisant un langage procédural pour générer l'arborescence du document cible.

//initialisation
main {
  eventLookAhead(true);
}
// transformation de l'élément mail
element mail {
  on start {
    changeGI ("message");
    var root = Elem ("mail");
           }
  }
// transformation de l'élément date en attribut
element date {
  on start {
     var ladate = content (currentNode());
     AddAttr (root, "date", ladate);
           }
  }
// transformation de l'élément recipient
element recipient {
  on start {
     changeGI ("destinataire");
     // insère expéditeur comme premier fils de body
     cutTree (currentNode());
     insertSubTree (root, 0, currentNode());
           }
  }
// transformation de l'élément sender
element sender {
   on start {
      changeGI ("expéditeur");
      // insère expéditeur comme premier fils de body
      cutTree (currentNode());
      insertSubTree (root, 0, currentNode());
            }
  }
// transformation de l'élément subject 
element suject {
    on start {
       changeGI ("titre"); 
      // crée l'élément contenu
      // et l'insère comme dernier fils de body
      var elcontenu = Node ("contenu");
      insertSubTree (root, -1, elcontenu);
      // insere titre dans contenu
      insertSubTree (elcontenu, 0, currentNode()); 
      // crée l'élément corps
      // et l'insère comme dernier fils de contenu
      var elcorps = Node ("corps");
      insertSubTree (elcontenu, -1, elcorps);
           }
  }
// transformation des éléments para
element p {
   on end {
     changeGI ("para");
     cutTree (currentNode());
     insertSubTree (elcontenu, -1, currentNode());
   }
// élimination des éléments cite,
génération des guillemets
element cite {
   on begin {
   changeContent (currentNode(), format ("«%s»",
content(currentNode())));
   flattenSubTree();
            }
   }

Balise, avec l'approche dirigée par la source, se différencie du langage de script d'IDM par le fait que la génération ne se fait plus de manière linéaire, mais par la construction d'une structure arborescente du document. Cette approche fournit une souplesse accrue dans la façon de placer les éléments cibles. De plus elle n'impose pas la génération des balises de début et de fin d'élément. En contrepartie, elle ne permet de produire que des documents structurés au format SGML ou XML. De plus, ce mode de génération nécessite la représentation en mémoire de l'arbre du document cible qui peut être importante.

La combinaison de la transformation dirigée par la source avec la modification de la structure du document source peut produire des effets de bord négatifs : le traitement d'un événement peut entraîner des modifications dans la structure du document et conduire à l'omission de sous-arbres entiers lors de la transformation. C'est pour éviter ces effets de bord que Balise permet de dupliquer préalablement la structure du document source (avec la fonction DumpSubTree) pour obtenir une instance servant à la génération du document, l'autre étant modifiée par les traitements de ces événements.

En conclusion, comme pour IDM, la composante impérative du langage Balise nécessite une connaissance de la programmation. Par contre, son approche déclarative permet la spécification de transformations plus complexes que celles d'IDM grâce à la possibilité de sélectionner des ancêtres lors de l'association d'une règle à un type d'élément et à la génération arborescente.

3.3.3.3 CoST 2

CoST 2 [English 96a] (Copenhagen SGML Tool) est un outil qui permet de spécifier des transformations de documents structurés en Tcl. Cet outil est un logiciel libre développé par la société ART (Advanced Rotorcraft Technology, Inc.) Ce langage intègre de puissantes fonctions de traitement de la composante textuelle des documents telles que la reconnaissance d'expressions régulières et leur remplacement. Cet outil de transformation est associé au parser sgmls [Clark].

CoST 2 propose une méthode de transformation par requêtes. Celles-ci servent à sélectionner les éléments du document source qui doivent être transformés mais également à identifier ceux qui sont utilisés lors de la génération.

Les requêtes de sélection des éléments source sont définies par les mots clés foreachNode et withNode associés à un traitement Tcl. Le traitement est appliqué au premier élément ou à l'ensemble des éléments respectant la requête. Lors de l'application du traitement, l'élément ayant satisfait la requête est appelé élément courant.

Les traitements sont des scripts Tcl et permettent d'écrire de façon linéaire le document cible sur un flot de sortie. Ces traitements peuvent utiliser des requêtes sur le document source pour en extraire le contenu. Ces requêtes permettent d'accéder aux éléments environnant l'élément courant (ancêtres, voisins et descendants), aux attributs des éléments et au contenu des feuilles.

La transformation de mail en message à l'aide de CoST 2 s'exprime de la façon suivante :

puts "<message date=\""
withNode withgi date {puts "[query content]"}
puts "\">"
puts "<reference>"
withNode withgi message hasatt ref {
  puts "[query attval ref]"
  }
puts "</référence><expéditeur>"
withNode withgi sender {puts "[query content]"}
puts "</expéditeur><destinataire>" 
withNode withgi sender {puts "[query content]"}
puts "</destinataire><contenu><titre>"
withNode withgi title {puts "[query content]"}
puts "</titre><corps>"
foreachNode withgi p {
   puts "<para>"
   puts "[query content]"
   puts "</para>
   }
puts "</corps></contenu></message>"

Les requêtes d'extraction du contenu sont introduites par le mot-clé query, tandis que les requêtes de sélection sont illustrées ici par le mot-clé foreachNode. La transformation présentée ci-dessus ne permet pas de traduire les element cite de la structure source, car la composition des requêtes n'est pas suffisamment expressive et l'opérateur foreachNode ne permet pas de différencier le traitement à associer au début, au contenu et à la fin de chaque élément. Pour pallier ce manque d'expressivité, CoST 2 permet d'ordonnancer les traitements selon la structure du document source en les associant aux événements de l'analyseur. Les actions TCL utilisant les requêtes sont alors associées aux événements de début et de fin d'élément.

Cet outil, profitant de la modularité apportée par le langage de script Tcl permet le développement de modules, ce qui conduit à une expression simple mais limitée des transformations. Parmi ces modules, on peut citer Simple Cost, qui permet une spécification simple de transformations dirigées par la source avec une génération linéaire par écriture sur le flot de sortie, RatFink [English 96b] qui permet la spécification de transformations de documents structurés SGML en documents au format RTF.

STIL [Schrod 95] et SGMLSpm [1] sont des outils de transformation qui utilisent des principes similaires à ceux de CoST. STIL est développé à l'université de Darmstadt, il utilise le langage Lisp pour la description des requêtes. SGMLSpm développé par David Megginson de l'université d'Ottawa est un module perl permettant l'expression de requêtes et de règles de transformation similaires à celles de CoST2.

3.3.3.4 Exrep

Exrep [Lambolez 95] est un outil de réécriture permettant de traiter un flot de texte en entrée et d'y appliquer un ensemble de règles de réécriture. Exrep est particulièrement adapté aux domaine de l'extrction et de la réutilisation de contenu de document.

Chaque règle de réécriture est formée d'une expression régulière permettant la reconnaissance d'une sous-chaîne dans la chaîne d'entrée, et d'une chaîne de remplacement se substituant à la sous-chaîne reconnue par l'expression régulière.

Les apport de Exrep sur les outils de réecritures standards d'Unix, tels que lex [Levine 92] et awk [Dougherty 92] sont :

  • la présence de dictionnaires, permettant de gérer des ensembles de sysnonymes et des glossaires. Cette propriété est particulièrement utile pour traiter le contenu textuel d'un document ;
  • l'indépendance de l'outil par rapport à la structure de lignes du flot d'entrée ; les caractères de fin de ligne sont traités comme les autres, permettant la reconnaisssance de sous chaînes divisées en plusieurs lignes.
  • la possibilité d'associer un contexte à un ensembe de règles de réécriture.

A cause de sa généricité lui permettant de traiter tout type de format de document, Exrep ne propose pas de primitive permettant de gérer facilement les balises SGML ou XML. La spécification d'une transformation doit donc contenir les expressions régulières permettant de rcoonaitre la syntaxe des balises de marquage.

Les transformations proposées par le système Exrep peuvent être considérées comme des transformations par requêtes avec génération linéaire. Ces transformations permettent le remplacement des balises (la substitution de <mail> par <message>, le remplacement de l'élément <date> par un attribut ou bien de l'attribut ref par un élément). Les transformations permettent l'insertion de balises en fonction du contenu d'un élément (remplacement des guillemets par l'élément cite). La principale limitiation d'Exrep est de ne pas permettre le déplacement d'éléments dans la structure, des systèmes tels que Scrimshaw (3.3.3.9) permettent de manipuler des variables permettant la mémorisation d'éléments pour leur réutilisation au cours de la transformation, ce qui permet les déplacement et leur réplication.

3.3.3.5 Chameleon

Chameleon [Mamrak 89] est un outil interactif de définition de structures génériques et de transformation entre formats de documents. Chaméleon, aussi appelé ICA pour Integrated Chameleon Architecture a été développé à l'université de l'Ohio en coopération avec la compagnie HaL Computer Systems, Inc.

SGML est utilisé par Chameleon comme format de description générique des documents et sert de pivot entre les documents de différents formats (figure 20).

[Here is a Drawing]

Figure 20 - Utilisation de SGML comme format pivot pour la transformation entre formats de documents

L'information de formatage des documents originaux est d'abord convertie sous forme de balises SGML. Les documents ainsi marqués sont transformés vers une structure générique SGML, enfin, ces documents sont exportés vers le format de destination voulu.

Ces transformations successives sont spécifiées par plusieurs modules de Chameleon (cf. figure 21) :

  • Devegram permet de créer des grammaires et des DTD pour la structure générique SGML.
  • retag permet de remplacer les balises de structure et/ou de formatage des documents.
  • intag est complémentaire à retag et permet d'insérer les informations dans le document quand celles-ci sont requises par la DTD.
  • Spec2gen permet de spécifier la correspondance entre le marquage spécifique et la structure générique.
  • Gen2spec permet d'exporter un document SGML vers le format de sortie.
[Here is a Drawing]

Figure 21 - Étapes de la transformation d'un document LaTeX en Troff
avec ICA

Chaque module permet la génération de filtres, représentés par des cercles sur la figure 21, qui permettent le passage du document d'un état dans un autre (source, marqué, SGML, cible).

L'originalité de ce système est l'utilisation de SGML comme format central pour la conversion de documents. Cela permet de s'appuyer sur des DTD existantes pour la représentation commune des formats source et cible. Pour utiliser cette méthode de transformation, deux étapes sont nécessaires : la structuration permet de représenter le document d'origine sous une forme structurée, l'export permet de traduire le document structuré dans le format de destination.

Les modules de spécification de transformations s'appuient sur les outils d'analyse syntaxique Lex et Yacc. Les modules Retag, Intag et Gen2spec ne permettent que de spécifier des réécritures de l'information de formatage ou de structure associée aux documents. Le module Spec2gen est le plus intéressant du point de vue de la transformation car c'est lui qui permet les opérations de manipulation de structure des documents.

Le module Spec2gen permet l'association des balises du document source avec les types définis dans la DTD SGML. Cette association est décrite à l'aide d'expressions régulières permettant d'exprimer l'organisation des balises sources. Certaines balises peuvent être perdues lors de cette étape car la structure générique SGML ne permet généralement pas de représenter toutes les informations nécessaires à la présentation du document. Dans l'exemple ci-dessus, le document est découpé en paragraphes, mais les sauts de ligne sont perdus.

Les expressions régulières permettent d'associer des règles de transformation (en l'occurrence un type d'élément SGML) à une séquence de balises dans le document marqué. Ces séquences d'éléments sont exprimées en termes de listes, d'alternatives et peuvent contenir des éléments optionnels. Les expressions régulières ne permettent pas d'exprimer la hiérarchie des balises source ; elles sont donc adaptées pour spécifier la transformation d'un ensemble de balises sans relations hiérarchiques, mais il est nécessaire d'étendre leur syntaxe et leur sémantique pour les utiliser dans un contexte de documents structurés (voir section 3.4.2.1).

3.3.3.6 DSSSL

DSSSL [ISO 94] est une norme de l'ISO pour définir la sémantique ou le style des documents SGML. DSSSL comprend deux parties : STTP (SGML Tree Transformation Process) et SSP (Semantic Specific Process), c'est la partie STTP qui assure les transformations de structure. Le but de la transformation de structure proposée par DSSSL est l'adaptation des documents SGML aux différents support de présentation.

Les spécifications de transformations sont exprimées dans le langage scheme et décrivent l'association entre les types de la DTD d'origine et ceux de la DTD destination. Ces spécifications d'associations sont composées de trois parties :

  • query-expression est l'expression d'une requête destinée à la sélection des noeuds de l'arbre source concernés par la transformation.
  • transform-expression est l'expression de la transformation évaluée pour chaque noeud sélectionné par la requête. Cette expression rend comme résultat la description du(des) noeud(s) de l'arbre destination correspondant au noeud sélectionné.
  • priority-expression est un composant optionnel qui spécifie quelles expressions de transformation sont utilisées lorsqu'un noeud de l'arbre répond à plusieurs requêtes.

La norme DSSSL, bien que datant de 1994, n'a connu qu'une implémentation partielle : Jade [Clark], associée à l'analyseur sgmls. La proposition XSL présentée dans la suite joue un rôle similaire à celui de DSSSL pour les documents XML.

3.3.3.7 XSL

XSL [Clark 98] est une proposition du consortium W3C pour la définition de feuilles de styles (stylesheets) pour les documents XML. Le langage XSL comprend deux parties :

  • un langage de transformation auquel nous nous intéressons particulièrement ;
  • une syntaxe de spécification de formatage des documents.

Le langage XML utilise le mécanisme des NameSpaces [Bray 98b] qui est également une proposition du consortium W3C. Les namespaces permettent de définir des espaces de noms dans les documents : les noms de types d'éléments sont précédés d'un préfixe indiquant à quel espace de nom ils appartiennent. XSL utilise l'espace de nom xsl pour identifier les directives de transformation des éléments de structure crées par la transformation.

Une feuille de style est composé d'un ensemble d'expressions (nommés templates) décrivant chacune une transformation élémentaire. Chaque template est représenté par un élément XML du type xsl:template.

Le modèle de transformation de XSL repose sur des requêtes spécifiant la structure des éléments source. Une requête permet de sélectionner un élément en fonction de son contexte ascendant (parents, ancêtres), la présence et la valeur des attributs des éléments constituant ce contexte.

Les requêtes XSL sont contenues par l'attribut match des éléments template.

Le contenu d'un élément template est constitué de l'ensemble des éléments qui sont créés dans le document cible par la transformation et de directives XSL qui permettent un traitement lors de la transformation. Ces directives permettent :

  • d'insérer des éléments texte ;
  • d'utiliser des compteurs ;
  • d'appliquer une autre transformation sur d'autres éléments ;
  • de traiter des éléments textuels, en particulier les valeurs des attributs ;
  • de contrôler l'exécution de la transformation avec :
    • des instructions conditionnelles (if...then...else) portent sur une requête ;
    • des boucles (for each) permettant de traiter de façon itérative tous les éléments reconnus par une requête.

    des règles conditionnelle en fonction d'une requête.

Lorsqu'une feuille de style XSL est appliquée, le template dont la requête identifie l'élément racine de la structure source est d'abord appliqué. ce template peut explicitement provoquer l'application des autres templates à d'autre éléments de la structure source.

La feuille de style suivante permet de transformer un document mail en message :

<xsl:stylesheet>

 <!-- transformation de l'élémnt mail        -->
 <xsl:template match="mail">
  <message date="{date}">
   <reference>
    <xsl:value-of expr="attribute(ref)"/>
   </reference>
   <!-- traite les fils de mail dans l'ordre où
        ils apparaissent dans la structure
        message                              -->
   <xsl:process select="sender"/>
   <xsl:process select="recipient"/>
   <xsl:process select="textbody"/>
  </message>
 </xsl:template>

 <!-- transformation de l'élément sender      -->
 <xsl:template match="sender">
  <expéditeur>
   <xsl:process-children/>
  </expéditeur>
 </xsl:template>

 <!-- transformation de l'élément recipient   -->
 <xsl:template match="recipient">
  <destinataire>
   <xsl:process-children/>
  </destinataire>
 </xsl:template>

 <!-- transformation de l'élément subject     -->
 <xsl:template match="subject">
  <titre>
   <xsl:process-children/>
  </titre>
 </xsl:template>

 <!-- transformation de l'élément textboby    -->
 <xsl:template match="textbody">
  <contenu>
   <!-- transformation de l'élément subject   -->
   <xsl:process select="ancestor(mail)/subject"/>
   <corps>
    <xsl:process-children/>
   </corps>
  </contenu>
 </xsl:template>

 <!-- traite l'élément p -->
 <xsl:template match="p">
  <para>
   <xsl:process-children/>
  </para>
 </xsl:template>

 <!--transformation de l'élément cite         -->
 <xsl:template match="cite">
  «
  <xsl:process-children/>
  »
 </xsl:template>
</xsl:stylesheet>

XSL permet de traiter tous les aspects de la transformation de mail en message présentée dans la section 3.1. Ce langage, encore en cours de définition, est parmi ceux présentés ici celui permet d'exprimer les transformations les plus complexes. Pour cela, il intègre la méthode transformation par requêtes, une construction descriptive de la structure cible et des instructions de contrôle permettant de guider la transformation.

La norme XSL étant destinée à la transformation de document pour produire une structure proche de son image physique il a été conçu pour la transformation des documents dans leur intégralité. Cependant, les déclarations XSL sont modulaires : une transformation est décrite par un ensemble de templates qui portent chacun sur un sous-ensemble du document source. Les templates peuvent donc être utilisés pour une transformation locale et faire partie de la spécification d'une transformation plus générale.

La contrepartie de cette déclaration modulaire est la nécessité de spécifier la façon de transformer chaque élément du document source.

3.3.3.8 SgmlQL

SgmlQL [Le Maitre 95], [Le Maitre 98] est un système de transformation fondé sur un langage reprenant les principes du langage d'interrogation de bases de données SQL. Ce système est développé au Laboratoire Parole et Langages (LPL) à l'université de Toulon. Ce système permet la construction de documents à partir de l'information contenue dans une base de documents SGML.

Chaque script SgmlQL décrit la construction d'un document SGML en utilisant des opérateurs de construction de document, d'élément et d'attribut. Le langage permet d'évaluer des requêtes construites avec les opérateurs SQL (Empty, Count, Sum, Indexing, Concatenation, Shrink, Exists, Forall, Select... from... where, Transpose... from... where) mais appliquées à des documents SGML au lieu de bases de données relationnelles.

SgmlQL permet par exemple d'extraire l'information contenue dans un ensemble de messages dont la structure est décrite dans notre exemple. Supposons que le fichier messages.sgml contienne un ensemble de messages. On affecte son contenu à une variable globale par l'expression :

global $mess = file "messages.sgml"

Les requêtes utilisent cette variable globale pour en interroger le contenu :

Nombre de messages
count (every message within $mess)
 
Les dix premiers messages
(every message within $mess)[1:10]
 
Tous les messages sont-ils adressés à Cécile ?
forall $m in 
(every destinataire within $mess):
text($m) match "Cécile"
 
L'ensemble des messages adressés à Cécile
select
  every message within $m
from
  $m in $mess
where
  text (first destinataire within
  $m) match "Cécile"

Le résultat des requêtes peut être appliqué aux opérateurs de construction d'éléments pour que le script produise un document SGML. Le script permettant de convertir le document mail en message s'écrit :

document docdtd: "message.dtd"
  body:
   element MESSAGE
    attr:{DATE = text(first DATE within $mess)}    
    content: [
     element REFERENCE
      content:[(first MAIL within $mess)->REF],
     element EXPEDITEUR
      content:[content(first SENDER within $mess)],
     element DESTINATAIRE
      content:[content(first RECIPIENT within $mess)],
     element CONTENU
      content:[
       element TITRE
        content:[content(first TITLE within $mess)],
       element CORPS
        content:[replace every P as $p 
                 within $mess
                 by element PARA
                     content: content (
                          replace every CITE as $c
                          within $p
                          by "« ".text($c)." »")
                ]
              ]
            ] 

La transformation de mail en message n'est pas la plus adaptée pour montrer les possibilités du langage SgmlQL, qui est conçu pour la construction de documents à partir d'une collection de documents SGML. Ce système répond à un besoin de transformation assez différent de celui concerné par notre problématique : l'utilisation et la génération de documents structurés à partir d'information provenant de sources diverses (bases de données, serveurs d'information, moteurs de recherche, World Wide Web, etc.).

Néanmoins l'exemple ci-dessus montre que les expressions SgmlQL sont compactes. De plus ce système permet de mettre en oeuvre tous les aspects de la transformation donnés en 3.1.

En contrepartie, le temps d'évaluation des requêtes qui est un facteur déterminant pour l'utilisation d'une telle approche dans un éditeur interactif est important pour les requêtes du type SQL. L'approche de la transformation proposée par ce système est plus adaptée au traitement automatique de bases de données documentaires qu'à la transformation d'instances au coup par coup, telle qu'elle est utilisée dans les éditeurs interactifs.

3.3.3.9 Scrimshaw

Scrimshaw [Arnon 93] est un langage de pattern-matching entre arbres permettant de spécifier des transformations de documents structurés. Ce langage se fonde sur une approche requêtes/action et une génération linéaire du document cible.

Scrimshaw permet de manipuler des variables pouvant contenir des listes de sous-arbres de la structure des documents. Ces variables sont affectées par le résultat de requêtes sur la structure du document. Les requêtes utilisent des opérateurs de pattern-matching classiques appliqués au document source :

  • grep {PATTERN->EXPRESSION} recherche la première occurrence de PATTERN dans l'ordre préfixe du document, et lorsqu'une occurrence est trouvée, l'expression est évaluée et son résultat est copié sur le flot de sortie.

    Dans la partie PATTERN associée à un opérateur grep, il est possible d'assigner des sous-parties à des variables. Ces variables peuvent être utilisées dans la partie EXPRESSION de la règle.

  • grepSearch {PATTERN->EXPRESSION} recherche toutes les occurrences de PATTERN dans la structure du document et les copie sur le flot de sortie.
  • map et mapSearch sont identiques à grep et grepSearch à la différence que tous les éléments du flot d'entrée ne coïncidant pas avec la partie PATTERN sont recopiés sur le flot de sortie.

Scrimshaw fournit également un mécanisme de pipeline permettant d'appliquer plusieurs transformations successives à une même instance.

La transformation de mail en message dans le langage Scrimshaw s'exprime de la façon suivante :

{mail [
   date [<vdate:#>]
   recipient [<vrec:#>]
   sender [<vsend:#>]
   title [<vtitle:#>]
   textbody [
     <vlp:map[{p[<vp:#*>]->para[<vp>]}] 
        ||mapSearch{cite [vcite:#*] -> "«",<vcite>,"»"}]
     >
            ]
        ] -> message [ expediteur [<vsend>]
                       destinataire [<vrec>]
                       contenu [
                         titre [<vtitle>]
                         corps [<vlp>]
                               ]
                     ]
}

La partie requête de cette transformation assigne respectivement les variables vrec, vsent et vtitle au contenu des éléments recipient, sender et title du document d'origine. La requête traitant les paragraphes est plus complexe : un opérateur map change d'abord les éléments p en para puis au résultat de cette transformation est appliqué un opérateur mapSearch permettant de remplacer les éléments cite par des guillemets. Le résultat de la transformation de la suite de paragraphes constituant le corps du mail est assigné à la variable vlp.

Scrimshaw est limité à la transformation des éléments et ne permet pas de spécifier des transformations impliquant les attributs. Cette limitation ne permet pas de prendre en compte les éléments date et reference dans la transformation de mail en message.

La partie génération de la transformation est une déclaration de la structure du document cible en utilisant les variables initialisées dans la partie requête.

Au delà de la syntaxe utilisée, le principe de transformation proposé par Scrimshaw se différencie de celui de DSSSL par la façon de générer le document cible. Au lieu d'utiliser les expressions de priorité pour définir l'ordre des transformations, Scrimshaw permet d'intégrer les opérateurs de pattern-matching à l'intérieur des requêtes. Ainsi les transformations peuvent être faites « à la volée » lors du pattern-matching (opérateurs map et mapsearch dans l'exemple). Le mécanisme de pipeline permet également de contrôler l'ordre dans lequel sont effectuées les transformations.

3.3.4 Synthèse

La diversité des systèmes de transformation explicite vient du fait qu'ils répondent à des besoins applicatifs différents. Nous identifions ici les relations entre les méthodes de transformation et le contexte applicatif (voir section 2.4) dans lequel elles sont utilisées :

  • Certaines bibliothèques de développement d'applications de documents structurés (Balise, IDM, Thot) intègrent des services de transformation. Ces outils proposent des primitives génériques permettant de programmer des transformations adaptées aux applications qu'ils permettent de développer. Cependant ils nécessitent un effort de développement important et ne peuvent pas être ré-utilisés dans un contexte autre que celui pour lequel ils ont été développés, parce que le système de transformation est intégré à l'application qui l'utilise.

    Ces systèmes peuvent également proposer des facilités pour spécifier des transformations dirigées par la source en reproduisant le comportement d'un parser (langage de script d'IDM, mécanisme d'événements de Balise). Cette possibilité permet de réécrire la structure et le contenu du document, pour l'exportation vers un autre format de documents par exemple, mais ne permet pas de transformations complexes entraînant une modification de l'ordre des éléments ou leur déplacement dans les niveaux de structure. En contrepartie, les transformations sont plus faciles à spécifier et ne réclament pas l'expertise nécessaire au développement de systèmes de transformation plus complexes.

  • Les systèmes dédiés à la transformation permettent de produire des filtres de conversion (CoST 2, STIL, Chameleon) ou de construction de documents (SgmlQL). Ces systèmes sont généralement basés sur le modèle requête-action et proposent des fonctions de transformation plus avancées que le modèle dirigé par la source (réordonnancement des éléments, gestion des attributs, sélection d'éléments en fonction de leur contexte).

    Ces transformations utilisent des algorithmes plus coûteux en temps de calcul. Les requêtes pouvant être appliquées à la globalité du document, la structure de celui-ci doit être parcourue à chaque évaluation. La place mémoire nécessaire à ces processus est également importante car elle doit contenir la structure dans son intégralité. C'est une des raisons pour lesquelles les transformations par requêtes ne sont pas utilisées dans des systèmes interactifs, mais trouvent leur application dans la conversion de grandes quantités de documents, mettant en oeuvre des processus de conversion non interactifs.

    L'expression des transformations par requêtes n'est pas aussi simple que celle des transformations dirigées par la source car les correspondances entre les éléments source et les éléments produits par la transformation ne sont pas directes. Par conséquent la programmation de ces transformations nécessite une connaissance plus approfondie des structures génériques des documents et de l'interprétation des requêtes par le système.

3.3.5 Spécification d'un système de transformation explicite pour l'édition de documents structurés

Cette partie expose une réflexion sur la possibilité d'expérimenter un système de transformations explicites dans le cadre applicatif de l'édition de document. Nous présentons ici les choix que nous avons fait préalablement à cette expérience.

Pour l'édition de documents structurés, les transformations explicites doivent remplir des conditions de performances et de localité adaptées à cette application. Le système doit pouvoir prendre en entrée un ensemble de transformations et se baser sur différents critères pour n'en retenir qu'une. Ces critères sont :

  • la structure de l'élément source. Cet élément (ou ce groupe d'éléments) est déterminé par la sélection active au moment où la transformation est demandée ;
  • le résultat attendu après la transformation qui est déterminé par la commande invoquée par l'utilisateur final et par le contexte dans lequel les éléments sont transformés. Le type des éléments résultant de la transformation est choisi par l'utilisateur. Dans certains cas, plusieurs transformations peuvent conduire à un résultat du type demandé et l'utilisateur doit déterminer la transformation à appliquer. Par exemple, la transformation d'un élément liste en une table peut conduire à la création d'une table contenant un ligne ou une colonne comme l'illustre la figure 22.

    La structure résultant d'une transformation peut ne pas être conforme à la structure générique définissant la classe de documents. Le système doit contrôler que la transformation ne produise que des structures conformes.

[Here is a Drawing]

Figure 22 - deux transformations de liste en table

Les systèmes de transformation dirigés par la source permettent une application rapide des transformations en n'utilisant qu'une place mémoire minimale. De plus ils permettent une expression simple des transformations. Cependant ces systèmes, généralement associés à une génération linéaire du document cible, sont trop limités pour des transformations impliquant un déplacement des éléments dans la structure du document.

Les requêtes de sélection permettent une sélection des transformations en fonction de la structure de l'instance source. Ce type de requête permet au système de proposer à l'utilisateur un choix de transformations pré-sélectionnées.

L'utilisation de requêtes de sélection permet de spécifier la génération des éléments cibles par construction (SgmlQL, XSL). Cette spécification permet de mêler des éléments fixes et des éléments identifiés dans le document source par les requêtes.

Cette approche permet une expression plus lisible de la structure produite par la transformation mais est limitée lorsque cette structure est dépendante de la structure de l'instance source. Par exemple la spécification de la transformation d'une liste ne doit pas présupposer de connaître le nombre d'éléments contenus dans la liste. Dans ce cas il est nécessaire d'étendre la syntaxe des règles de génération avec des opérateurs de contrôle permettant de spécifier qu'une structure doit être crée autant de fois qu'il y a d'éléments dans la structure source. La déclaration de la production du document perd alors son aspect déclaratif et intègre une composante procédurale plus difficile à appréhender.

La complexité induite par cette approche est la raison pour laquelle nous avons cherché à combiner le mode de génération dirigé par la source et par construction des éléments cibles. La partie action des expressions de transformation que nous proposons est composé d'un ensemble de règles de génération décrivant chacune la construction d'une branche dans la structure des éléments engendrés. Ces règles sont relatives à des éléments identifiés dans la requête et déclenchées lors d'un parcours dans l'ordre préfixe des éléments reconnus par cette même requête.

Ainsi, nous avons expérimenté la technique de transformation explicite dans un environnement d'édition de documents HTML. Nous avons étendu le mécanisme et nous avons adapté l'interface pour prendre en compte l'édition de nouvelles structures telles que HTML 4.0 et MathML (Mathematical Markup Language). Ce système de transformation est présenté dans la section suivante.

3.4 Les transformations explicites dans Amaya

L'éditeur de documents HTML Amaya [Quint 94] est développé à l'INRIA par une équipe du consortium W3C. Nous avons implémenté dans cet éditeur une fonction de transformation d'éléments HTML et XML [Bonhomme 96]. Cette expérience nous a permis d'évaluer les techniques de transformation explicite, de sélection de structures par requêtes et d'application des règles dirigées par la source. L'intégration de ce système dans un éditeur interactif lui confère quelques spécificités que n'ont pas les systèmes de transformation présentés précédemment.

Il est nécessaire que les transformations intervenant lors de l'édition du document soient performantes : le délai d'attente ne doit pas excéder la seconde. C'est pourquoi nous n'utilisons que des méthodes rapides de transformation (expressions régulières, application des règles dirigées par la source).

Amaya utilise une représentation structurée des documents édités. La structure des documents édités reste continuellement en conformité avec la DTD HTML (contrôle de structure strict). Par conséquent, les structures produites par le système de transformation doivent également produire des éléments conformes à la DTD.

Les transformations effectuées lors de l'édition ne portent généralement pas sur l'ensemble du document mais sur un nombre limité d'éléments choisis par l'utilisateur.

L'interface utilisateur doit être simple et rendre dans la mesure du possible les transformations transparentes. Pour cela, nous nous appuyons sur la sélection effectuée par l'utilisateur et les menus et boutons d'édition proposant à l'utilisateur les types d'éléments définis par la DTD. Les transformations sont spécifiées à l'avance, dans un fichier. L'utilisateur n'a pas besoin de connaître ce fichier et n'a pas à spécifier les transformation au moment où il veut les effectuer.

Nous avons voulu proposer un système de transformation explicite demandant une expression minimale des transformations. Plus précisément, nous voulons permettre de n'exprimer que les transformations des éléments de structure qui subissent des modifications, le système devant se charger de copier des éléments dont la structure est inchangée.

3.4.1 Interface utilisateur

Deux interfaces utilisateur sont proposées pour les transformations dans Amaya impliquant deux modes d'interaction avec le système de transformation. L'utilisateur peut demander explicitement la transformation de la sélection courante par l'entrée de menu Transformer. Il peut également déclencher une transformation en sélectionnant un passage du document et en sélectionnant un type d'élément dans une palette.

Dans le premier cas, l'ensemble des transformations pouvant s'appliquer à la sélection est proposé à l'utilisateur dans un menu construit dynamiquement, lui permettant ainsi de sélectionner la transformation voulue. Nous appellerons par la suite ce mode d'interaction appel explicite.

Dans le second cas, la première transformation (dans l'ordre de leur déclaration) produisant le type d'élément demandé et applicable à la sélection courante est déclenchée. L'utilisateur n'a pas forcément conscience qu'il provoque une transformation de structure et n'interagit qu'une fois avec le système. C'est, par exemple, ce qui se produit lorsqu'une table est sélectionnée et que l'on clique sur l'icône Liste de la barre de boutons d'Amaya. La table sélectionnée est alors transformée en en listes imbriquées. Ce mode d'interaction est nommé appel induit.

3.4.2 Spécification des transformations

Un fichier portant l'extension .trans contient la description de l'ensemble des transformations prédéfinies relatives à une DTD. Chaque transformation comprend trois composantes :

  • Le nom de la transformation qui sera présenté à l'utilisateur de façon qu'il puisse faire le bon choix dans le cas d'un appel explicite.
  • Une requête identifiant la structure des éléments source auxquels peut s'appliquer la transformation.
  • Un ensemble de règles de génération relatives à des éléments identifiés dans la requête.

Une spécification de transformations a donc la syntaxe suivante :

Transformations := Transformation +
Transformation  := Nom ':' Requete '{' Règles '}'
Nom             := TEXTE
3.4.2.1 Requêtes

Les requêtes sont des expressions comprenant les opérateurs choix (|), séquence (,), liste (+), élément optionnel (?) et contenu ([ ]) utilisés pour combiner des noeuds. Chaque noeud permet d'identifier un ensemble d'éléments de la structure du document lorsque celle-ci est confrontée aux requêtes.

Requête       :=  Exp_requete
Exp_requete   :=  Noeud | '(' Exp_choix ')' | 
'(' Exp_seq ')' | Exp_liste | Exp_option Exp_choix := Exp_requete ( '|' Exp_requete ) + Exp_seq := Exp_requete ( ',' Exp_requete ) + Exp_liste := Exp_requete Op_liste Op_liste := '+' Exp_option := '?' Exp_requete

Ces expressions décrivent une organisation de noeuds qui est utilisée comme filtre sur la structure des éléments source. Les noeuds déclarés dans les requêtes peuvent être des noeuds simples ; les éléments qu'ils permettent d'identifier sont alors reconnus quelque soit leur contenu. Une expression peut aussi spécifier des noeuds avec un contenu, appelés noeuds composés ; les éléments qu'ils permettent d'identifier sont alors reconnus si et seulement si leur contenu est reconnu.

Un noeud simple est défini par un nom de type d'élément. L'ensemble des éléments identifiés par un noeud peut être restreint par la spécification d'une présence ou d'une valeur d'attribut. Les noeuds de la requête peuvent également être nommés pour faire le lien avec les règles de génération. Plusieurs noeuds peuvent porter le même nom pour leur appliquer la même règle de génération :

Noeud         :=  Noeud_simple | Noeud_composé
Noeud_composé :=  Noeud_simple '[' Exp_requete ']'
Noeud_simple  :=  [Nom ':'] Type_elem |
              [Nom ':'] '<' Type_elem ( ' ' Attr_spec )* '>'
Nom           :=  TEXTE
Type_elem     :=  TEXTE
Attr_spec     :=  Nom_attr | Nom_attr '=' Val_attr
Nom_attr      :=  TEXTE
Val_attr      :=  '"' TEXTE '"'

Le type de l'élément peut être soit un nom de type tel qu'il est défini dans la DTD, soit un jocker (*) qui représente n'importe quel type d'élément. Si une spécification d'attribut n'est pas associée à une valeur, seule la présence de cet attribut est requise pour que l'élément soit reconnu. La valeur associée à un attribut permet de filtrer les éléments qui ont un attribut du type spécifié qui a cette valeur.

Les quelques exemples suivants illustrent la syntaxe des requêtes utilisées par Amaya. La première requête identifie une liste non vide d'éléments de type li. La seconde identifie un élément div contenant un élément h2 suivi d'une liste éventuellement vide d'éléments p ou autres.

li +
div [h2, ?(p | *)*]

L'exemple suivant permet de différentier les éléments de type h2 selon qu'ils sont dans des divisions de premier niveau (T1) ou de second niveau (T2).

div [T1:h2, *+, div [T2:h2, *+]+ ]

La requête suivante identifie les éléments de type p portant un attribut id de valeur quelconque et un attribut classe ayant la valeur commentaire parmi une liste d'éléments quelconques.

( <p id classe="commentaire"> | * )+

Les requêtes du système de transformation d'Amaya servent d'une part à la sélection des extraits de documents sur lesquels les transformations peuvent être appliquées, d'autre part à l'identification d'éléments du document pour l'application de règles de transformation. Ces requêtes sont proches de celles proposées par XSL.Une première différence avec ce dernier est qu'Amaya permet d'associer des règles à plusieurs noeuds de la requête tandis que XSL ne permet que l'utilisation d'un seul élément identifié par la requête dans une règle de construction. Une seconde différence est que les requêtes d'Amaya permettent de spécifier un contexte plus étendu dans lequel il est possible de désigner les voisins des éléments ; dans les requêtes XSL seuls les ascendants des éléments source peuvent être précisés.

Amaya ne s'appuie pas sur le mécanisme de requêtes pour la génération mais sur un parcours dirigé par la structure avec une génération arborescente des éléments résultant de la transformation. C'est pourquoi la syntaxe des requêtes et la sémantique associée est différente des systèmes Scrimshaw et SgmlQL qui utilisent les requêtes comme mode de construction du document cible.

La syntaxe que nous avons présentée est inspirée de celle des expressions régulières et plus compacte que celle de XSL qui est exprimée en XML. Cette caractéristique permet une analyse plus rapide des fichiers de transformation. La vitesse de l'interprétation est un facteur important car il est possible de modifier le fichier contenant les expressions de transformation au cours d'une session d'édition et de profiter immédiatement de ces modifications. Le fichier est alors interprété à la volée lorsqu'une transformation est déclenchée.

3.4.2.2 Règles de génération

Les règles de génération des éléments cibles sont composées d'un identifiant et de la spécification d'une branche à générer dans l'arbre de structure du document. Ces deux composantes sont séparées par le caractère '>'.

Règles      :=  Règle+
Règle       :=  Identifiant '>' Branche ';'
Identifiant :=  TEXTE

L'identifiant fait la relation entre la règle de transformation et un ensemble de noeuds de la requête. Il peut être un nom défini dans la partie requête et la règle sera alors appliquée à l'ensemble des éléments reconnus par les noeuds de la requête portant ce nom. Il est ainsi possible d'associer la même règle à un ensemble d'éléments de types différents. Par exemple, la transformation d'une table HTML en liste s'écrit :

Liste : table [tbody [tr [(Cell:td|Cell:th)]+ ] ]
   {
   tr   > :ol.li;
   Cell > ol:li; 
   }

Il est également possible, grâce au renommage des noeuds de la requête, d'associer des règles différentes à des noeuds différents, mais représentant le même type d'élément. Par exemple, la transformation suivante transforme une liste simple HTML en liste titrée ; le premier item de la liste simple (Premier:li) étant transformé en titre de liste.

Liste titrée : ul [Premier:li, (Autres:li)+]
   {
   Premier > dl:dt;
   Autres  > dl.dd;
   }

La spécification de la branche engendrée par une règle est relative à la structure engendrée par les règles précédemment appliquées. Lorsque la première règle est appliquée, la branche complète est crée. Le règles suivantes peuvent soit engendrer une nouvelle branche complète, soit engendrer une branche qui est attaché à l'un des éléments créés par la règle précédente, grâce aux éléments de placement définis ci-dessous. L'élément de plus haut niveau de la dernière branche entièrement crée est appelée élément racine de la structure produite.

Les éléments crées par l'application d'une règle sont toujours insérés après (comme frère suivant) les éléments crées par les règles précédemment appliquées. La descendance est écrite sous la forme d'une liste dont les éléments sont séparés par les caractères '.' et ':', le caractère ':' ne pouvant apparaître qu'une seule fois par règle. Ce caractère permet de séparer la branche en deux ensembles d'éléments :

  • Les éléments de placement sont ceux spécifiés à la gauche du séparateur ':'. Ces éléments permettent de spécifier la position où seront insérés les éléments créés par la règle dans la structure de l'instance en construction.
  • Les éléments de construction sont ceux spécifiés à la droite du séparateur ':'. Ces éléments sont systématiquement créés lors de l'application de la règle.
Branche    :=  [ Placement ] ':' [ Génération ] | 
               [ Génération ]
Placement  :=  Élément ( '.' Élément )*
Génération :=  Élément ( '.' Élement )* [
Fin_génération ] |
               '/'
Fin_génération := [ '.' '$' | '.' '"' TEXTE '"' ] ['#'] 
Élément    :=  Élément_simple |
Élément_attr
Élément_simple :=  Nom

L'un et l'autre de ces ensembles étant optionnels, de nombreuses combinaisons sont possibles. Nous exposons tous les cas ci-dessous en les illustrant d'un schéma de la structure engendrée par la règle. Les arbres de gauche représentent la structure engendrée avant l'application de la règle, l'arbre de droite, cette même structure après l'application de la règle. Les noeuds de placement sont représentés en vert et les noeuds de génération sont présentés en rouge. Lorsqu'ils ont une influence, nous avons représenté, dans l'arbre de gauche, les noeuds de placement et de génération de la règle précédente.

elem > T1:T2;
Cas général : des éléments de placement et de construction sont spécifiés. Les éléments de construction sont insérés comme dernier fils de l'élément de placement de plus bas niveau déjà existant.
  • T1
    • T1.1
    • T1.2
  • T1
    • T1.1
    • T1.2
    • T2

Si tous les éléments de placement ne sont pas présent dans la branche la plus à droite de la structure crée préalablement à l'application de la règle, ceux-ci sont également crées.

  • T0
    • T1
    • T2
  • T1
    • T0
      • T1
      • T2
    • T1
      • T2
elem > T1.T2:;
les éléments de construction sont omis : le contenu de l'élément source (reconnu par elem dans la requête, et identifié par data dans le schéma) est copié à la position déterminée par les éléments de placement.
  • T1
    • T1.1
    • T2
  • T1
    • T1.1
    • T2
      • data
elem > :T1.T2;
Les éléments de placement sont omis : les éléments de construction sont engendrés comme nouvelle racine de la transformation.
  • T1
    • T1.1
    • T1.2
  • 11
    • T1
      • T1.1
      • T1.2
    • T1
      • T2
elem > T1.T2;
Les éléments de placement sont omis : les éléments de construction sont crées à la même position que ceux de la dernière règle appliquée.
  • T1
    • T1.1
    • T1.2
  • T1
    • T1.1
    • T1.2
    • T1
      • T2
elem > :;
Les éléments de placement et de construction sont omis : le contenu de l'élément source (data) est copié comme frère de la racine de la transformation.
  • T0
    • T1
    • T2
  • T1
    • T0
      • T1
      • T2
    • data
elem >;
Les éléments de placement et de construction sont omis : le contenu de l'élément source (data) est copié à la position déterminée par les éléments de placement de la dernière règle appliquée.
  • T1
    • T1.1
    • T1.2
  • T1
    • T1.1
    • T1.2
    • data

La distinction entre éléments de placement et éléments de construction permet de définir de façon précise où les éléments doivent être créés ou copiés dans la structure du document. Cette approche est intermédiaire entre la génération linéaire et la génération arborescente : l'ordre des éléments dans la structure est conservé, mais ils peuvent être insérés à des niveaux de structure spécifiques. Ce choix permet de proposer une syntaxe simple pour les expressions de transformation (une liste d'éléments) tout en répondant aux besoins de transformations au cours de l'édition. Ces transformations sont localisées et interviennent sur un petit nombre d'éléments, elles ne font pas de réordonnancement d'éléments qui peuvent être perturbants pour l'utilisateur.

Contrairement aux systèmes utilisant une génération linéaire des documents cibles, il n'est pas nécessaire de spécifier l'intégralité des structures produites par la transformation, Amaya s'appuie sur le modèle générique des documents et applique une politique visant à conserver l'intégralité du contenu des éléments transformés. En conséquence, les règles de transformation ne spécifient que les niveaux de structure du document où interviennent les changements. Par exemple, les règles de la transformation exposée ci-dessus et permettant de transformer les listes en listes titrées ne spécifient que la transformation des éléments listes (ul) et item (li) en éléments liste titrées (dl), titres de listes (dt) et corps de listes titrées (dd). Le contenu des listes est implicitement transféré de la liste source dans la liste titrée, à la condition que la structure générique l'autorise.

Des symboles spéciaux peuvent être utilisés dans une règle de génération. Ces symboles permettent un autre comportement que le comportement par défaut de la génération de l'instance cible.

  • Le symbole '$' remplace le dernier élément de la règle. Il permet de transférer le noeud reconnu par la requête au lieu de ne transférer que son contenu. Ce symbole est utilisé lorsque qu'un élément source a été reconnu par un joker.

    La transformation suivante permet par exemple de transformer une séquence d'élément en liste HTML :

    Liste : (item:*)+ 
    { 
    item > ul:li.$;
    }
    
  • Le symbole '/ ' permet d'ignorer le noeud source, ce symbole remplace la totalité de la partie génération de la règle. Le contenu de l'élément reconnu par la requête n'est alors pas transféré dans la structure cible.

    La transformation suivante permet de transformer une table en liste, en ignorant le titre de la table (caption) :

    Liste : table [caption, tbody[tr[td+]+]]
    {
    caption > /;
    td      > ul:li;
    }
    
  • Le symbole '#' est utilisé lorsque plusieurs règles sont spécifiées pour un même noeud de la requête. Les règles sont alors appliquées dans l'ordre de leur déclaration. Le contenu de l'élément source reconnu est transféré lors de l'application de la règle identifiée par le symbole '#'. Dans la transformation suivante, une image est insérée avant chaque élément lien HTML (a), et le contenu de l'ancre est présenté en gras :
    A2Img : <a href>
    {
     a > <a href=a.href>.<img src="link.gif">;
     a > a:strong #;
    }
    

    Ce symbole peut être utilisé dans plusieurs règles pour dupliquer la descendance des éléments source lors de la transformation.

    Le symbole '$' peut également être utilisé lorsque plusieurs règles relatives à un même noeud sont déclarées, son rôle est alors également d'identifier la règle sur laquelle doit être transféré l'élément source et son contenu. Par exemple, la transformation suivante permet de transformer une séquence d'éléments quelconques en liste HTML et de précéder chacun d'entre eux d'une titre :

    Promo : (Item:*)+
    {
    Item > ul:li.h2."Promotion : " ;
    Item > ul.li:$ ;
    }
    

Le système de transformation d'Amaya permet également de générer des attributs sur les éléments spécifiés dans les règles de génération. Ces attributs peuvent prendre des valeurs fixes ou copier des valeurs d'attributs présents dans la structure source.

Élément_attr   :=  '<' Nom ( ' ' Attribute)* '>'
Attribute      :=  Nom '=' Value
Value          :=  Nom '.' Nom | '"' TEXTE '"'

La transformation suivante transforme une suite de paragraphes, dont certains portent des attributs style et d'autres contiennent des éléments b, en une suite de paragraphes ne portant que des attributs style et des éléments span portant un attribut style.

BtoCSS : ( p [(*|b)+])+;
   {
      p > <p style=p.style>:;
      b > p:<span style="font-face:bold;">;
   }

La règle p spécifie que chaque paragraphe de la structure source est transformé en un paragraphe portant un attribut style qui prend la valeur de l'attribut style du paragraphe original. La règle b transforme chaque élément b en un élément span et crée un attribut style attaché à cet élément. Avec la manipulation des attributs, les transformations proposées par Amaya permettent de créer une présentation spécialisée des éléments en utilisant le mécanisme des CSS2 (Cascading Style Sheets, level 2) [Bos 98] proposé par le W3C pour la présentation des documents HTML.

Il est possible de générer des feuilles de texte au cours de la transformation : le dernier noeud de la partie génération d'une règle peut être une chaîne textuelle (première règle de la transformation Promo). Si une règle qui provque la création d'éléments textuels est la seule attachée à un élément de la requête, sa descendance est alors remplacée par la feuille de texte spécifiée.

3.4.3 Déroulement d'une transformation

Nous montrons, à l'aide d'un exemple, le déroulement d'une transformation explicite dans Amaya. Nous décrivons d'abord comment sont représentées les requêtes, puis comment cette représentation est utilisée pour leur interprétation, ensuite nous expliquons comment se déroule la génération de la structure cible.

Prenons comme exemple la transformation

dans un document HTML d'une suite de titres de deux niveaux (h1 et h2) entrecoupés d'éléments quelconques (*) en une structure de liste titrées imbriquées s'écrit :

Listes Titrées:(h1,(C1:*)+,(h2,(C2:*)+)*)+;
  {
    h1 > dl:dt;
    C1 > dl.dd:*;
    h2 > dl.dd.dl:dt ;
    C2 > dl.dd.dl.dd:*; 
  }

L'ensemble des requêtes de toutes les expressions de transformation déclarées est représenté sous la forme d'un automate qui est éclaté en fonction de la profondeur des requêtes. Ainsi, l'interprétation de l'expression de transformation donnée en exemple produit l'automate de reconnaissance de structure présenté figures 23. La génération de cet automate ne se fait que lors de la première transformation d'une session d'édition. L'automate est alors gardé en mémoire et utilisé lors des transformations suivantes.

L'automate construit est éclaté de façon à obtenir un automate pour chaque niveau de structure de l'ensemble dans les requêtes interprétées. Chacun de ces automates de niveau permettant de déterminer quelles parties de requêtes reconnaissent une séquence d'éléments voisins, appelée sous-requête (partie Exp_requête de la règle Noeud_composé de la grammaire de la section 3.4.2.1).

Les transitions d'un automate de reconnaissance sont étiquetées par le nom du type correspondant à la transition et un ensemble de couples d'identificateurs : le premier identifie de façon unique la sous-requête à laquelle appartient le noeud représenté par la transition, il est appelé ide. Si la descendance de ce noeud est spécifiée par la requête, le second identificateur, appelé idinf, identifie la sous-requête définissant cette descendance dans l'automate du niveau inférieur, il est nul sinon.

L'automate présenté dans la figure 23, ne représente qu'une sous-requête et aucune transition ne fait référence à une sous-requête car aucune descendance de noeud n'est définie dans la requête. Par conséquent le couple d'identificateurs associé à chaque transition est : (ide = 1, idinf = 0).

[Here is a Drawing]

Figure 23 - Automate de reconnaissance de la requête (h1,(C1:*)+,(h2,(C2:*)+)*)+

La figure 24 montre les automates des deux niveaux de structure construits lors de l'interprétation d'une seconde requête : h1, (ol[li+]|ul[li+]) qui reconnaît un titre suivi d'une liste numérotée (ol) ou non (ul). L'interprétation de cette requête étend l'automate de niveau 0 de la figure 23 et produit un automate de niveau 1 pour reconnaître les sous-requêtes (li+). Les transitions associées aux noeuds parents des sous-requêtes référencent les transitions correspondantes dans la sous-requête par le deuxième paramètre de leur couple d'identificateurs (ul (2 1) et ol (2 2)). Notons que deux couples d'identificateurs sont associés à la transition représentant le noeud h1 dans l'automate de niveau 0 car cette transition est utilisée pour la reconnaissance des deux requêtes.

[Here is a Drawing]

Figure 24 - Automates de reconnaissance des deux requêtes

L'algorithme de reconnaissance parcourt l'arbre de structure de l'instance source depuis le niveau le plus bas jusqu'aux éléments constituant la sélection. Chaque ensemble d'éléments frères (qui ont le même parent) est analysé par l'automate du niveau correspondant. Si cet ensemble est reconnu en utilisant des transitions portant toutes un ou plusieurs identificateurs ide, ces identificateurs sont remontés au niveau supérieur et seules les transitions ayant un identificateur idinf appartenant à cet ensemble permettent la reconnaissance du niveau supérieur.

Un ensemble d'éléments frères est reconnu par un automate si et seulement si il existe une suite de transitions qui a les propriétés suivantes :

  1. La suite des noms de types associés aux transitions est égale à la suite des noms de types des éléments successifs.
  2. La suite des transitions mène à un état final de l'automate (représenté en gras sur les figures 23 et 24).
  3. Il existe au moins un ide tel que chaque transition soit définie par un couple (ide, idinf) où idinf est égal à 0 ou bien appartient à l'ensemble des ide reconnus par l'automate de niveau inférieur appliqué aux descendants de l'élément reconnu par le noeud associé à la transition.

Le résultat de la reconnaissance sur un niveau est l'ensemble des ide répondant à la troisième propriété.

Une table de nommage des éléments est construite durant la reconnaissance pour associer aux éléments de la source les règles relatives aux noeuds de la requête. L'algorithme ne détaille pas la reconnaissance d'attributs qui est une extension de l'égalité entre le type de l'élément et le type exprimé dans la requête.

Le résultat de l'évaluation de requêtes est ensemble de transformation dont les requêtes ont été reconnues par l'instance source. Dans le cas d'un appel explicite, cet ensemble est présenté à l'utilisateur pour lui permettre de sélectionner une transformation de son choix, Dans le cas d'un appel induit, la transformation correspondant à la première requête de l'ensemble est appliquée.

L'application des règles de transformation se fait lors d'un parcours de l'arbre de structure de la source. L'instance source est préalablement déconnectée du corps du document pour pouvoir générer les éléments définis dans les règles de transformation directement dans la structure du document et pouvoir ainsi vérifier qu'ils sont conformes à la structure générique du document.

La figure 25 montre la construction de l'instance cible par l'application des règles h1, C1, h2 et C2, et illustre le rôle des noeuds de placement et des noeuds de construction.

  • La règle h1 (présentée en mauve) crée l'élément de placement dl et l'élément de construction dt.
  • La première application de la règle C1 (rouge foncé) ne crée pas l'élément de placement dl car c'est déjà le dernier élément du niveau le plus haut de la structure du document cible, par contre l'élément de placement dd est créé car il ne correspond pas au type du dernier élément du second niveau de structure (dt). L'étoile en fin de règle signifie que l'élément p est copié dans la structure cible.
  • La seconde application de la règle C1 (rouge clair) ne génère pas de noeuds de placement car ceux-ci sont déjà présents dans la branche la plus à droite de la structure crée. Seul l'élément ol est copié.
  • La première application de la règle h2 (bleu foncé) crée l'élément de placement dl et l'élément de construction dt, tandis que la seconde ne crée que l'élément dt ( l'élément dl étant déjà créé par les règles précédentes).
  • L'application des règles C2 copie les éléments source (ul et table) dans la structure cible.

    • h1
    • p
    • ol
    • h2
    • ul
    • h2
    • table
  • dl
    • dt
    • dd
      • p
      • ol
      • dl
        • dt
        • dd
          • ul
        • dt
        • dd
          • table

structure source

structure cible


Figure 25 - Application des règles de transformation en liste titrée

Nous n'avons pas représenté sur la figure la descendance des éléments source. Cette descendance est simplement transférée depuis l'instance source dans les éléments correspondant dans l'instance destination. Par exemple, la descendance de h1 est transférée dans l'élément dt. Les éléments p, ol, ul et table ainsi que leur descendance sont transférés dans l'instance destination car les règles qui leur sont associées se terminent par le symbole '*'.

La transformation est effectuée par deux parcours de l'arbre de structure des éléments source. Le premier évalue les requêtes des différentes expressions de transformation, le second permet la génération des éléments de la structure cible.

Ces deux parcours sont rendus nécessaires pour laisser à l'utilisateur la possibilité de sélectionner une transformation après que la reconnaissance des requêtes a été effectuée et qu'un sous-ensemble des transformations a été pré-sélectionné. Cette interaction doit évidemment se faire préalablement à la phase de génération de l'instance cible. Dans le cas d'un appel induit, les deux parcours de la structure sont également effectués car l'algorithme de reconnaissance des requêtes effectue un parcours ascendant de l'arbre de structure de la source, tandis que la génération fait un parcours dans l'ordre préfixe, donc en descendant dans l'arbre de structure.

3.4.4 Application du système de transformations explicites d'Amaya

Le système de transformation d'Amaya a été conçu pour assister l'utilisateur dans l'élaboration de documents HTML. Alors que les autres éditeurs HTML ne proposent pas de commandes d'édition permettant la manipulation de structure, les transformations permettent à l'utilisateur de facilement structurer des documents faiblement structurés. Prenons l'exemple d'une liste que l'on voudrait changer en table : dans un éditeur quelconque il aurait fallu créer une table vide (éventuellement en spécifiant ses dimensions), et transférer un à un les contenus de chaque item de la liste dans les cellules de la table nouvellement créée. Avec Amaya, une seule transformation permet de changer une liste en table simplement en sélectionnant la liste à transformer et en cliquant sur l'icône table.

Les transformations dans Amaya se sont également avérées très utiles pour l'édition de formules mathématiques selon la DTD MathML [Ion 98]. Cette DTD XML est développée par le consortium W3C pour intégrer des formules mathématiques dans des pages Web. Les formules mathématiques MathML peuvent être très structurées : la figure 26 montre une formule mathématique et sa représentation MathML. Chaque opérateur est représenté par un (ou plusieurs) élément de structure, reflétant l'arbre syntaxique de la formule.

[Here is a formula]
<msqrt> <mfrac>
  <mrow>
   <msup>
    <mi>x</mi>
    <mn>2</mn>
   </msup>
   <mo>+</mo>
   <msup>
    <mi>y</mi>
    <mn>2</mn>
   </msup>
  </mrow>  
  <mn>2</mn>
</mfrac> </msqrt>

Figure 26 - Une formule mathématique et sa représentation MathML

La nature structurée des équations mathématiques est utile pour les applications interprétant la structure de ces équations, mais elle ne se prête pas facilement à l'édition. Par exemple, il est naturel pour un utilisateur de saisir le numérateur avant d'indiquer qu'il en train de saisir une fraction, ce comportement implique la création du contenu d'un élément avant de créer l'élément lui-même (ici la fraction). Il est nécessaire d'opérer une transformation de structure pour englober le numérateur dans l'élément fraction.

Amaya permet, grâce aux transformations, de sélectionner une expression mathématique et de choisir ensuite l'opérateur dans laquelle cette expression doit être insérée. Ce mode d'édition, combiné avec une palette contenant les opérateurs mathématiques permet une édition interactive des formules mathématiques reproduisant le schéma naturel de la rédaction.

Nous avons expérimenté le mécanisme de transformation d'Amaya dans l'éditeur Thot qui permet de manipuler des objets de diverses natures. L'objectif de cette expérience était d'évaluer l'apport de cette technique dans un environnement d'édition générique pour répondre à la problématique de cette thèse.

Cette expérience nous a montré que les transformations explicites ne sont pas adaptées aux environnements d'édition de documents structurés génériques. En effet, la transformation des éléments nécessite la spécification des transformations qui sont applicables à la DTD qui définit ces éléments. Les documents édités par Thot appartiennent à un ensemble de DTD susceptible d'augmenter au cours du temps. La réalisation d'un système de transformation complet pour un tel environnement passe par la spécification de transformation pour chacune des DTD utilisées, mais aussi en ces DTD. Sauf dans certains cas d'application très spécifiques, dans lesquels les transformations par filtre décrites au début de ce chapitre peuvent suffire, la définition des transformations devient alors une tâche trop importante comparativement à l'utilisation qui en est faite.

3.5 Synthèse

Après avoir présenté les méthodes de transformation explicites et les outils exploitant ces différentes méthodes ainsi que notre expérimentation de la transformation explicite, nous tirons des conclusions sur l'utilisation de cette approche dans notre problématique.

Les systèmes de transformation dirigés par la source sont performants (de l'ordre du nombre de noeuds de l'instance source). Cependant ce jugement doit être nuancé lorsque le contexte des éléments cibles doit être pris en compte. Le coût supplémentaire est minime lorsque seulement les frères précédents et ancêtres de l'élément (contexte gauche immédiat) doivent être considérés, cette information pouvant être conservée lors de l'application des règles précédentes. Le surcoût peut s'avérer important dès qu'un ensemble d'éléments constitue le contexte, principalement les éléments suivant l'élément en cours de transformation, ou la descendance de cet élément (contexte droit).

Les règles de transformation dépendantes du contexte posent des problèmes lors de l'implémentation du mécanisme de transformation :

  • Place mémoire : le contexte doit être stocké en mémoire pour être utilisé lors de la transformation. Pour de gros documents, le nombre d'éléments à transformer peut être important (de l'ordre d'une dizaine de milliers d'éléments pour un document d'une centaine de pages). Pour pallier à cet inconvénient, certains systèmes tels que Balise limitent l'étendue du contexte gauche et ne mémorisent que le frère précédent et les ancêtres de l'élément traité.

    Ce problème se pose pour les applications qui traitent le document comme un flot de données. C'est le cas des applications bâties sur un parser. Un outil qui stocke tout l'arbre du document en mémoire pour d'autres fonctions que la transformation peut accéder à tous les éléments de la structure sans nécessiter de mémoire supplémentaire.

  • Performance : la sélection des règles de transformation en fonction du contexte de l'élément source implique la confrontation de la spécification avec le contexte courant. Les algorithmes de comparaison d'arbres sont coûteux.

Un autre point important en la défaveur des transformations dirigées par la source est qu'elles ne permettent pas de réaliser toutes les catégories de transformations. En particulier, elles ne permettent pas de mettre en oeuvre des transformations impliquant un ordonnancement différent des éléments dans la structure.

La transformation par requêtes nécessite une représentation de la structure d'un document en mémoire pour pouvoir appliquer des algorithmes de pattern-matching sur ces structures ([Kilpeläinen 92], [Cai 90], [Hoffmann 82]).

L'utilisation des requêtes pour la sélection d'une transformation ou d'un sous-ensemble des règles de transformations telles qu'elles sont utilisées dans XSL n'est pas pénalisante du fait de la localité des requêtes. Par contre, les requêtes permettant l'extraction d'information doivent traiter la structure entière du document à chaque évaluation, au détriment des performances du système d'évaluation de ces requêtes.

En contrepartie, des transformations complexes peuvent être réalisées en utilisant l'approche par requêtes, comme celles impliquant des déplacements d'éléments dans la structure des documents ou impliquant un changement dans l'ordre des éléments. Ces transformations ne peuvent pas être réalisées avec l'approche dirigée par la source et la génération linéaire.

Pour l'édition interactive, l'intérêt de l'approche par requête est la possibilité de sélection des règles à appliquer en fonction de la structure du document source. Ainsi, comme il a été montré dans le système de transformation d'Amaya, une même expression de transformation peut s'appliquer à un ensemble d'éléments n'ayant pas exactement la même configuration structurelle.

Le tableau de la figure 27 synthétise les caractéristiques des systèmes de transformation explicites étudiés :

  • Le langage dans lequel doivent être exprimées les transformations peut être un langage de programmation ou un langage spécifique (en italique). Les langages spécifiques ont l'avantage d'être adaptés à l'expression des transformations, mais nécessitent un apprentissage particulier.
  • Les méthodes de transformation proposées telles qu'elles ont été exposées dans la section 3.3.1.
  • La méthode de génération du document cible : dans le cas de la transformation arborescente, le tableau précise si la transformation permet la génération d'un nouveau document ou change la structure du document source (transformation sur place).
  • Le domaine d'application du système de transformation (voir section 3.3.4).
Méthode de
transformation Génération
LangageDirigée par la source Requête
action
Linéaire Arborescente Applications
IDM C++
Script
oui oui (scripts) non oui non filtres de conversion
Balise Balise oui oui non non sur place / nouveau
CoST 2 Tcl non oui non oui non
DSSSL Scheme non non oui non nouveau formatage
XSL XML ECMA oui (scripts) non oui non nouveau formatage
Chameleon Graphique non oui non
Scrimshaw Scrimshaw non non oui non
Amaya trans non oui (ordre) oui non sur place édition
interactive

Figure 27 - Tableau comparatif des systèmes de transformation explicite.

La plupart des systèmes de transformation explicites nécessitent une expression extensive de la transformation des documents. C'est à dire que la spécification nécessite une description de la transformation de chacun des éléments du document source..

La déclaration des transformations entre documents structurés nécessite non seulement une connaissance de la syntaxe du langage de transformation, mais également la connaissance des DTD source et cible. Cependant, la plupart des outils de transformation ne vérifient pas la conformité du document produit par rapport à sa DTD. Parmi les systèmes présentés, seul Amaya, qui est un environnement d'édition basé sur la syntaxe, Balise, qui est une bibliothèque de développement d'applications utilisant les documents structurés, et Chameleon, qui permet de spécifier des transformations à partir d'une représentation sous forme de grammaire des DTD, vérifient la conformité du document cible avec son modèle.

Notre objectif est de proposer un service de transformation de documents structurés prenant en compte la validité du document cible par rapport à sa DTD. Cette caractéristique est à notre sens essentielle pour un système de transformation. En effet, l'édition de documents structurés utilise des mécanismes qui se fondent sur la structure et qui supposent que les documents sont conformes à leur structure générique.

Lors de la création d'éléments comme lors de la transformation d'éléments, la conformité d'un document dépend non seulement de son type, de celui de son père et de ses frères, mais en plus, les mécanismes d'inclusion, d'exclusion (au sens SGML) et d'héritage impliquent que la validité d'une instance dépende du contexte du document entier. Ainsi, il n'est pas possible de décider de la validité d'une transformation à partir de sa seule spécification. Par conséquent, la validité des éléments insérés ne peut être vérifiée par le système que lorsque la transformation est effectuée.

Nous abordons dans le chapitre suivant une approche plus formelle du modèle de documents structurés. Nous définissons clairement ce que sont les types d'éléments que nous manipulons et les relations entre ces types qui seront utilisées pour la transformation. Ainsi nous pourrons proposer un système de transformation de basant sur les structures génériques des types d'éléments nous garantissant par construction la validité de la structure des éléments crées.

Notre objectif n'est pas seulement de proposer des transformations garantissant le maintien de la validité du document, mais aussi de s'appuyer sur les relations entre les types des éléments concernés pour proposer un mécanisme de transformation automatique.


[Section 4] [Table of contents]