Ajax

L’intégration du javascript dans les pages html a permit de rendre le web plus dynamique.

Ainsi il eest devenu possible de rendre visible des éléments de pages sans recharger cette dernière. Le client web devient avec le javascript de plus en plus lourd et de moins en moins léger.

Ajax (acronyme d’Asynchronous JavaScript and XML) a permit une nouvelle étape: via l’utilisation du javascript et d’ajax il est devenu possible de poser des questions aux serveurs et de traiter les réponses.

Il est alors possible d’ajouter dans une page sans la recharger des informations provenant du serveur web.

Cette pratique permet:

  • des gains dans les échanges (on ne rechareg pas n fois la même page et on échange que des infos utilent)
  • un côté dynamique (la page peux changer suivant des paramètres)

Dans la pratique les données échangées avec l’utilisation d’ajax sont de type:

  • string
  • json
  • xml

Le format string n’est pas intérressant car non structuré.

Le choix entre Json et XML est difficile et je n’ai pas trouvé de vrai benchmark indiquant une préférence.

Mon choix ce porte sur le XML car:

  • python le supporte (json aussi mais bon)
  • utilisation de xslt possible
  • traitement et lecture des données plus clair

Note

cet article ne traite pas de la partie javascript/jquery

Pour l’ensemble des exempel nous allons utiliser

  • un serveur python/bottle
  • le framework jquery
Dir
 |_ test.py
 |_static
    |_ jquery-1.9.1.min.js

utilisation simple

Dans cet exemple nous allons simplement via un boutton ajouter un message dans une page html.

le fichier xml échanger ce présente ainsi

_images/20130519_1.png

le programme test.py est le suivant

from bottle import route, run, request, response,  static_file
from xml.dom.minidom import getDOMImplementation
import sys

import string
from random import sample


test1_txt="""
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Parser du XML avec jQuery</title>
<script type="text/javascript" src="static/jquery-1.9.1.min.js"></script>
<script type="text/javascript">
$(function(){

    $('.recupMsg').click(function(){
        $.ajax({
            type: "GET",
            url: "hello",
            dataType: "xml",
            success : function(xml) {
                var appendHtml = "";
                $(xml).find('msg').each(function(){
                    var txt = $(this).text();
                    appendHtml += txt+"<br/>";
                });
                $("#result").append(appendHtml);
            }});
    });
});
</script>
</head>
<body>
    <div id="container">
        <button class="recupMsg">Recuperer le message</button>
        <div id="result"></div>
    </div>
</body>
</html>
"""



@route('/static/:filename')
def jequery_file(filename):
    return static_file(filename, root='./static')

@route('/hello')
def hello():
    impl = getDOMImplementation()
    newdoc = impl.createDocument(None,"sample",None)
    top_element = newdoc.documentElement
    att = newdoc.createElement('msg')
    txt = newdoc.createTextNode('Hello World!')
    att.appendChild(txt)
    top_element.appendChild(att)

    response.headers['Content-Type'] = 'text/xml'
    return newdoc.toxml('iso-8859-15')


@route('/test1')
def test1():
    return test1_txt

on obtient donc sur l’adresse http://127.0.0.1:8080/test1 le résultat suivant

_images/20130519_2.png

ce qui correspond au html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Parser du XML avec jQuery</title>
<script type="text/javascript" src="static/jquery-1.9.1.min.js"></script>
<script type="text/javascript">
$(function(){

    $('.recupMsg').click(function(){
        $.ajax({
            type: "GET",
            url: "hello",
            dataType: "xml",
            success : function(xml) {
                var appendHtml = "";
                $(xml).find('msg').each(function(){
                    var txt = $(this).text();
                    appendHtml += txt+"<br/>";
                });
                $("#result").append(appendHtml);
            }});
    });
});
</script>
</head>
<body>
    <div id="container">
        <button class="recupMsg">Recuperer le message</button>
        <div id="result"></div>
    </div>
</body>
</html>

après avoir cliquer sur le boutton nous obtenons

_images/20130519_3.png

ce qu’il faut noter:

  • l’utilisation de jquery

  • l’appel en cas de succès à une fonction traitant le xml (il faudrait ajouter la fonction en cas d’echec: error)

  • il est possible de traiter l’arbre dom par différente fonction

    • $(this).find(‘tutu’)
    • $(this).attr(‘id’)
    • $(this).text()
    • children(), parent(), ...

utilisation avec passage de paramètre

le principe est d’envoyer une requête au serveur avec des paramètres pour obtenir un fichier xml du type

_images/20130519_4.png

le programme test.py est le suivant

from bottle import route, run, request, response,  static_file
from xml.dom.minidom import getDOMImplementation
import sys

import string
from random import sample


pop = string.ascii_letters + string.digits


test2_txt="""
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Parser du XML avec jQuery</title>
<script type="text/javascript" src="static/jquery-1.9.1.min.js"></script>
<script type="text/javascript">
$(function(){

    $('#target').submit(function(){
        $.ajax({
            type: "POST",
            url: "getpassword",
            dataType: "xml",
            data: $('#target').serialize(),
            success : function(xml) {
                var appendHtml = "";
                appendHtml += $(xml).find('username').text() +"<br/>";
                appendHtml += $(xml).find('password').text() +"<br/>";
                $("#result").append(appendHtml);
            }});
    return false;
    });
});
</script>
</head>
<body>
    <form id="target" action="">
        username <input type=text name="username"><br/>
        length <input type=text name="length"><br/>
        <input type="submit" value="Envoyer">
    </form>
    <div id="result"></div>
</body>
</html>
"""

@route('/static/:filename')
def jequery_file(filename):
    return static_file(filename, root='./static')

@route('/test2')
def test2():
    return test2_txt


@route('/getpassword', method='POST')
def getpassword():
    username = request.forms.get('username')
    length = int(request.forms.get('length'))
    passwd = ''.join(sample(pop, length))

    impl = getDOMImplementation()
    newdoc = impl.createDocument(None,"sample",None)
    top_element = newdoc.documentElement
    att = newdoc.createElement('username')
    txt = newdoc.createTextNode(unicode(username,'iso-8859-15'))
    att.appendChild(txt)
    top_element.appendChild(att)
    att = newdoc.createElement('password')
    txt = newdoc.createTextNode(passwd)
    att.appendChild(txt)
    top_element.appendChild(att)

    response.headers['Content-Type'] = 'text/xml'
    return newdoc.toxml('iso-8859-15')

run(host='localhost', port=8080)

on obtient donc sur l’adresse http://127.0.0.1:8080/test2 le résultat suivant

_images/20130519_5.png

ce qui correspond au html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>Parser du XML avec jQuery</title>
<script type="text/javascript" src="static/jquery-1.9.1.min.js"></script>
<script type="text/javascript">
$(function(){

    $('#target').submit(function(){
        $.ajax({
            type: "POST",
            url: "getpassword",
            dataType: "xml",
            data: $('#target').serialize(),
            success : function(xml) {
                var appendHtml = "";
                appendHtml += $(xml).find('username').text() +"<br/>";
                appendHtml += $(xml).find('password').text() +"<br/>";
                $("#result").append(appendHtml);
            }});
    return false;
    });
});
</script>
</head>
<body>
    <form id="target" action="">
        username <input type=text name="username"><br/>
        length <input type=text name="length"><br/>
        <input type="submit" value="Envoyer">
    </form>
    <div id="result"></div>
</body>
</html>

après avoir cliquer sur le boutton nous obtenons

_images/20130519_6.png

ce qu’il faut noter:

  • l’utilisation de jquery
  • l’utilisation de la méthode post
  • utilisation de la fonction serialize qui permet le passage des paramètres

on peut remplacer la fonction serialize par un code du type

/* data: $('#target').serialize(), */
data: "username=fred&length=10",

mais cela signifie qu’il faut traiter tout les champs et les exceptions

$('#target').submit(function(){
    var username = $(this).find("input[name='username']").val();
    var length = $(this).find("input[name='length']").val();
    $.ajax({
        type: "POST",
        url: "getpassword",
        dataType: "xml",
        data: "username="+username+"&length="+length,
        success : function(xml) {
            var appendHtml = "";
            appendHtml += $(xml).find('username').text() +"<br/>";
            appendHtml += $(xml).find('password').text() +"<br/>";
            $("#result").append(appendHtml);
        }});
return false;
});