Mozilla Transformations XML avec CSS et DOM

  • Document original : oreillynet.com
  • Date orignale : 15 octobre 2002
  • Auteur : Scott Andrew LePera
  • Publication : © Copyright 2002 Scott Andrew LePera
  • Traduction : Bruno Ethvignot, Dimitri Lecas, François Constantineau
  • Mise à jour : 14/10/2005

Pendant que l'adoption du XHTML continue de s'étendre aux cercles du développement web, la question inévitable se pose : ne pouvons-nous vraiment pas nous passer du désagréable HTML spécifique au navigateur et créer nos documents en pur XML ?

XML dans le navigateur a été le sujet de beaucoup de discussions animées au sujet du développement web avant-gardiste. Certains estiment que le remplacement de HTML par XML ne peut recuillir une audience importante en raison d'un manque d'agents utilisateurs pouvant correctement l'analyser et l'afficher. D'autres estiment que XML est vraiment approprié au serveur ou s'utilise seulement comme une structure descriptive de données et n'a aucune place dans le monde visuel du Web qui est déjà bien déservi par le HTML.

Malgré cela, la nouvelle génération de navigateurs possède de puissantes capacités XML. Les récentes versions de Mozilla offrent un analyseur syntaxique (ou parseur) et un moteur de rendu qui supportent les technologies XML comme les feuilles de style XML, les espaces de noms XML, XLink, SVG et MathML. Avec son support natif de SOAP et les prochaines implémentations de WSDL et de XSLT, Mozilla est assuré de devenir un puissant lecteur parmi les logiciels clients XML.

Mozilla permet aussi d'avoir un rendu du XML dans le navigateur avec CSS et de le manipuler avec le DOM. C'est un réel avantage pour tout ceux d'entre nous désirant expérimenter des transformations XML (à la fois visuelles et structurelles) sans devoir fouiller dans des technologies peu familières comme XPath, le langage naturel de XSLT pour parcourir le DOM. Si vous êtes déjà familier avec les CSS et le DOM, vous êtes plus qu'à mi-chemin de la réalisation de transformations XML dans Mozilla.

Cet article montre clairement la façon d'afficher du XML dans le navigateur avec un minimum de CSS et de JavaScript. Les exemples suivant ont été écrits et testés avec Mozilla 1.0 sur Linux Mandrake 9.0, Mac OS X et Win2K. Cet article n'est pas une initiation complète sur le DOM, CSS, ou XML et une compréhension de base de chacune de ces technologies est souhaitable.

Le fichier XML d'exemple

J'ai choisi un fichier RSS épuré pour fournir un exemple XML à cet article. J'aurais pu choisir n'importe quel document XML au hasard, mais RSS est utilisé dans l'objectif particulier de la syndication de contenu, souvent des nouvelles et des articles de journaux Web (weblog) et est idéal pour démontrer les bases des transformations avec les CSS et le DOM. Tout au long de cet article, je montrerai comment utiliser les CSS pour appliquer un style de mise en forme aux éléments RSS et comment utiliser l'interface du DOM de niveau 2 pour parcourir et transformer le résultat. A la fin de cet article, je créerai (une esquisse évidemment ) un lecteur de RSS basé sur le navigateur alimenté lui même pas des RSS.

La première chose a faire est mettre en forme les éléments XML existants avec CSS. Comme avec le HTML, c'est accompli avec un lien sur une feuille de style.

Application d'un style

Une feuille de style XML est généralement importée via une instruction de traitement xml-stylesheet dans l'en-tête du document XML. C'est analogue à l'utilisation de la balise link en HTML pour importer une CSS et la syntaxe est semblable :

<?xml version="1.0"?>
<?xml-stylesheet href="rss.css" type="text/css"?>

À la différence du HTML, aucune supposition n'est faite sur le formatage des éléments XML de la part du processeur. Un navigateur comprend (implicitement ou autrement) qu'un élément <P> HTML est un objet de mise en forme de type en bloc, tandis que <EM> est un objet de mise en forme de type en ligne. De même, un navigateur peut supposer sans risque que l'écriture en gras est le formatage par défaut d'un texte à l'intérieur d'un élément HTML <strong>. Ce n'est pas ainsi avec du XML brut, en le reliant à un un document CSS, les règles de base pour la mise en forme visuelle de chaque élément et son contenu peuvent être données au processeur.

Je dois d'abord décider quels éléments sont à formater comme des éléments de bloc. Puisque tous les éléments sont affichés par défaut sur une seule ligne, j'ai seulement besoin d'indiquer les éléments de bloc dans la feuille de style. Je commencerai en définissant l'affichage, la police et les propriétés des cadres des éléments rss, channel et item :

rss
{
    display:block;
    margin:10px;
}

channel
{
    display:block;
    height:300px;
    width:280px;
    border:1px solid #000;
    overflow:auto;
    background-color:#eee;
    font: 12px verdana;
}

item
{
    display: block;
    padding:10px;
    margin-bottom:10px;
    border-top:1px solid #ccc;
    border-bottom:1px solid #ccc;
    background-color:#fff;
}

A ce point, je ne suis pas vraiment intéressé par certains éléments de la métadonnée channel, donc j'utiliserai display:none pour les supprimer de la sortie visuelle. Notez que cela n'enlève pas les éléments du document; si j'avais voulu le faire, j'aurai utilisé la méthode du DOM appropriée pour les enlèver par programmation. J'y arriverai un peu plus tard. Je veux garder les éléments du channel title et description, donc je ferai mon CSS ainsi :

channel>title, channel>description
{
    display: block;
    margin-left:10px;
    margin-top:10px;
    background-color:#eee;
    font-weight:bold;
}

channel>title
{
    font-size:16px;
}

channel>description
{
    font-size:10px;
    margin-bottom:10px;
}

item>title
{
    font-weight:bold;
}

item>link, channel>link, channel>language
{
    display: none;
}

Pour vérifier mon style de mise en page, je démarre Mozilla 1.0 et lui donne mon document RSS. Voici le résultat jusqu'ici :

photo écran : XML avec CSS appliqué

Comme vous pouvez le voir, mettre en page du XML avec une CSS est aussi simple que de faire la même chose en HTML. Mais j'ai un problème : Aucun de mes liens ne sont de vrais liens. C'est-à-dire qu'ils ne se comportent pas comme des liens HTML quand je clique dessus. Je dois trouver une façon de transformer les éléments link de RSS en des liens opérationnels. CSS est mal assorti pour fournir cette sorte de fonctionnalité, mais j'ai un autre outil à ma disposition : DOM.

Transformations avec le DOM

Si vous êtes déjà familier avec l'utilisation de l'interface du DOM de niveau 2 pour manipuler le HTML, la partie suivante doit vous être familière. Voici l'approche de base :

  1. Identifiez et obtenir les références de tous les éléments paires title et link du document RSS.
  2. Extraire le texte de chaque paire.
  3. Créez un lien XHTML (<a>) avec le titre et le texte de l'URL indiquées.
  4. Remplacez l'élément title par le lien HTML dans le document.

Le code suivant utilise la méthode getElementsByTagName du DOM pour récupérer un ensemble de références d'élément item du document XML. La boucle for qui suit réitère sur l'ensemble et obtient les références de chaque éléments title et link. Finalement, le texte du titre et du lien sont d'abord extraits en faisant référence au noeud de texte de chacun, puis à la propriété nodeValue du noeud :

var allItems = document.getElementsByTagName("item");
for (var i=0;i<allItems.length;i++)
{
    var itemElm = allItems[i];
    var titleElm = itemElm.getElementsByTagName("title").item(0);
    var titleText = titleElm.firstChild.nodeValue;
    var linkElm = itemElm.getElementsByTagName("link").item(0);
    var linkURL = linkElm.firstChild.nodeValue;
}

Ceci fournit la partie nécessaire qui établit un lien HTML approprié de chaque item du RSS. Cependant, un peu code supplémentaire est nécessaire pour que tout fonctionne.

Traiter avec les espaces de noms

Le concept des espaces de noms XML est devenu une recommandation du W3C en 1999. Ils existent pour permettre aux éléments XML de différents schémas d'être mélangés sans entrer en conflit. Par exemple, XHTML a un élément title, tout comme RSS. Pour empêcher un analyseur syntaxique XML de confondre les deux, un espace de noms est déclaré dans l'élément racine du document XML. L'espace de nom se compose d'un préfixe associé à une URI et est utilisé pour distinguer des éléments et des attributs importés d'autres spécifications XML.

Les balises suivantes montrent comment importer un élément XHTML img dans un document RSS :

<?xml version="1.0"?>
<rss version="0.91" xmlns:xhtml="http://www.w3.org/1999/xhtml">
  <channel>
    <title>scottandrew.com</title>

    <link>http://www.scottandrew.com</link>
    <xhtml:img src="/img/photo.jpg" alt="Handsome pic of Scott"/>
  ...
</rss>

L'attribut xmlns associe le préfixe de l'espace de nom "xhtml" avec l'URI. De cette façon, un analyseur syntaxique XML est averti que l'élément img existe dans un espace de nom à l'extérieur de celui par défaut. (bien sûr, il n'y a aucune garantie, pour que l'analyseur syntaxique sache quoi faire avec img, puisque tous les analyseurs syntaxiques XML ne sont pas nécessairement des navigateurs.)

En utilisant l'interface du DOM avec un document XHTML, il est supposé que tous les nouveaux éléments créés par programmation avec createElement sont en fait des éléments XHTML. Les spec du DOM de niveau 2 donnent une méthode distincte pour la création d'éléments venant d'un espace de nom différent. La méthode createElementNS accepte deux arguments : une chaîne faisant référence à l'URI de l'espace de nom et une chaîne représentant l'élément à créer :

var xhtml = "http://www.w3.org/1999/xhtml";
var newLinkElm = document.createElementNS(xhtml,"a");

Puisque mon application est destinée à être lue par un navigateur, je peux utiliser createElementNS pour importer un élément <a> XHTML dans mon document RSS. Avec l'information recueillie par l'opération DOM précédente, je peux assigner un attribut href au nouvel élément <a>, puis créer et insérer un nouveau noeud texte. Puisque l'attribut href, comme l'élément <a> lui-même, est importé du XHTML, je dois utiliser la méthode setAttributeNS. Cette méthode fonctionne exactement comme la méthode setAttribute du DOM 2 et utilise un argument supplémentaire déclarant l'espace de nom de l'attribut.

Finalement, je remplace l'élément TITLE RSS de cette item avec l'élément <a> XHTML , en utilisant la méthode replaceChild du DOM 2 pour le faire. Mozilla doit maintenant permettre au titre de l'item de se comporter comme un lien XHTML. Voici le code complet de mon script parcourant les noeuds :

var xhtml = "http://www.w3.org/1999/xhtml";
var allItems = document.getElementsByTagName("item");
for (var i=0;i<allItems.length;i++)
{
    var itemElm = allItems[i];
    var titleElm = itemElm.getElementsByTagName("title").item(0);
    var titleText = titleElm.firstChild.nodeValue;
    var linkElm = itemElm.getElementsByTagName("link").item(0);
    var linkURL = linkElm.firstChild.nodeValue;

    var newLinkElm = document.createElementNS(xhtml,"a");
    var txtNode = document.createTextNode(titleText);
    //newLinkElm.setAttributeNS(xhtml,"href",linkURL); // NDT : incorrect voir plus bas
    newLinkElm.setAttributeNS("","href",linkURL);
    newLinkElm.style.display = "block";
    newLinkElm.appendChild(txtNode);
    itemElm.replaceChild(newLinkElm,titleElm);
}

Attachement du script

Pour implémenter ceci, je dois associer le script avec le document RSS pour que ces transformations du DOM puissent avoir lieu à l'exécution. Au moment où j'écris ces lignes, je n'ai pas pu trouver une façon convenable pour associer un fichier de script externe avec un document XML (à la différence des xml-stylesheet, il ne semble y avoir aucune instruction de traitement "xml-script" équivalente et il semble douteux que le W3C aille dans ce sens). Il n'y a aucune méthode "onload" d'un document RSS, donc je vais avoir besoin d'un plan d'attaque différent.

En utilisant une déclaration d'espace de noms XML je peux importer un élément XHTML script et l'insérer comme le dernier élément dans la racine du document RSS. Mettre l'appel du script à la fin force le document à être chargé en mémoire avant que le JavaScript ne soit exécuté :

<?xml version="1.0"?>
<?xml-stylesheet href="rss.css" type="text/css"?>
<rss version="0.91" xmlns:xhtml="http://www.w3.org/1999/xhtml">
  <channel>
    <title>scottandrew.com</title>
    <link>http://www.scottandrew.com</link>

    <description>DHTML, DOM and JavaScript News</description>
    <language>en-us</language>
    <!-- ITEM elements go here -->
  </channel>
  <xhtml:script type="text/javascript" src="rss.js" />

</rss>

Le chargement du fichier RSS dans Mozilla produit maintenant le résultat désiré : des titres qui soient des liens cliquables. Vous pouvez voir un exemple fonctionnant ici, bien que vous ayez besoin de Mozilla 1.0 ou une version supérieure pour pouvoir le tester.

NDT : L'exemple orginal donné par Scott Andrew ne fonctionnait que dans les navigateurs dérivés de la branche de Mozilla 1.0, comme Mozilla 1.0.2, Netscape 7, Chimera 0.6, ... Mais les liens crées dynamiquement ne fonctionnaient plus à partir de Mozilla 1.1, et le bogue 184744 avait été ouvert sur bugzilla laissant penser à une regression. Cependant d'après Boris Zbarsky, l'instruction newLinkElm.setAttributeNS(xhtml,"href",linkURL); était incorrecte, puisque l'attribut href d'un élément <a> XHTML doit être dans un espace de nom nul. L'exemple donné par Scott Andrew fonctionne dans les navigateurs dérivés de la branche de Mozilla 1.0 pour la seule raison que la version 1.0 a un bogue dans le traitement des attributs des espaces de nom. En remplaçant l'instruction précédente par l'instruction newLinkElm.setAttributeNS("","href",linkURL);, l'exemple fonctionne bien dans Mozilla 1.0 et plus. (testé dans Mozilla 1.3b sous Linux et Netscape 7.02 sous Mac OS 9).

Une approche alternative : XLink

Mozilla supporte les hyperliens de base via XLink comme alternative à l'importation XHTML. Avec XLink, il n'y a pas besoin de créer un nouvel élément. Au lieu de cela, la fonctionnalité d'hyperliens vient de l'attachement d'attributs XLink à l'élément en question, faisant ainsi de n'importe quel élément un lien potentiel.

Pour accomplir cela, fixez les attributs XLink appropriés à l'item de l'élément title avec la méthode setAttributeNS. Voici une version modifiée du JavaScript qui incorpore XLink au lieu de XHTML :

var xlink = "http://www.w3.org/1999/xlink";
var allItems = document.getElementsByTagName("item");
for (var i=0;i<allItems.length;i++)
{
    var itemElm = allItems[i];

    var titleElm = itemElm.getElementsByTagName("title").item(0);
    var linkElm = itemElm.getElementsByTagName("link").item(0);
    var linkURL = linkElm.firstChild.nodeValue;

    titleElm.setAttributeNS(xlink,"type","simple");
    titleElm.setAttributeNS(xlink,"show","replace");
    titleElm.setAttributeNS(xlink,"href", linkURL);
}

Directions futures

Il a été avancé qu'il serait préférable que les développeurs web continuent à faire du HTML valide 4.01 tant que les agents utilisateurs ne seront pas capables de faire une analyse et un rendu XML corrects. Peut-être. Cependant comme je l'ai démontré, quelques agents utilisateurs sont déjà bien préparés pour traiter le XML. Le puissance des CSS et du DOM dans les transformations XML a amené pour beaucoup la question de savoir si des technologies comme XSLT sont vraiment nécessaires. Je ne fais pas telles revendications, mais si les capacités de Mozilla 1.0 sont un signe, l'avenir de XML sur le Web est accessible et s'annonce bien sans aucun doute.


Faire un commentaire.

(Site mise a jour le mardi 16 mars 2004)

Ce document à une CSS valide Ce document est conforme au XHTML 1.0