Utiliser XML comme format d'échange de données, en utilisant prototype.js

17 mars 2008Ajax, XML, prototype.js
 Cet article a été rédigé il y a plusieurs années et peut ne plus être tout à fait à jour…

Nous avons vu il y a déjà pas mal de temps (plus d'un an, en fait !) comment Utiliser JSON comme format d'échange de données avec le Framework prototype.js. A présent, nous allons voir comment faire la même chose en utilisant XML comme format de données échangées.


Introduction

Historiquement, le format de données utilisé pour les échanges entre client et serveur en Ajax est le XML - c'est d'ailleurs de là que vient le X de "Asynchronous Javascript And Xml" !

Cela dit, il n'est pas rare de voir d'autres format être utilisés ; parmi eux, on trouve notamment :

  • HTML : Lorsque le serveur renvoi des portions de pages entières, autant les envoyer en HTML, et ensuite les injecter dans le document via la propriété innerHTML - c'est plus rapide, en temps de développement, que de traiter des données, et les injecter dans le DOM "à la main" !
  • JSON : Lorsque l'on souhaite manipuler les données en JavaScript, les renvoyer depuis le serveur sous forme de "Notation Objet JavaScript" facilite souvent les choses !

Mais ce n'est pas toujours vous qui choisissez le format de données - et HTML et JSON ne sont pas toujours les plus appropriés pour répondre à votre besoin.
Il peut dont vous être utile de savoir gérer, côté client, des données renvoyées au format XML par le serveur.

Comme souvent, je commencerai cet article par la présentation de la page côté navigateur, qui effectue la requête Ajax.
Je passerai ensuite au programme serveur, pour finir en revenant côté client, avec l'utilisation de cette réponse.


Envoi d'une requête Ajax depuis le client

Pour émettre une requête Ajax côté client, deux éléments sont nécessaires :

  • Une page HTML - toute simple, en l'occurrence
  • Et une portion de code JavaScript

Page HTML cliente

Tout d'abord, voici le code de ma page HTML :

<?php header('Content-type: text/html; charset=UTF-8'); ?>
<?php echo '<?xml version="1.0" encoding="UTF-8"?>'; ?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
 "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html>
<head>
  <title>Ajax et XML avec Prototype.js</title>
  <script type="text/javascript" src="lib/prototype/prototype.js"></script>
  <script type="text/javascript" src="test-1.js"></script>
</head>
<body>
    <p>
        <a href="#" onclick="gestionClic(); return false;">Cliquez-ici</a>
    </p>
    <div id="resultat">&nbsp;</div>
</body>
</html>

Quelques points à noter :

  • Inclusion du Framework JavaScript prototype.js (en version 1.6.0.2, ici)
  • Inclusion du fichier JS au sein duquel nous développerons
  • Ajout d'un lien ; c'est lors du clic sur celui-ci que nous déclencherons l'appel Ajax
  • Et un élément "resultat", que nous utiliserons pour affichages en sortie.


JavaScript déclenchant la requête Ajax

Côté JavaScript, rien de nouveau, si vous avez déjà lu quelques uns des articles de ce blog à propos de prototype.js :

var gestionClic = function ()
{
    var myAjax = new Ajax.Request(
      './test-server.php',
      {
        method: 'get',
        parameters: {},
        onSuccess: function (xhr)
          {
            
            // Ici, utilisation de la réponse
            
          } // onSuccess
      }
    );
};

Une fois que nous saurons comment gérer une réponse au format XML, nous n'aurons qu'à compléter ;-)


Génération d'une réponse au format XML sur le serveur

Côté serveur, dans un cas réel, nous construirions dynamiquement du XML par rapport à des données dépendant de la requête reçue depuis le client.
Ici, dans un cas d'exemple... des données "en dur" suffiront :

<?php header('Content-type: text/xml; charset=UTF-8'); ?>
<?php echo '<?xml version="1.0" encoding="UTF-8"?>'; ?>
<personnes>
    <personne id="1">
        <nom>Lerdorf</nom>
        <prenom>Rasmus</prenom>
    </personne>
    <personne id="4">
        <nom>Gutmans</nom>
        <prenom>Andi</prenom>
    </personne>
    <personne id="9">
        <nom>Suraski</nom>
        <prenom>Zeev</prenom>
    </personne>
</personnes>

Quelques points à noter :

  • Nous avons trois "personne"s, chacune contenant une information "nom" et d'une information "prenom"
  • Chacune de nos trois personnes est porteuse d'un attribut nommé "id"

Pour être interprétées comme une réponse au format XML une fois parvenues côté client, il est important que les données soient accompagnées du bon en-tête HTTP : leur Content-type doit être "text/xml".


Traitement de cette réponse au format XML, sur le client

Lorsque le serveur envoie des données au format XML (et reconnaissables comme telles côté client, via le Content-type: text/xml), elles sont rendues disponibles via la propriété responseXML de l'instance d'objet XmlHttpRequest utilisée pour effectuer la requête.

prototype.js passe cet objet en paramètre à la fonction de callback que nous avons branché sur l'événement success - appelé en fin de requête, lorsque celle-ci a fonctionné correctement.

Cela signifie que, dans notre fonction onSuccess, utiliser xhr.responseXML nous donne accès à l'objet Document contenant les données envoyées en réponse.

Notre fonction gestionClic peut donc devenir :

var gestionClic = function ()
{
  var myAjax = new Ajax.Request(
    './test-server.php',
    {
      method: 'get',
      parameters: {},
      onSuccess: function (xhr)
        {
          // Objet Document contenu dans la propriété responseXML
          var nodePersonnes = xhr.responseXML;
          var nodesPersonne = nodePersonnes.firstChild.getElementsByTagName('personne');
          
          var output = '';
          for (i=0 ; i<nodesPersonne.length ; i++)
          {
            var nodePersonne = nodesPersonne[i];
            
            var attributes = nodePersonne.attributes;
            var id = attributes.getNamedItem('id').nodeValue;
            
            var nodeNom = nodePersonne.getElementsByTagName('nom')[0];
            var nom = nodeNom.firstChild.nodeValue;
            
            var nodePrenom = nodePersonne.getElementsByTagName('prenom')[0];
            var prenom = nodePrenom.firstChild.nodeValue;
            
            output += id + ' - ' 
                         + nom.toUpperCase() 
                         + ' - ' + prenom.capitalize() 
                         + '<br />';
          }
          $('resultat').innerHTML = output;
        } // onSuccess
    }
  );
};

Le parcours de la liste d'éléments "personne" peut aussi se faire en utilisant les fonctionnalités d'itérateurs fournies par prototype.js :

var gestionClic = function ()
{
  var myAjax = new Ajax.Request(
    './test-server.php',
    {
      method: 'get',
      parameters: {},
      onSuccess: function (xhr)
        {
          // Objet Document contenu dans la propriété responseXML
          var nodePersonnes = xhr.responseXML;
          var nodesPersonne = nodePersonnes.firstChild.getElementsByTagName('personne');
          
          var output = '';
          $A(nodesPersonne).each(function (nodePersonne)
            {
              var attributes = nodePersonne.attributes;
              var id = attributes.getNamedItem('id').nodeValue;
              
              var nodeNom = nodePersonne.getElementsByTagName('nom')[0];
              var nom = nodeNom.firstChild.nodeValue;
              
              var nodePrenom = nodePersonne.getElementsByTagName('prenom')[0];
              var prenom = nodePrenom.firstChild.nodeValue;
              
              output += id + ' - ' 
                        + nom.toUpperCase() 
                        + ' - ' + prenom.capitalize() 
                        + '<br />';
            });
          $('resultat').innerHTML = output;
        } // onSuccess
    }
  );
};

La différence est que nous avons utilisé la fonction $A pour transformer la liste d'éléments DOM en une liste Enumerable de prototype.js, ce qui nous permet ensuite de lui appliquer l'ensemble des fonctions proposées par ce mixin.


Conclusion

Renvoyer depuis le serveur des données au format XML a, à mes yeux, deux avantages - qui se recoupent :

  • XML est un format de données extrêmement répandu, et, donc, compris par tous - humains ou langages de programmation, d'ailleurs
  • L'API DOM permettant de manipuler des documents XML est standardisée, et disponibles dans la plupart des langages de programmation - utiliser XML augmente donc la portabilité de votre code !
    • D'ailleurs, vous trouverez dans le fichier joint à cet article une implémentation PHP faisant appel à notre "Web Service", et effectuant les mêmes manipulations que notre code JavaScript. Vous verrez que le code est exactement le même (aux différences de langage près, bien évidemment).

Cela dit, dans le cadre d'une application orientée JavaScript (ce qui est souvent le cas lorsque l'on réalise des appels Ajax)... J'ai généralement tendance à privilégier le format JSON pour mes échanges de données, du fait de sa simplicité de manipulation via ce langage.
Le format XML étant, à mes yeux, à privilégier dans le cas où l'interopérabilité est primordiale.


MAJ 03/04/2008 : Ajout en pièce jointe à l'article d'une archive contenant un exemple complet