Poster une réponse 
 
Note de cette discussion :
  • Moyenne : 0 (0 vote(s))
  • 1
  • 2
  • 3
  • 4
  • 5
Vos utilisations de XML
Auteur Message
Roworll Hors ligne
Membre

Messages : 722
Inscription : Dec 2006
Réputation : 14
Message : #11
RE: Vos utilisations de XML
Citation :Ca m'a l'air très intéressant. Peux-tu développer un peu s'il te plaît ?
Bien sur.
Le système de traduction est composé de trois éléments:

1 - Le fichier XML qui contient les chaines à traduire

J'ai un fichier par page et par langue.
Ces fichiers n'ont pas de headers XML car ils sont destinés à être inclus dans le XML renvoyé par PHP

Voici par exemple le fichier welcome-fr.xml
Code PHP :
<labels>
    <
label name="name">Pseudo</label>
    <
label name="pass">Mot de Passe</label>
    <
label name="enter">Entrer</label>
    <
label name="lost">Codes Oubliés ?</label>
    <
label name="remem">Se Rappeler</label>
    <
label name="browsers">Accostez avec</label>
    <
label name="access">Accéder à la Station</label>
</
labels
Le fichier welcome-en.xml
Code PHP :
<labels>
    <
label name="log">Login</label>
    <
label name="pass">Password</label>
    <
label name="enter">Enter</label>
    <
label name="lost">Password Lost?</label>
    <
label name="remem">Remember me</label>
    <
label name="browsers">Dock with</label>
    <
label name="access">Enter the Station</label>
</
labels

2 - Le fichier PHP qui va créer le XML

L'application traine une variable de session qui contient le nom de la langue en cours (fr, en, etc)
Code PHP :
    $_xml ='<?xml version="1.0" encoding="UTF-8"?>';
    
$_xml.='<?xml-stylesheet type="text/xsl" href="./xsl/welcome.xsl"?>';
    
$_xml.='<page xml:lang="'.$_SESSION['ST_Lng'].'" theme="'.$_SESSION['ST_Theme'].'" pgname="welcome">';
    
$_xml.=$_SESSION['ST_Menu'];
    
$_xml.=$_SESSION['ST_ThemeParam'];
    
$_xml.='<elem>welcome</elem>';
    
$rsN=db_query('SELECT news_id, news_title, news_text, news_date, news_img, news_lng, player_id, player_name FROM news LEFT JOIN players ON news_player_id = player_id WHERE news_lng=\''.$_SESSION['ST_Lng'].'\' ORDER BY news_date DESC limit 0,10');
    
$_xml.='<news>';
    while(
$lnN=mysql_fetch_array($rsN)){
        
$_xml.='
            <new>
                <id>'
.$lnN['news_id'].'</id>
                <title>'
.$lnN['news_title'].'</title>
                <text>'
.nl2br($lnN['news_text']).'</text>
                <date>'
.strftime('%Y-%m-%d',$lnN['news_date']).'</date>
                <img>'
.$lnN['news_img'].'</img>
                <lng>'
.$lnN['news_lng'].'</lng>
                <player id="'
.$lnN['player_id'].'">'.$lnN['player_name'].'</player>
            </new>'
;
    }
    
$_xml.='</news>';
    
//C'est ici que je rajoute mon fichier XML de traduction
    
$_xml.=file_get_contents('xml/welcome-'.$_SESSION['ST_Lng'].'.xml');
    
$_xml.='</page>';

    
header ('content-type: text/xml');
    echo 
$_xml

3 - Le fichier XSL qui va transformer la page

C'est lui qui va mettre en place toutes les informations.

Voici le morceau de code ou on affiche les zones de saisie login/password
Code PHP :
<!-- Le Login-->
<
xsl:value-of select="/page/labels/label[@name='log']" /> <input type="text" maxlength="30" size="10" name="login_name" /><br />
<!-- 
Le Mot de Passe-->
<
xsl:value-of select="/page/labels/label[@name='pass']" /> <input type="password" maxlength="30" size="10" name="login_password" /><br />
<!-- 
Le Bouton de validation-->
<
input type="submit" class="button" value="{/page/labels/label[@name='enter']}" /> 

Au final, si ma variable de session contient 'fr', j'aurai à l'écran
Pseudo [ ]
Mot de Passe [ ]
[Entrer]

Si ma variable de session contient 'en', j'aurai
Login [ ]
Password [ ]
[Enter]

Gros avantage encore une fois, cette transformation est faite sur le client.
PHP se limite à envoyer du XML, ce qui limite grandement la charge.

---------------------------------------------------------

Citation :Tu es obligé de passer par une bibliothèque pour lire les attributs et les noeuds enfants, non ?
Uniquement lorsque j'ai besoin d'exploiter le XML dans PhP.
Vu que 95% du temps je ne fais que créer du XML pour l'envoyer brut vers le client, je me contente de faire une grosse chaine de caractére.
Par exemple :
Code PHP :
    $_xml ='<?xml version="1.0" encoding="UTF-8"?>';
    
$_xml.='<?xml-stylesheet type="text/xsl" href="./xsl/stats.xsl"?>';
    
$_xml.='<page xml:lang="fr" title="Statistiques">';
    
$_xml.=getGuilds();
    
$_xml.='<statcls>';
    
$rsC=db_query("SELECT count(*) as tot, char_class FROM characters, guilds WHERE char_hide=0 AND char_guild_id=guild_id and guild_game='vg' GROUP BY char_class");
    while(
$lnC=mysql_fetch_assoc($rsC)){
        
$_xml.='<stat total="'.$lnC['tot'].'">'.$lnC['char_class'].'</stat>'
    }
    
$_xml.='</statcls>';
    
$_xml.='<statart>';
    
$rsC=db_query("SELECT count(*) as tot, char_art FROM characters, guilds WHERE char_hide=0 AND char_guild_id=guild_id and guild_game='vg' GROUP BY char_art");
    while(
$lnC=mysql_fetch_assoc($rsC)){
        
$_xml.='<stat total="'.$lnC['tot'].'">'.$lnC['char_art'].'</stat>'
    }
    
$_xml.='</page>';

    
disconnect();
    
header ('content-type: text/xml');
    echo 
$_xml
Pas besoin d'utiliser SimpleXML pour créer le XML que je vais envoyer au client.
Une simple concaténation de chaine est aussi efficace et moins gourmande en ressources / temps.

Par contre, si j'ai besoin à l'intérieur d'un module PHP de lire un élément du fichier XML ou de modifier un XML existant, SimpleXML s'impose.
03-23-2007 09:22 AM
Trouver tous les messages de cet utilisateur Citer ce message dans une réponse
denisc Hors ligne
Membre

Messages : 385
Inscription : Nov 2006
Réputation : 7
Message : #12
RE: Vos utilisations de XML
C'est plus long que d'envoyer la page avec les textes en dur dans la bonne langue tout ça, non?
Ca donne plus de trafic dans les tuyaux : 2 fichiers au lieu d'un seul !
D'autant que si c'est regénéré à chaque fois que l'utilisateur appelle la page, l'intérêt me semble très limité sur cet exemple !

FarmWars : http://farmwars.plein2jeux.fr --> maj 01/01/08 : Inscriptions fonctionnelles
03-23-2007 02:12 PM
Trouver tous les messages de cet utilisateur Citer ce message dans une réponse
Roworll Hors ligne
Membre

Messages : 722
Inscription : Dec 2006
Réputation : 14
Message : #13
RE: Vos utilisations de XML
Le XSL se met en cache sur le client (à l'instar des css).
Les 2 fichiers ne sont envoyés que la 1ere fois.
La seule partie dynamique est le XML qui est régénéré par PHP à chaque fois

Supposes que tu appelles la même page 10 fois.
Avec un moteur de template tu auras 10 fois le process de traduction / remplacement effectué sur le serveur d'ou augmentation de la charge.

Par XML/XSL, tu n'envoies que les données et c'est le client qui mettra 10 fois la traduction en place.

Gain de performance du serveur.
03-23-2007 02:23 PM
Trouver tous les messages de cet utilisateur Citer ce message dans une réponse
denisc Hors ligne
Membre

Messages : 385
Inscription : Nov 2006
Réputation : 7
Message : #14
RE: Vos utilisations de XML
Va falloir que je trouve une formation pour ça... XSLT, je connais pas plus que XML 10

FarmWars : http://farmwars.plein2jeux.fr --> maj 01/01/08 : Inscriptions fonctionnelles
03-23-2007 02:25 PM
Trouver tous les messages de cet utilisateur Citer ce message dans une réponse
Roworll Hors ligne
Membre

Messages : 722
Inscription : Dec 2006
Réputation : 14
Message : #15
RE: Vos utilisations de XML
Un autre exemple un peu plus parlant.
Regarde sur cette page http://vanguard.steel-titans.net/roster.php5

Le fichier source est en XML (pas mis en forme... trop feignasse et ca prends plus de bande passante de coller des retour à la ligne et des tabulations partout).
Aved le XSL approprié, à partir d'une source unique, j'affiche 5 présentations différentes !

J'ai un fichier source de 32Ko, un fichier XSL de 33 Ko et la version HTML finale fait 518Ko !!!

Imagine si c'est PHP qui doit créer ce monstre et tout envoyer à partir du serveur !
Pour info, le temps de traitement PhP avoisine les 0.015s.
(Ce message a été modifié le : 03-23-2007 02:38 PM par Roworll.)
03-23-2007 02:37 PM
Trouver tous les messages de cet utilisateur Citer ce message dans une réponse
denisc Hors ligne
Membre

Messages : 385
Inscription : Nov 2006
Réputation : 7
Message : #16
RE: Vos utilisations de XML
Peux-tu poster ou envoyer par mail les deux fichiers sources de cette page stp?

FarmWars : http://farmwars.plein2jeux.fr --> maj 01/01/08 : Inscriptions fonctionnelles
03-23-2007 07:25 PM
Trouver tous les messages de cet utilisateur Citer ce message dans une réponse
Roworll Hors ligne
Membre

Messages : 722
Inscription : Dec 2006
Réputation : 14
Message : #17
RE: Vos utilisations de XML
Arf j'avais oublié de répondre à ce topic.
Voici les pages qui me permettent de générer le roster

Le code PHP (j'ai mis de cote lee code des includes)
Code PHP :
require './lib/sessions.php';
require 
'./lib/dbaccess.php';

connect();
$_xml ='<?xml version="1.0" encoding="UTF-8"?>';
$_xml.='<?xml-stylesheet type="text/xsl" href="./xsl/roster.xsl"?>';
$_xml.='<page xml:lang="fr" title="Effectifs">';
// Petite fonction pour récupérer le contenu de la liste déroulante des guildes.
$_xml.=getGuilds();

$lnG=mysql_fetch_assoc(mysql_query("SELECT * FROM guilds WHERE guild_id='".$_SESSION['VG_Guild']."'"));
$_xml.='<guild>';
$_xml.='<name>'.$lnG['guild_name'].'</name>';
$_xml.='<link>'.$lnG['guild_page'].'</link>';
$_xml.='</guild>';
    
$_xml.='<members>';
$rsC=db_query("SELECT char_nom, char_class, char_titre, char_game_id, char_niv, char_art, char_artniv, char_rank, char_joined FROM characters WHERE char_hide=0 AND char_guild_id='".$_SESSION['VG_Guild']."'");
while(
$lnC=mysql_fetch_assoc($rsC)){
    
$_xml.='<member>';
    
$_xml.='<id>'.$lnC['char_game_id'].'</id>';
    
$_xml.='<name>'.$lnC['char_nom'].'</name>';
    
$_xml.='<titre>'.$lnC['char_titre'].'</titre>';
    
$_xml.='<class>'.$lnC['char_class'].'</class>'
    
$_xml.='<niv>'.$lnC['char_niv'].'</niv>';
    
$_xml.='<art>'.$lnC['char_art'].'</art>';
    
$_xml.='<artniv>'.$lnC['char_artniv'].'</artniv>';
    
$_xml.='<joined>'.$lnC['char_joined'].'</joined>';
    
$_xml.='<rank>'.$lnC['char_rank'].'</rank>';
    
$_xml.='</member>';
}
$_xml.='</members>';

$_xml.='<ranks>';
$rsC=db_query("SELECT DISTINCT char_rank FROM characters WHERE char_hide=0 ND char_guild_id='".$_SESSION['VG_Guild']."'");
while(
$lnC=mysql_fetch_assoc($rsC)){
    
$_xml.='<rank>'.$lnC['char_rank'].'</rank>';
}
$_xml.='</ranks>';

$_xml.='    
<classes>
    <class type="2">Bard</class>
    <class type="3">Blood Mage</class>
    <class type="3">Cleric</class>
    <class type="3">Disciple</class>
    <class type="1">Dread Knight</class>
    <class type="4">Druid</class>
    <class type="2">Monk</class>
    <class type="4">Necromancer</class>
    <class type="1">Paladin</class>
    <class type="4">Psionicist</class>
    <class type="2">Ranger</class>
    <class type="2">Rogue</class>
    <class type="3">Shaman</class>
    <class type="4">Sorcerer</class>
    <class type="1">Warrior</class>
</classes>'
;
$_xml.='    
<crafts>
    <craft>Crafter</craft>
    <craft>Blacksmith</craft>
    <craft>Outfitter</craft>
    <craft>Artificer</craft>
</crafts>'
;
$_xml.='    
<types>
    <type id="1">Defensive Fighter</type>
    <type id="2">Offensive Fighter</type>
    <type id="3">Healer</type>
    <type id="4">Mage</type>
</types>'
;

$_xml.=getPageTime();
$_xml.='</page>';

disconnect();
header ('content-type: text/xml');
echo 
$_xml

Un extrait du XML généré. J'ai mis des ... à certains endroits plutôt que la longue liste fastidieuse des guildes/membres.
Code PHP :
<?xml version="1.0" encoding="UTF-8"?>
<?xml
-stylesheet type="text/xsl" href="./xsl/roster.xsl"?>
<page xml:lang="fr" title="Effectifs">
    <guilds cur="2" refresh="1">
        <guild id="2" page="124554051626" server="Infineum">Archanges</guild>
        <guild id="3" page="111669149947" server="Gelenia">Ordre de la Lune Noire</guild>
        <guild id="4" page="124554051616" server="Infineum">Compagnie d'Ombre Rune</guild>
        <guild id="5" page="124554051657" server="Infineum">La Confrerie de l'Acier</guild>
        <guild id="6" page="124554051628" server="Infineum">Les Chevaliers de Lethantis</guild>
        <guild id="7" page="124554051620" server="Infineum">Ordre du fleau</guild>
        <guild id="8" page="124554051640" server="Infineum">La Gargote de Telon</guild>
        <guild id="9" page="124554051686" server="Infineum">La Lune Rousse</guild>
        ...
        <guild id="45" page="111669150064" server="Gelenia">Lames Sylvestres</guild>
        <guild id="46" page="111669149829" server="Gelenia">Leviathan</guild>
        <guild id="47" page="111669149974" server="Gelenia">Obsidien</guild>
        <guild id="48" page="111669149779" server="Gelenia">Secret Circle</guild>
        <guild id="49" page="111669149756" server="Gelenia">Vae Victis</guild>
    </guilds>
    <guild>
        <name>Archanges</name>
        <link>124554051626</link>
    </guild>
    <members>
        <member>
            <id>124554106390</id>
            <name>Agron</name>
            <titre>Amateur Outfitter</titre>
            <class>Monk</class>
            <niv>14</niv>
            <art>Outfitter</art>
            <artniv>11</artniv>
            <joined>0007-02-17</joined>
            <rank>Member</rank>
        </member>
        <member><id>124554080709</id>
            <name>Akema</name>
            <titre>Armorsmith</titre>
            <class>Warrior</class>
            <niv>11</niv>
            <art>Blacksmith</art>
            <artniv>31</artniv>
            <joined>0007-02-12</joined>
            <rank>Leader</rank>
        </member>
        <member><id>124554072557</id>
            <name>Alhonso</name>
            <titre>Novice Artificer</titre>
            <class>Bard</class>
            <niv>21</niv>
            <art>Artificer</art>
            <artniv>8</artniv>
            <joined>2007-03-10</joined>
            <rank>Member</rank>
        </member>
        <member><id>124554149857</id>
            <name>Alwin</name>
            <titre></titre>
            <class>Druid</class>
            <niv>14</niv>
            <art>Crafter</art>
            <artniv>1</artniv>
            <joined>2007-03-24</joined>
            <rank>Initiate</rank>
        </member>
        <member><id>124554063715</id>
            <name>Anarki</name>
            <titre></titre>
            <class>Paladin</class>
            <niv>25</niv>
            <art>Blacksmith</art>
            <artniv>3</artniv>
            <joined>0007-02-02</joined>
            <rank>Leader</rank>
        </member>
        ...
        <member><id>124554077409</id>
            <name>Zoukata</name>
            <titre></titre>
            <class>Shaman</class>
            <niv>18</niv>
            <art>Blacksmith</art>
            <artniv>7</artniv>
            <joined>0007-02-15</joined>
            <rank>Member</rank>
        </member>
    </members>
    <ranks>
        <rank>Member</rank>
        <rank>Leader</rank>
        <rank>Initiate</rank>
        <rank>Undefined</rank>
        <rank>Elder</rank>
        <rank>Officer</rank>
    </ranks>    
    <classes>
        <class type="2">Bard</class>
        <class type="3">Blood Mage</class>
        <class type="3">Cleric</class>
        <class type="3">Disciple</class>
        <class type="1">Dread Knight</class>
        <class type="4">Druid</class>
        <class type="2">Monk</class>
        <class type="4">Necromancer</class>
        <class type="1">Paladin</class>
        <class type="4">Psionicist</class>
        <class type="2">Ranger</class>
        <class type="2">Rogue</class>
        <class type="3">Shaman</class>
        <class type="4">Sorcerer</class>
        <class type="1">Warrior</class>
    </classes>    
    <crafts>
        <craft>Crafter</craft>
        <craft>Blacksmith</craft>
        <craft>Outfitter</craft>
        <craft>Artificer</craft>
    </crafts>    
    <types>
        <type id="1">Defensive Fighter</type>
        <type id="2">Offensive Fighter</type>
        <type id="3">Healer</type>
        <type id="4">Mage</type>
    </types>
    <ts>1175149747.8694</ts>
    <pagetime>0.018</pagetime>
    <querycount>3</querycount>
    <querytime>0.006</querytime>
</page> 


Le XSL
Il est plus touffu car il contient un peu de JS pour la présentation par onglets et le tri des tables.
Je fournis le code brut, sans commentaires mais je veux bien expliquer certains passages.
Désolé pour le manque de couleurs mais le XML passe moyen.
Code PHP :
<?xml version="1.0" encoding="UTF-8" ?>
<xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:import href="com-xsl.xsl" />
<xsl:output method="html"    encoding="utf-8"    doctype-public="-//W3C//DTD XHTML 1.0 Strict//EN" doctype-system="http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd" />

<xsl:template match="/">

<html>
<head>
    <xsl:call-template name="header"><xsl:with-param name="title" select="/page/@title"/></xsl:call-template>
    <script language="javascript" type="text/javascript">
    <![CDATA[
    function switchDetail(o){
        r=o.nextSibling.nextSibling;
        if(r.style.display==''){
            r.style.display='none';
            o.innerHTML=' [ + ]';
        } else {
            r.style.display='';
            o.innerHTML=' [ - ]';
        }
    }
    
    var toSort='';
    var aSort=new Array();
    
    function sort(x,v){
        var a=new Array();
        typSort=v;
        var t=x.parentNode.parentNode;

        if(!aSort[t.id]){
            aSort[t.id]=new Array();
            aSort[t.id][2]=1;
        } else {
            if(aSort[t.id][1]==x.cellIndex) {
                aSort[t.id][2]*=-1;
            } else {
                aSort[t.id][2]=1;
            }
        }
        aSort[t.id][1]=x.cellIndex
        aSort[t.id][0]=x.cellIndex;
        toSort=t.id;

        //Passage de la table en tableau js
        for(var r=1;r<t.rows.length;r++){
            a[r-1]=new Array();
            for(var c=0;c<t.rows[r-1].cells.length;c++){
                a[r-1][c]=t.rows[r].cells[c].innerHTML;
            }
        }
        a.sort(sortTable);

        while(t.rows.length>1) t.deleteRow(t.rows[1].rowIndex);

        for(var r=0;r<a.length;r++){
            nr=t.insertRow(r+1);
            for(var c=0;c<a[r].length;c++){
                nc=nr.insertCell(c);
                nc.innerHTML=a[r][c];
            }
        }
    }
    
    function sortTable(e1,e2){
        if(typSort==0){
            if(stripHTML(e1[aSort[toSort][0]]) >= stripHTML(e2[aSort[toSort][0]])){
                r=1;
            } else {
                r=-1;
            }
        } else {
            r=e1[aSort[toSort][0]] - e2[aSort[toSort][0]]
        }
        return r * aSort[toSort][2];
    }

    function stripHTML(oldString) {
      return oldString.replace(/<[^>]*>/g, "");
    }
    
    function setTab(x){
        document.getElementById('craft').style.display='none';
        document.getElementById('class').style.display='none';
        document.getElementById('global').style.display='none';
        document.getElementById('rank').style.display='none';
        document.getElementById('type').style.display='none';
        document.getElementById('tabcraft').className='taboff';
        document.getElementById('tabclass').className='taboff';
        document.getElementById('tabglobal').className='taboff';
        document.getElementById('tabrank').className='taboff';
        document.getElementById('tabtype').className='taboff';
        document.getElementById(x).style.display='';
        document.getElementById('tab'+x).className='tabon';
    }
    
    ]]>
    </script>
</head>
<body style=" margin:0px; padding:0px;">
    <div>
        <xsl:variable name="totmember" select="count(//member)" />
        <div class="title">Effectif de Guilde
        <xsl:apply-templates select="/page/gname" />
        <xsl:apply-templates select="/page/guilds" /></div>
        <div id="loginfo" />
        <div class="menu">
            <xsl:call-template name="menu"/>
        </div>
        <div class="header">
        Voici les informations concernant la guilde <b><a href="http://vgplayers.station.sony.com/guildsProfiles.vm?guildId={/page/guild/link}" target="_blank"><xsl:value-of select="/page/guild/name"/></a></b>
        <br />
        </div>
        <div>
        Nombre total de membres : <xsl:value-of select="$totmember" /><br />
        </div>
        <br />
        
        <div style="border:solid black 1px; border-left:none; overflow:visible; width:700px;">
            <div id="tabglobal" class="tabon"  onClick="setTab('global');" onMouseOver="this.style.backgroundColor='#CCCCCC'" onMouseOut="this.style.backgroundColor='transparent'">Vue Générale</div>
            <div id="tabclass"  class="taboff" onClick="setTab('class');"  onMouseOver="this.style.backgroundColor='#CCCCCC'" onMouseOut="this.style.backgroundColor='transparent'">Par Classe</div>
            <div id="tabcraft"  class="taboff" onClick="setTab('craft');"  onMouseOver="this.style.backgroundColor='#CCCCCC'" onMouseOut="this.style.backgroundColor='transparent'">Par Artisanat</div>
            <div id="tabrank"   class="taboff" onClick="setTab('rank');"   onMouseOver="this.style.backgroundColor='#CCCCCC'" onMouseOut="this.style.backgroundColor='transparent'">Par Rang</div>
            <div id="tabtype"   class="taboff" onClick="setTab('type');"   onMouseOver="this.style.backgroundColor='#CCCCCC'" onMouseOut="this.style.backgroundColor='transparent'">Par Type</div>
            <div id="global" style="clear:both;">
                <div>
                    <table style="border-left:solid black 1px;" cellspacing="0" cellpadding="2" id="srtglobal">
                        <tr style="font-weight:bold; background-color:#DDDDDD; cursor:default">
                        <td width="150" onClick="sort(this,0)">Nom</td>
                        <td width="100" onClick="sort(this,0)">Classe</td>
                        <td width="30" onClick="sort(this,1)">Niv.</td>
                        <td width="100" onClick="sort(this,0)">Artisanat</td>
                        <td width="20" onClick="sort(this,1)">Niv.</td>
                        <td width="150" onClick="sort(this,0)">Titre</td>
                        <td width="150" onClick="sort(this,0)">Rang</td>
                        </tr>
                        <xsl:for-each select="/page/members/member">
                        <xsl:sort select="name" />
                            <tr onMouseOver="this.style.backgroundColor='#DDDDDD';" onMouseOut="this.style.backgroundColor='transparent';">
                            <td><a href="http://vgplayers.station.sony.com/characters.vm?characterId={id}" target="_blank"><xsl:value-of select="name" /></a></td>
                            <td><xsl:value-of select="class" /></td>
                            <td><xsl:value-of select="niv" /></td>
                            <td><xsl:value-of select="art" /></td>
                            <td><xsl:value-of select="artniv" /></td>
                            <td><xsl:value-of select="titre" /></td>
                            <td><xsl:value-of select="rank" /></td>
                            </tr>
                        </xsl:for-each>
                    </table>
                </div>
            </div>
    
            <div id="class" style="display:none; clear:both;">
            <xsl:for-each select="/page/classes/class">
                <xsl:variable name="class" select="." />
                <xsl:variable name="total" select="count(//member[class=$class])" />
                <xsl:variable name="totlvl" select="sum(//member[class=$class]/niv)" />
                <xsl:variable name="plural">
                    <xsl:if test="$total > 1" >s</xsl:if>
                </xsl:variable>
                <xsl:variable name="totdisp">
                    <xsl:if test="$total = 0" >Aucun</xsl:if>
                    <xsl:if test="$total > 0" ><xsl:value-of select="$total"/></xsl:if>
                </xsl:variable>
                <xsl:variable name="avglvl">
                    <xsl:if test="$total = 0" ></xsl:if>
                    <xsl:if test="$total > 0" > (<xsl:value-of select="round($totlvl div $total)" />)</xsl:if>
                </xsl:variable>
                    
                <div>
                    <xsl:attribute name="style">
                        border-left:solid black 1px; padding-top:10px; padding-bottom:10px;
                        <xsl:if test="position()!=1">
                        border-top:solid black 1px; 
                        </xsl:if>
                    </xsl:attribute>
                    <span onclick="switchDetail(this)" style="cursor:pointer;"> [ + ]</span>
                    <div style="display:inline;">
                     <xsl:value-of select="date"/>
                    <xsl:value-of select="$totdisp" /> <xsl:value-of select="." /><xsl:value-of select="$plural" /> <xsl:value-of select="$avglvl" />
                    </div>
                    <table cellspacing="0" cellpadding="2" style="display:none; padding-top:10px;padding-left:10px;" id="cls-{$class}">
                        <tr style="font-weight:bold; background-color:#DDDDDD; cursor:default">
                        <td width="150" onClick="sort(this,0)">Nom</td>
                        <td width="100" onClick="sort(this,0)">Classe</td>
                        <td width="30" onClick="sort(this,1)">Niv.</td>
                        <td width="100" onClick="sort(this,0)">Artisanat</td>
                        <td width="20" onClick="sort(this,1)">Niv.</td>
                        <td width="150" onClick="sort(this,0)">Titre</td>
                        <td width="150" onClick="sort(this,0)">Rang</td>
                        </tr>
                    <xsl:for-each select="//member[class=$class]">
                        <xsl:sort select="name" />
                        <tr onMouseOver="this.style.backgroundColor='#DDDDDD';" onMouseOut="this.style.backgroundColor='transparent';">
                        <td><a href="http://vgplayers.station.sony.com/characters.vm?characterId={id}" target="_blank"><xsl:value-of select="name" /></a></td>
                        <td><xsl:value-of select="class" /></td>
                        <td><xsl:value-of select="niv" /></td>
                        <td><xsl:value-of select="art" /></td>
                        <td><xsl:value-of select="artniv" /></td>
                        <td><xsl:value-of select="titre" /></td>
                        <td><xsl:value-of select="rank" /></td>
                        </tr>
                    </xsl:for-each>
                    </table>
                </div>
            </xsl:for-each>
            </div>
    
            <div id="craft" style="display:none; clear:both;">
            <xsl:for-each select="/page/crafts/craft">
                <xsl:variable name="craft" select="." />
                <xsl:variable name="total" select="count(//member[art=$craft])" />
                <xsl:variable name="totlvl" select="sum(//member[art=$craft]/artniv)" />
                <xsl:variable name="plural">
                    <xsl:if test="$total > 1" >s</xsl:if>
                </xsl:variable>
                <xsl:variable name="totdisp">
                    <xsl:if test="$total = 0" >Aucun</xsl:if>
                    <xsl:if test="$total > 0" ><xsl:value-of select="$total"/></xsl:if>
                </xsl:variable>
                <xsl:variable name="avglvl">
                    <xsl:if test="$total = 0" ></xsl:if>
                    <xsl:if test="$total > 0" > (<xsl:value-of select="round($totlvl div $total)" />)</xsl:if>
                </xsl:variable>
                    
                <div>
                    <xsl:attribute name="style">
                        border-left:solid black 1px; padding-top:10px; padding-bottom:10px;
                        <xsl:if test="position()!=1">
                        border-top:solid black 1px; 
                        </xsl:if>
                    </xsl:attribute>
                    <span onclick="switchDetail(this)" style="cursor:pointer;"> [ + ]</span>
                    <div style="display:inline;">
                     <xsl:value-of select="date"/>
                    <xsl:value-of select="$totdisp" /> <xsl:value-of select="." /><xsl:value-of select="$plural" /> <xsl:value-of select="$avglvl" />
                    </div>
                    <table cellspacing="0" cellpadding="2" style="display:none; padding-top:10px;padding-left:10px;" id="art-{$craft}">
                        <tr style="font-weight:bold; background-color:#DDDDDD; cursor:default">
                        <td width="150" onClick="sort(this,0)">Nom</td>
                        <td width="100" onClick="sort(this,0)">Classe</td>
                        <td width="30" onClick="sort(this,1)">Niv.</td>
                        <td width="100" onClick="sort(this,0)">Artisanat</td>
                        <td width="20" onClick="sort(this,1)">Niv.</td>
                        <td width="150" onClick="sort(this,0)">Titre</td>
                        <td width="150" onClick="sort(this,0)">Rang</td>
                        </tr>
                    <xsl:for-each select="//member[art=$craft]">
                        <xsl:sort select="name" />
                        <tr onMouseOver="this.style.backgroundColor='#DDDDDD';" onMouseOut="this.style.backgroundColor='transparent';">
                        <td><a href="http://vgplayers.station.sony.com/characters.vm?characterId={id}" target="_blank"><xsl:value-of select="name" /></a></td>
                        <td><xsl:value-of select="class" /></td>
                        <td><xsl:value-of select="niv" /></td>
                        <td><xsl:value-of select="art" /></td>
                        <td><xsl:value-of select="artniv" /></td>
                        <td><xsl:value-of select="titre" /></td>
                        <td><xsl:value-of select="rank" /></td>
                        </tr>
                    </xsl:for-each>
                    </table>
                </div>
            </xsl:for-each>
            </div>
    
            <div id="rank" style="display:none; clear:both;">
            <xsl:for-each select="/page/ranks/rank">
                <xsl:variable name="rank" select="." />
                <xsl:variable name="total" select="count(//member[rank=$rank])" />
                <xsl:variable name="totlvl" select="sum(//member[rank=$rank]/niv)" />
                <xsl:variable name="plural">
                    <xsl:if test="$total > 1" >s</xsl:if>
                </xsl:variable>
                <xsl:variable name="totdisp">
                    <xsl:if test="$total = 0" >Aucun</xsl:if>
                    <xsl:if test="$total > 0" ><xsl:value-of select="$total"/></xsl:if>
                </xsl:variable>
                <xsl:variable name="avglvl">
                    <xsl:if test="$total = 0" ></xsl:if>
                    <xsl:if test="$total > 0" > (<xsl:value-of select="round($totlvl div $total)" />)</xsl:if>
                </xsl:variable>
                    
                <div>
                    <xsl:attribute name="style">
                        border-left:solid black 1px; padding-top:10px; padding-bottom:10px;
                        <xsl:if test="position()!=1">
                        border-top:solid black 1px; 
                        </xsl:if>
                    </xsl:attribute>
                    <span onclick="switchDetail(this)" style="cursor:pointer;"> [ + ]</span>
                    <div style="display:inline;">
                     <xsl:value-of select="$totdisp" />
                     <xsl:value-of select="." /><xsl:value-of select="$plural" /> <xsl:value-of select="$avglvl" />
                    </div>
                    <table cellspacing="0" cellpadding="2" style="display:none; padding-top:10px;padding-left:10px;" id="rnk-{$rank}">
                        <tr style="font-weight:bold; background-color:#DDDDDD; cursor:default">
                        <td width="150" onClick="sort(this,0)">Nom</td>
                        <td width="100" onClick="sort(this,0)">Classe</td>
                        <td width="30" onClick="sort(this,1)">Niv.</td>
                        <td width="100" onClick="sort(this,0)">Artisanat</td>
                        <td width="20" onClick="sort(this,1)">Niv.</td>
                        <td width="150" onClick="sort(this,0)">Titre</td>
                        <td width="150" onClick="sort(this,0)">Rang</td>
                        </tr>
                    <xsl:for-each select="//member[rank=$rank]">
                        <xsl:sort select="name" />
                        <tr onMouseOver="this.style.backgroundColor='#DDDDDD';" onMouseOut="this.style.backgroundColor='transparent';">
                        <td><a href="http://vgplayers.station.sony.com/characters.vm?characterId={id}" target="_blank"><xsl:value-of select="name" /></a></td>
                        <td><xsl:value-of select="class" /></td>
                        <td><xsl:value-of select="niv" /></td>
                        <td><xsl:value-of select="art" /></td>
                        <td><xsl:value-of select="artniv" /></td>
                        <td><xsl:value-of select="titre" /></td>
                        <td><xsl:value-of select="rank" /></td>
                        </tr>
                    </xsl:for-each>
                    </table>
                </div>
            </xsl:for-each>
            </div>
        
            <div id="type" style="display:none; clear:both;">
            <xsl:for-each select="/page/types/type">
                <xsl:variable name="type" select="@id" />
                <xsl:variable name="total" select="count(/page/members/member[class=/page/classes/class[@type=$type]])" />
                <xsl:variable name="totlvl" select="sum(/page/members/member[class=/page/classes/class[@type=$type]]/niv)" />
                <xsl:variable name="plural">
                    <xsl:if test="$total > 1" >s</xsl:if>
                </xsl:variable>
                <xsl:variable name="totdisp">
                    <xsl:if test="$total = 0" >Aucun</xsl:if>
                    <xsl:if test="$total > 0" ><xsl:value-of select="$total"/></xsl:if>
                </xsl:variable>
                <xsl:variable name="avglvl">
                    <xsl:if test="$total = 0" ></x