un petit annuaireun petit annuaire à visiter
unpetitannuaire
read my profile
sign my guestbook

Message: message me
Website: visit my website


Member Since: 1/17/2006

SubscriptionsSites I Read

Posting Calendar

|<< oldest | newest >>|
view all weblog archives

Get Involved!

Suggest a link

Recommend to friend

Create a site


Friday, January 20, 2006

un autre petit tutorial en java

Programmation de servlets Java

Les servlets sont des programmes écrits en Java qui permettent de traiter et de répondre à des requètes passées la plupart du temps à un serveur web les abritant. Ils peuvent donc être utilisés pour traiter des données issues d'un formulaire au sein d'une page HTML, pour la génération de pages HTML dynamiques en y incluant par exemples des informations issues de base de données. Ils sont donc probablement une réponse pertinente à la croissante complexité des sites web, notamment ceux de commerce éléctronique.
Ce tutorial, loin d'être exhaustif, a pour objectif de présenter de la manière la plus claire possible les fonctions de bases mises à disposition par l'API Servlet.
 

Plan:

Installation
Architecture de base d'un servlet
Exemple: traitement de formulaires
Maintien de sessions
Cookies
Problèmes de threading
JDBC: Java DataBase Connectivity
Servlets et transformations XSLT avec Xalan-J
Un servlet évolué: Cocoon
Upload de fichiers

1 Installation


Les sections suivants supposent que le JDK de SUN, ainsi que Apache 1.2 et spérieur ont été préalablement installé.

1.1 Installation du Kit de Développement de Servlets : le JSDK

La première étape consiste à télécharger le JSDK2.0 sur le site de SUN (ici), le décompresser puis à copier (cp -R) le répertoire JSDK2.0 dans le répertoire de votre choix (on prendra /usr/lib/ pour la suite de ce tutorial). Il faut alors mettre à jour le path en incluant /usr/lib/JSDK2.0/bin (export PATH=/usr/lib/JSDK2.0/bin:$PATH), ainsi que le classpath en y ajoutant le chemin de l'archive jsdk.jar contenant les classes (export CLASSPATH = /usr/lib/JSDK2.0/lib/jsdk.jar :$CLASSPATH sous bash).
Pour vérifier que tout s'est bien déroulé, on lance l'utilitaire servletrunner qui devrait afficher les lignes suivantes :


olly%>servletrunner
servletrunner starting with settings:
port = 8080
backlog = 50
max handlers = 100
timeout = 5000
servlet dir = ./examples
document dir = ./examples
servlet propfile = ./examples/servlet.properties

servletrunner permet de tester les servlets, c'est à dire qu'il va faire office de mini-serveur, écoutant sur un port spécifique (8080 par défaut). Il est possible de modifier les paramètres par défaut de servletrunner, notamment les flags -d suivi du répertoire contenant les servlets, et -s suivi du fichier de propriétés de la zone à considérer.
 

1.2 Installation du module côté serveur : ApacheJserv

La première étape consiste à télécharger le moteur de servlets d'Apache, ApacheJServ, puis à décompresser l'archive quelque part sur le disque, sous /tmp par exemple. Il y a ensuite deux façons de procéder pour rajouter le module mod_jserv. La première consiste à recompiler complètement Apache après lui avoir ajouté le source de mod_jserv. La seconde nécessite une version d'Apache 1.3.*, avec support des Dynamic Shared Objects (DSO) et permet d'ajouter le module mod_jserv de manière dynamique, c'est à dire sans avoir à recompiler Apache. Pour des raisons de temps, seule la deuxième procédure, plus "moderne",  est décrite ici.
Comme pour la plupart des packages fournis sous forme de code source, il est nécessaire dans un premier temps d'éxécuter le script de configuration avec configure. configure s'efforce de deviner le maximum de choses, et si l'ensemble des fichiers sont à leur place habituelle, tout se passeras parfaitement. Pour ma part, voici la ligne de commande que j'ai utilisé (avec succès sous SuSE) :

olly%>./configure -with-jsdk=/usr/lib/JSDK2.0/lib/jsdk.jar  -disable-debugging -with-apache-install=/usr

(La directive -with-apache-install=/usr est nécéssaire sous SuSE (mon cas) car configure croit que apxs est sous apache_dir/sbin/, alos qu'il  est en réalité sous /usr/sbin.)
Lors d'une seconde intallation sous Mandrake 7.0, la commande est devenue :

olly%>./configure --with-apxs=/usr/sbin/apxs --prefix=/usr/lib/jserv --with-jdk-home=/usr/lib/jdk1.2.2 --with-JSDK=/usr/lib/JSDK2.0/lib/jsdk.jar --disable-debugging --with-java-platform=2

olly%>make
olly%>make install
 

1.3 Configuration pour l'éxécution de servlets

L'environnement d'Apache JServ est divisé en zones, totalement indépendantes les unes des autres. Cela permet de séparer les servlets selon le possesseur, le mesures de sécurité désirées, ou encore les ressources allouées.  Toutefois, une unique zone suffit dans la plupart des utilisations.
Apache JServ possède un fichier de configuration nommé jserv.conf qui sert à définir son comportement au regard d'Apache. Le fichier de configuration d'Apache /etc/httpd/httpd.conf doit donc contenir une directive Include permettant d'inclure le fichier jserv.conf en son sein.

Exemple de ligne à inclure dans httpd.conf (après avoir copié le fichier jserv.conf à l'endroit indiqué):
Include /etc/httpd/jserv.conf

Le fichier jserv.conf contient à son tour une directive ApJServProperties /chemin/vers/jserv.properties pointant sur le fichier jserv.properties qui contient les propriétés des diférents servlets utilisés. jserv.properties permet entre autres choses de spécifier le nombre de zones souhaitées, le nom donné à chacune, ainsi que leur emplacement sur le disque.
Par exemple, si l'on souhaite deux zones nommées zone_a et zone_b, le fichier jserv.properties devra contenir les lignes suivantes :



# List of servlet zones Apache JServ manages
zone=zone_a, zone_b

Configuration : plusieurs zones. Chaque zone possède un fichier nom_zone.properties propre, dans lequel est entre autres indiqué le répertoire où trouver les servlets (repositories=/chemin/vers/classes).

Les zones disponibles doivent être indiquées dans le fichier jserv.properties. Les lignes zones=zone1, zone2, ... et le chemin des fichiers de propriété leur correspondant : zone1.properties=/chemin/vers/zone1.properties, zone2.properties=/chemin/vers/zone2.properties, etc..

Une fois JServ configuré, il est nécessaire de relancer Apache, avec une des commandes suivantes: rcapache restart, apachectl restart ou bien kill -NOHUP `cat var/httpd.pid`.
 

2 Architecture de base d'un servlet

Avant de rentre dans les détails, examinons le code d'un servlet avec fonctionnalités minimale.

2.1 Exemple : Hello World!

Ce premier exemple de servlet effectue une tâche toute simple : il crée une page HTML intitulée "mon premier servlet", laquelle affiche simplement "Salut tout le monde".



import javax.servlet.*; //importe le package servlet
import javax.servlet.http.*; //importe servlet.http
import java.io.*; //importe les classes d'entrée-sortie
public class ExempleServlet extends HttpServlet { // ExempleServlet hérite de HttpServlet
    /* surcharge la méthode doGet */
    public void doGet (HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        PrintWriter out;
        response.setContentType("text/html");          // then write the data of the response
        out = response.getWriter();
        out.println("<HTML>
                            <HEAD><TITLE> mon premier servlet </TITLE></HEAD>
                           <BODY><P>Salut tout le monde!</BODY></HTML>");
        out.close();
    }
}

Ce servlet hérite donc de la classe HttpServlet, et surcharge la méthode doGet, cette dernière étant appelée lorsqu'un client envoie une requète GET au serveur.

Pour éxécuter ce servlet, il suffit de placer le code compilé (ExempleServlet.class) dans l'un des répertoires correspondant aux zones configurées, par exemple ~/example/ puis d'ouvrir avec un browser l'URL http://localhost/example/ExempleServlet.
 

2.2 Contenu du package javax.servlet

Le coeur du package est la classe Servlet de laquelle tout servlet doit obligatoirement hériter. Un servlet n'utilise pas nécéssairement le protocole HTTP , c'est pourquoi il existe une interface HttpServlet héritant de la classe Servlet. Tous les servlets utilisés avec ApacheJserv devront bien sur hériter de l'interface HttpServlet et surcharger certaines de ses méthodes, par exemple les méthodes doGet ou doPost
Le package Servlet contient également deux classes qui permettent l'interaction avec les clients du serveur web, les classes ServletRequest et ServletResponse. La classe ServletRequest fournit des informations concernant la requète parvenue au serveur, notamment les noms et valeurs des paramêtres passés, l'adresse IP du client, ls cookies et donne également accès via un stream aux données encapsulées dans le corps de requètes HTTP, notamment lors de l'envoi de données au serveur via une méthode POST. La classe ServletResponse fournit des méthodes permettant de répondre aux clients, par exemple une méthode permettant de fixer le type MIME de la réponse, ainsi que des streams via lesquels il est possible d'envoyer des données au client. Les classes HttpServletRequest et HttpServletResponse sont des interfaces qui étendent un peu plus les classes ServletRequest et ServletResponse en permettant l'accès aux caractèristiques spécifiques des headers HTTP.
 
 
  • classe HttpServletRequest
Un objet de cette classe permet d'accéder aux éléments du header HTTP de la requète, tels que les cookies envoyés avec la requète, le type de méthode utilisée, aisni que les noms de paramètres et leur valeur passés avec la requète. La méthode getHeader permet de récupérer tout ou partie du header de la requète HTTP. Par exemple:
String useragent = request.getHeader("user-agent"); 
if (useragent.indexOf("Netscape")) {
   /** instructions éxécutées si le navigateur client est Netscape **/
}


La méthode getParameter retourne une chaîne de caractères contenant la valeur du paramètre passé en argument. Par exemple:


String bookId = request.getParameter("bookid");

Cette instruction stocke dans la variable bookId la valeur du paramètre nommé bookid (getParameter renvoie NULL si le paramètre n'existe pas).
Il est également possible d'obtenir une chaine de caractères unique contenant l'ensemble des paramètres et valeurs grâce à la méthode getQueryString, et de la parser soi-même par la suite.
Lors d'une requète POST, on utilisera pour lire les données contenues dans le corps de la requète la méthode getReader, qui renvoie un BufferedReader (cas de données texte)  ou  la méthode getInputStream qui renvoie un ServletInputStream.(données binaires).
 
  • classe HttpServletResponse
La classe HttpServletResponse fournit deux méthodes permettant de renvoyer des données à l'utilisateur : la méthode getWriter, qui renvoie un objet Writer permet de renvoyer des données de type texte, par exemple le contenu d'une page HTML.  La méthode getOutputStream retourne un ServletOutputStream grâce auquel il est possible de faire parvenir des données binaires au client. Dans les deux cas, il est important de fermer le stream après utilisation afin que le serveur sache que la réponse est complète.

    2.2 Cycle de vie d'un servlet

  • Initialisation
Lorsqu'une requète cliente porte sur un servlet non encore en mémoire, celui-ci est dans un premier temps chargé par le classLoader du moteur Jserv, puis sa méthode init() est appelée. C'est dans cette méthode que doivent donc être placée les commandes gourmandes en ressources ou celles prenant du temps (connection aux bases de données, par exemple). Il est important lorsque l'on surcharge la méthode init() de faire appel à la méthode init de la super classe, ce qui a pour effer de sauver la

Exemple de surcharge de la méthode init() :



public class MonServlet extends HttpServlet {
    public void init(ServletConfig config) throws ServletException {
        super.init(config);
        try {
            Class.forName("xxx");
        }
        catch(java.lang.ClassNotFoundException e) {
            ...
        }
    }
    public void doGet(...) {
    ...
    }
}

  • Fonctionnement
Après initialisation, le servlet est capable de recevoir une requète de la part d'un client. Lorsqu'une requète lui parvient, il appelle alors la méthode service(), qui reconnait le type de la requète HTTP (GET, POST, ...) et la fait parvenir à la méthode conçue pour traiter les requètes de ce même type (doGet(), doPost(), ...)
  • Destruction
Un servlet est normalement gardé en mémoire en prévision d'éxécutions futures, cependant pour des raisons diverses, notamment la configuration de Jserv et l'occupation des ressources, le moteur de servlet peut décider de détruire le servlet en appelant sa méthode destroy(). C'est donc ici que le concepteur de servlets doit inclure des instructions permettant par exemple de sauvegarder des données pour de futures sessions.
 

3 Exemple : traitement de formulaires

Les formulaires au sein d'une page HTML permettent l'interaction entre client et serveur web. Un formulaire contient généralement plusieurs éléments ou contrôles, comme par exemple des zones de saisie de texte, des boutons, des listes de choix, qu'il appartient à l'utilisateur de remplir, cliquer ou sélectionner selon ses désirs. Chacun des choix de l'utilisateur est stocké dans une paire NAME/VALUE.
Il existe deux méthodes pour faire parvenir les données de l'utilisateur au serveur. La première, dite méthode GET, transmet les données utilisateurs dans le header de la requète, tandis que la seconde, la méthode PUT, les transmet dans le corps de la requète, permettant de transférer des volumes de données beaucoup plus important.

3.1 Méthode GET


 
<form ACTION="/servlets/cherche" METHOD="GET">
<B>Chercher</B>
<input TYPE="text" NAME="query" VALUE="" SIZE=20>
<B>avec</B>
<select NAME="type">
<option VALUE="Google" SELECTED>Google
<option VALUE="Altavista">Altavista
<option VALUE="Metacrawler">Metacrawler
<option VALUE="Dictionnaire">Dictionnaire
</select> 
<input TYPE="submit" VALUE="Now!">
</form>
Chercher avec

Pour traiter une requète GET, il est nécessaire de surcharger la méthode doGet. A l'intérieur de cette méthode, la méthode getParameter permet de récupérer la valeur d'un paramètre passé au servlet avec la requète GET. Par exemple:

String bookId = request.getParameter("bookId"); //permet de récuperer la valeur du paramètre "bookid". La méthode renvoie null si le paramètre n'existe pas. Il est possible d'utiliser cela pour compacter les pages dynamique en un seul servlet:
 



String bookId = request.getParameter("bookId");
if (bookid == null) {

    //affiche le formulaire

} else {

    //traite le formulaire

}



 

3.2 Méthode PUT

La méthode PUT est généralement utilisée pour uploader des fichiers du disque de l'utilisateur vers le serveur. Elle peut par exemple être utilisée pour soumettre des images, ou encore des fichiers contenant des données à analyser par le serveur.

4 Maintien de sessions


HttpSession session = request.getSession(true);

Rien de plus pour l'instant.

5 Cookies


Bien que les classes et méthodes utilsées pour le maintien de session utilisent les cookies sans que l'on ai besoin d'y toucher directement, l'API Servlet comprends la classe javax.servlet.http qui permet de manipuler des objets Cookies
 

    5.1 Envoyer un cookie

Pour créer un cookie:


Cookie c = new Cookie("login", str_login);
c.setVersion(1);
c.setDomain(".mon_domaine.com");
res.addCookie(authCookie);

    5.2 Récupérer un cookie


L'instruction suivante permet de récupèrer l'ensemble des cookies:

Cookie[] cookies = req.getCookies(); 

La classe Cookie possède alors les méthodes suivantes:
public String getName()  pour récupèrer le nom du cookie

public String getDomain() pour récupèrer le domaine

public String getValue() pour récupérer la valeur stockée dans le cookie


6 Problèmes de threading

Un serveur web pouvant servir plusieurs clients de manière concurrente, lorsqu'un servlet est conçu de manière à accèder à une ressource partagée, par exemple une base de données, il est parfois nécéssaire de prévenir l'accès simultané par plusieurs clients à cette même ressource. Afin d'obliger un servlet à ne traiter qu'une seule requète à tout moment, il existe deux possibilités : la première consiste à concevoir le servlet de façon à ce qu'il implémente l'interface SingleThreadModel.

Un exemple d'un tel servlet est le suivant :



public class ReceiptServlet extends HttpServlet implements SingleThreadModel {
    public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException
    {
        ...
    }

    ...
}


Le serveur s'assure alors que la méthode service n'est pas appelée plus d'une seule fois simultanément.
Un moteur de base de données comporte bien souvent des systèmes de verrouillage d'accès et n'est donc pas un bon exemple. Prenons plutot l'exemple d'un fichier texte contenant un nombre plusieurs clients pourraient vouloir modifier simultanément

La deuxième possibilité est de synchroniser l'accès à la ressource.

7 Java DataBase Connectivity

Il serait difficile de parler de l'API Servlet sans également mentionner l'API JDBC. En effet, ce dernier permet à tout servlet d'accèder de manière directe à pratiquement n'importe quelle base de donnée externe, pourvu que celle ci possède un driver JDBC. Dans cet article, nous utilisons la base de données PostgreSQL, dont le driver JDBC est disponible à cette adresse. Il faut avant de commencer s'assurer que le chemin du driver JDBC est présent dans le $CLASSPATH. (au besoin faire un olly>export CLASSPATH=$CLASSPATH:/usr/lib/pgsql/jdbc6.5-1.2.jarou bien insérer la ligne wrapper.classpath=/usr/lib/pgsql/jdbc6.5-1.2.jardans le fichier jserv.properties)

Pour faire fonctionner l'example fourni, il est nécéssaire d'avoir une base de données (ici nommée test), et d'y insérer une table avec quelques données. Pour cela, il suffit de créer un fichier texte tout simple nommé par exemple jdbc.sql contenant les quelques commandes SQL suivantes :



create table stories (story_title varchar(100), story_url varchar(100), story_date date);
insert into stories values ('NASA Proposes Launch Solar Sail Vehicle For 2010', 'http://slashdot.org/article.pl?sid=00/05/15/058238', '2000-05-15');
insert into stories values ('Linuxcare Responds To Tim O\'Reilly's Article', 'http://slashdot.org/article.pl?sid=00/05/15/0254252', '2000-05-15');
insert into stories values ('New Internet VCR Service', 'http://slashdot.org/article.pl?sid=00/05/14/2048217', '2000-05-15');


 

Ensuite la commande  olly>psql test< jdbc.sql permet d'éxécuter ces commandes (et donc de créer la table et d'y insérer les trois enregistrements).

    7.1 Connection à une base de donnée

Dans le monde JDBC, une base de données est représentée par une URL, par exemple jdbc:postgresql://host:port/base. En ce qui concerne le driver JDBC pour PostgreSQL, host est par défaut égal à localhost et port à 5432



import java.sql.*;
public class jdbctest {
   public static void main(String args[])
   {
        String url = "jdbc:postgresql:test";
        Connection con;
        Statement stmt;

        try
        {
           Class.forName("postgresql.Driver");
        }
        catch(java.lang.ClassNotFoundException e)
        {
           System.err.print("ClassNotFoundException: "); System.err.println(e.getMessage());
        }

        try
        {
           con = DriverManager.getConnection(url, "olly", "");
           stmt = con.createStatement(); 

            ResultSet rs = stmt.executeQuery("select * from stories");
           while (rs.next())
           {
               String s = rs.getString("story_title");
               System.out.println(s);
           }
           stmt.close();
           con.close();

        }
       catch (SQLException ex)
       {
           System.err.println("SQLException: " + ex.getMessage());
       }
   }
}


Stockage d'objet Java dans une base PostgreSQL

Postgresql est une base de données d'un genre un peu particulier : elle possède par rapport à une base relationnelle traditionnelle des extensions objets, qui lui permettent par exemple de stocker une table dans un champs d'une autre table.

Il est donc tout à fait possible en Java de stocker un objet dans un stream, si la classe de l'objet implémente l'interface java.io.Serializable. Cette caractèristique rend alors possible le stockage d' objets Java dans une base Postgresql, au moyen des LargeObject. Cependant, Postgresql est un moteur de base de données d'un genre un peu particulier : il possède par rapport à une base relationnelle traditionnelle des extensions objets, qui lui permettent par exemple de stocker une table dans un champs d'une autre table. La classe postgresql.util.Serialize du driver JDBC se sert de cette caractèristique pour fournir un moyen de stocker un objet Java en tant que table.
 

8 Un servlet évolué: Cocoon

Cocoon permet de transformer des données XML grâce a des feuilles de style XSL de façon à obtenir non seulement du HTML pour les navigateurs classiques, mais également du WML pour les browser WAP contenus dans certains téléphones mobiles, ou encore du PDF . Il permet donc d'ouvrir les sites web inter ou intranet à un nombre considérable de clients, sans que soient nécessaires les refontes de chaque document pour le rendre compatible avec les systèmes de navigation spécifiques à chaque client. 
 

    Installation de Cocoon

La première chose a faire consiste à télécharger Cocoon, à partir du site http://xml.apache.org, puis à le compiler (comme à l'habitude, ./configure, make, make install)
Il est ensuite nécessaire de rendre les classes Cocoon visibles par le moteur de servlets : il faut pour cela ajouter des wrapper.classpath vers tous les .jar requis par Cocoon dans le fichier jserv.properties
cocoon.jar :
xerces.jar : parseur XML
xalan.jar : moteur de transformation XSLT
fop.jar : formating
par exemple:
wrapper.classpath=/usr/local/java/lib/cocoon.jar

Il faut ensuite choisir la zone servlet dans laquelle Cocoon doit résider, zone dans cette exemple. Il faut donc passer le fichier cocoon.properties en parametre au fichier zone.properties, en y ajoutant la ligne suivante:
servlet.org.apache.cocoon.Cocoon.initArgs=properties=[path-to-cocoon]/conf/cocoon.properties

Il faut également dire à Apache d'associer tous fichier xml avec Cocoon. Pour cela, il faut ajouter:



Action cocoon /servlet/org.apache.cocoon.Cocoon
AddHandler cocoon xml


dans le fichier jserv.conf. (/servlet/ est le point de montage de la zone servlet a laquelle appartient Cocoon)
Nous sommes alors prêts pour créer notre premier document XML, ainsi que sa feuille de style.
Plusieurs cas de figures : le fichier XML existe, il faut simplement lui adjoindre une feuille XSL. Deuxième cas, l'information est stockée dans une base de données, par exemple postgreSQL, et il va être nécessaire d'extraire dans un premier temps cette information, pour la mettre au format XML, puis lui appliquer une transformation XSL.

Cas 1: Le fichier XML existe deja
Le fichier XML est le suivant, et nous voulons afficher ses infos dans un document HTML, sous forme de table.



<?xml version="1.0" encoding="UTF-8"?>
<stories>
    <story>
        <story_title>NASA Proposes Launch Solar Sail Vehicle For 2010</story_title>
        <story_url> http://slashdot.org/article.pl?sid=00/05/15/058238</story_url>
        <story_date>2000-05-15</story_date>
    </story>

    <story>
        <story_title>Linuxcare Responds To Tim O&apos;Reilly&apos;s Article</story_title>
        <story_url>http://slashdot.org/article.pl?sid=00/05/15/0254252</story_url>
        <story_date>2000-05-15</story_date>
    </story>

    <story>
        <story_title>New Internet VCR Service</story_title>
        <story_url>http://slashdot.org/article.pl?sid=00/05/14/2048217</story_url>
        <story_date>2000-05-15</story_date>
    </story>
</stories>


La feuille de style que l'on doit appliquer pour obtenir le résultat souhaité est très simple:



<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:template match="/">
<html>
<body>
<xsl:apply-templates select="stories"/>
</body>
</html>
</xsl:template>

<xsl:template match="stories">
<table>
<xsl:apply-templates select="story"/>
</table>
</xsl:template>

<xsl:template match="story">
 <tr><td><a href="{story_url}"><xsl:value-of select="story_title"/></a></td><td><xsl:value-of select="story_date"/></td></tr>
</xsl:template>

</xsl:stylesheet>


Cette feuille de style est stockée dans le fichier stories.xsl. Pour signifier à Cocoon qu'il doit appliquer cette feuille au document XML ci-dessus, il faut rajouter une ligne à ce dernier, dans son entête,  juste après le tag de version.



<?xml version="1.0"?>
<?xml-stylesheet href="stories.xsl" type="text/xsl"?>
<?cocoon-process type="xslt"?>

<stories>
.
.



En pointant votre browser sur l'url de stories.xml, on obtient le code HTML suivant:
 



<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN"
                      "http://www.w3.org/TR/REC-html40/strict.dtd">
<html><body><table><tr><td><a
      href="http://slashdot.org/article.pl?sid=00/05/15/058238">NASA Proposes Launch Solar Sail Vehicle For 2010</a></td><td>2000-05-15</td></tr><tr><td><a
      href="http://slashdot.org/article.pl?sid=00/05/15/0254252">Linuxcare Responds To Tim O'Reilly's Article</a></td><td>2000-05-15</td></tr><tr><td><a href="http://slashdot.org/article.pl?sid=00/05/14/2048217">New Internet VCR Service</a></td><td>2000-05-15</td></tr></table></body></html>

<!-- This page was served in 748 milliseconds by Cocoon 1.7 -->



 
 

Cas 2 : l'information est stockée dans une base de données
 

Il faut passer par ce que l'on appelle un SQLProcessor. XSQL, fourni par Oracle, est un exemple de produit transformant un résultat d'une requète SQL en XML. Pour pouvoir utiliser SQLProcessor, il faut s'assurer qu'une ligne du type processor.type.sql = org.apache.cocoon.processor.sql.SQLProcessor est présente dans le fichier cocoon.properties.

Cet exemple éxécute une requète SQL sur une base PostGreSQL grâce à JDBC (il faut donc lui fournir les coordonnées du driver, ainsi que des infos utilisateurs, tq login et password) puis récupère les résultats et les formatte en XML. Il s'agit simplement de remplacer le bloc <query> ... </query> par le résultat, puis de lui appliquer la feuille de style normale.



<?xml version="1.0"?>
<?xml-stylesheet href="stories.xsl" type="text/xsl"?>
<?cocoon-process type="sql"?>
<?cocoon-process type="xslt"?>

<page>

 <connectiondefs>
  <connection name="test_connection">
   <driver>postgresql.Driver</driver>
   <dburl>jdbc:postgresql:test</dburl>
   <username>olly</username>
   <password></password>
  </connection>
 </connectiondefs>

 <query connection="test_connection" doc-element="stories" row-element="story">
  select story_title, story_url, story_date from stories
 </query>

</page>


Les attributs doc-element et row-element permettent de spécifier respectivement le nom que va prendre l'ensemble des résultats (ResultSet), et les lignes (rows). S'ils ne sont pas spécifié, ces noms seront ROWSET et ROW.
 

9 Upload de fichiers

Pour "uploader" un fichier grace à un servlet Java, il faut utiliser le package com.oreilly.servlet disponible à cette adresse. Imaginons que l'on ai le formulaire suivant:
<form  enctype="multipart/form-data" action="action" method="post"><br>
<textarea name="indata" cols="70" rows="10"></textarea><br>
<input type="file" name="infile"><br>
<input type="submit" name="submit" value="Continue"><br>
</form><br>

Ce formulaire contient deux champs, un champ de type texte (textarea), et un champ de type "file". Supposons maintenant que l'on veuille sauver les données du formulaire (fichier ou texte) dans le fichier /tmp/dataXX-YY. La méthode doPost() permettant de réaliser cela est la suivante :
 import java.io.*;
 import javax.servlet.*;
 import javax.servlet.http.*;
 import java.util.Date;
 import com.oreilly.servlet.multipart.*;
 .
 .
 public void doPost (HttpServletRequest request, HttpServletResponse response)  throws ServletException, IOException {
        /** récupère la date courante **/
        Date d = new Date();
 /** forge une chaine de caractère contenant la date **/
        String timestamp = new String(d.getMinutes() + "-" + d.getSeconds());
 /** crée un nouveau multipart parser, la taille des objets parsés étant de 10 MB au maximum **/
        MultipartParser mp = new MultipartParser(request, 10*1024*1024); // 10MB
        Part part;
 /** itére tous les parties **/
        while ((part = mp.readNextPart()) != null) {
     /** s'il s'agit du fichier **/
            if (part.getName().equals("infile")) {
         /** recupere les données sous la forme d'un FilePart **/
                FilePart filePart = (FilePart) part;
                String fileName = filePart.getFileName();
  /** recopie dans un nouveau fichier **/
                if (fileName != null) {
                    long size = filePart.writeTo(new File("/tmp/data" + timestamp));
                    break;
                }
     /** s'il s'agit de la zone de texte **/
            } else if (part.getName().equals("indata")) {
         /** recupere les données sous la forme d'un objet ParamPart **/
                ParamPart paramPart = (ParamPart) part;
  /** récupere la valeur du champ "indata" **/
                String indata = paramPart.getStringValue();
  /** pour écrire dans un fichier **/
                PrintWriter fos = new PrintWriter(new FileWriter("/tmp/data" + timestamp));
  fos.print(indata);
                fos.close();
            }
        }
}

 

 


un petit tutorial en java

Using the Xalan XSLT engine within a java servlet

Introduction

Separation of style from content allows for the same data to be presented in different ways and is the clear answer to the multiplication of connected devices (Palm, Pocket PC, Interactive TV) that can access networked ressources using their own language (WML, WebClipping, HTML, XHTML, cHTML, etc..).
In this article, we show how to produce HTML and WML content from an XML data source, and the appropriate XSLT stylesheets. The XSLT transformation is done using the Xalan transformation engine, an open-source java project hosted by the Apache foundation. The Xalan engine is called from a java servlet, running in the Tomcat servlet engine.
 

Requirements

In this article, I will assume that you have installed the Tomcat servlet engine, and the Xalan XSLT engine. Both are available from java.apache.org and xml.apache.org. I also assume that xalan.jar, xerces.jar (the XML parser bundled with Xalan) and the servlet classes are present in your classpath. If not, try something like:

XALAN_HOME=/path/to/xalan.jar
XERCES_HOME=/path/to/xerces.jar
export CLASSPATH=$CLASSPATH:$XALAN_HOME:$XERCES_HOME
 
 

Creating a new web application within Tomcat

Although you could install your java classes in an existing web application (the one called "examples", for instance), it is probably better to create a new web application.  This is nicely explained in "Deploying web applications to Tomcat" by James Goodwill.
Assuming $TOMCAT_HOME is the path to the Tomcat directory, first change directory to webapps (the root of all web applications) and create the following directories:

/xslt
/xslt/WEB-INF
/xslt/WEB-INF/classes

To do so, type the following commands:
> cd $TOMCAT_HOME/webapps
> mkdir xslt
> cd xslt
> mkdir WEB-INF
> cd WEB-INF
> mkdir classes
> cd classes

The /xslt/WEB-INF/classes directory is the place where you will store all the servlets classes described below.

Once the directories are created, you should install a servlet context, by editing the file $TOMCAT_HOME/conf/server.xml, and adding the following lines:

<Context path="/xslt" docBase="webapps/xslt" debug="0" reloadable="true" >
</Context>

path="/xslt" tells Tomcat that all requests starting with /onjava belong to the onjava web application.
docBase="webapps/xslt" tells the servlet container that the web application is located on webapps/xslt"
 

Once you have done these operations, you need to restart Tomcat.
 

Xalan-J : a Java XSLT engine

We use Xalan as our XSLT engine. While we embed Xalan within our servlet, Xalan-J can also be used in a command line way to perform XSLT transformation and produce static output files. For example, imagine you want to produce a static HTML file called slashdot.html from a XML file called slashdot.xml.
You just need to type the following line:
> java org.apache.xalan.xslt.Process -in slashdot.xml -xsl slashdot.xsl -out slashdot.html

If you want the output to be displayed on the screen, simply omit the -out flag and argument.

The XSLT processor class

Xalan-J implements the TrAX (Transformation API for XML) interface. From the Xalan documentation: "A TRaX TransformerFactory is an object that processes transformation instructions, and produces Templates (in the technical terminology). A Templates object provides a Transformer, which transforms one or more Sources into one or more Results. To use the TRaX interface, you create a TransformerFactory, which may directly provide a Transformers, or which can provide Templates from a variety of Sources. The Templates object is a processed or compiled representation of the transformation instructions, and provides a Transformer. The Transformer processes a Source according to the instructions found in the Templates, and produces a Result".
In the code below, the XSLT processor class contains a method that takes as input a XML source, a XSL source, a servlet request (it is not used here) and a servlet response, and it returns the output of the transformation to the servlet output stream.


import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

import org.xml.sax.SAXException;

import javax.xml.transform.*;
import javax.xml.transform.stream.*;

public class XalanXslProcessorBean {

    TransformerFactory tFactory;

    //the constructor simply gets a new TransformerFactory instance
    public XalanXslProcessorBean() {
        tFactory = TransformerFactory.newInstance();
    }

    //this method takes as input a XML source, a XSL source, and returns the output of the transformation to the servlet output stream
    public void process(StreamSource xmlSource,
                                  StreamSource xslSource,
                                  HttpServletRequest request,
                                  HttpServletResponse response)
             throws ServletException, IOException, SAXException {
        try {
            Templates templates = tFactory.newTemplates(xslSource);
            Transformer transformer = templates.newTransformer();
             transformer.transform(xmlSource, new StreamResult(response.getOutputStream()));
        }
        catch (Exception e) {
           //should log some message here
        }
    }
}



 
 

The XML data

The XML file we will use was grabbed from the slashdot.org site, and contains the slashdot news in XML form. It needs to be saved to your disk (and called slashdot.xml for example).


<?xml version="1.0"?><backslash xmlns:backslash="http://slashdot.org/backslash.dtd">

 <story>
  <title>NASA Proposes Launch Solar Sail Vehicle For 2010</title>
  <url>http://slashdot.org/article.pl?sid=00/05/15/058238</url>
  <time>2000-05-15 07:54:15</time>
  <author>timothy</author>
  <department>ralph-nader-will-have-to-hire-a-chase-car</department>
  <topic>space</topic>
  <comments>99</comments>
  <section>articles</section>
  <image>topicspace.gif</image>
 </story>

 <story>
  <title>Linuxcare Responds To Tim O'Reilly's Article</title>
  <url>http://slashdot.org/article.pl?sid=00/05/15/0254252</url>
  <time>2000-05-15 02:57:07</time>
  <author>timothy</author>
  <department>consider-source-horses-mouth-grain-of-salt</department>
  <topic>linuxbiz</topic>
  <comments>142</comments>
  <section>articles</section>
  <image>topiclinuxbiz.gif</image>
 </story>

 <story>
  <title>New Internet VCR Service</title>
  <url>http://slashdot.org/article.pl?sid=00/05/14/2048217</url>
  <time>2000-05-14 20:51:57</time>
  <author>timothy</author>
  <department>this-is-cool-but-can-they-do-that?</department>
  <topic>news</topic>
  <comments>189</comments>
  <section>articles</section>
  <image>topicnews.gif</image>
 </story>

 <story>
  <title>Google Releases WAP Search Tool</title>
  <url>http://slashdot.org/article.pl?sid=00/05/14/1240252</url>
  <time>2000-05-14 17:49:11</time>
  <author>emmett</author>
  <department>wireless</department>
  <topic>internet</topic>
  <comments>141</comments>
  <section>articles</section>
  <image>topicinternet.jpg</image>
 </story>

 <story>
  <title>No More Unreal Ports For Linux?</title>
  <url>http://slashdot.org/article.pl?sid=00/05/14/1439224</url>
  <time>2000-05-14 16:32:11</time>
  <author>timothy</author>
  <department>one-web-one-program-happy-mothers-day</department>
  <topic>games</topic>
  <comments>250</comments>
  <section>articles</section>
  <image>topicgames.jpg</image>
 </story>

 <story>
  <title>Pioneer Introduces 1st DVD Recorder (In Japan)</title>
  <url>http://slashdot.org/article.pl?sid=00/05/14/152210</url>
  <time>2000-05-14 15:50:48</time>
  <author>CmdrTaco</author>
  <department>steam-rising-from-the-riaas-forehead</department>
  <topic>tv</topic>
  <comments>98</comments>
  <section>articles</section>
  <image>topictv.jpg</image>
 </story>

 <story>
  <title>QuakeForge And QuakeWorld Forever Merge</title>
  <url>http://slashdot.org/article.pl?sid=00/05/14/1447248</url>
  <time>2000-05-14 15:07:27</time>
  <author>CmdrTaco</author>
  <department>and-then-there-was-one</department>
  <topic>quake</topic>
  <comments>57</comments>
  <section>articles</section>
  <image>topicquake.gif</image>
 </story>

 <story>
  <title>What Happens When Open Source And Work Collide?</title>
  <url>http://slashdot.org/article.pl?sid=00/05/09/016208</url>
  <time>2000-05-14 14:04:07</time>
  <author>Cliff</author>
  <department>sticky-situations</department>
  <topic>programming</topic>
  <comments>170</comments>
  <section>askslashdot</section>
  <image>topicprogramming.gif</image>
 </story>

 <story>
  <title>Black Holes Don't Exist???</title>
  <url>http://slashdot.org/article.pl?sid=00/05/14/1339252</url>
  <time>2000-05-14 13:39:24</time>
  <author>Roblimo</author>
  <department>pop-science-can-be-fun</department>
  <topic>science</topic>
  <comments>162</comments>
  <section>articles</section>
  <image>topicscience.gif</image>
 </story>

 <story>
  <title>Los Alamos Lab: We're OK, You're OK</title>
  <url>http://slashdot.org/article.pl?sid=00/05/14/0143228</url>
  <time>2000-05-14 04:44:44</time>
  <author>timothy</author>
  <department>sir-please-step-*away*-from-the-plutonium-bin</department>
  <topic>news</topic>
  <comments>278</comments>
  <section>articles</section>
  <image>topicnews.gif</image>
 </story>

</backslash>



 

The XSLT stylesheet

An XSL stylesheet basically consists of a set of templates. Each template "matches" some set of elements in the original XML data and then describes the contribution that the matched element makes to the final output.
An XSLT template is defined by a xsl:template tag, whose "match" parameter determines where this template applies. For example <xsl:template match="/"> ... </xsl:template> applies to the root element of the XML document, while <xsl:template match="backslash/story"> matches every story element that has backslash as father. Templates are generally applied recursively, i.e. a template calls another templates using the xsl:apply-templates tag.
<xsl:value-of> inserts the value of an expression to the final output. Note that {element} can also be used to insert the value of element.

Here is the HTML stylesheet (named slashdot.xsl) we will use:



<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

<xsl:template match="/">
<html>
<body>
<xsl:apply-templates select="backslash/story"/>
</body>
</html>
</xsl:template>

<xsl:template match="backslash/story">
  <li><a href="{url}"><xsl:value-of select="title"/></a></li>
</xsl:template>

</xsl:stylesheet>


Outputting HTML with a servlet

This java code implements a basic servlet, which uses the XalanXslProcessorBean class defined above. It sets the Content-Type portion of the HTTP header to text/html, creates two StreamSources objects from both the xml and the xsl files, and perform the transformation


import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

import javax.xml.transform.stream.*;

public class XslProcessorServlet extends HttpServlet {

    XalanXslProcessorBean processor;

    public void init(ServletConfig config) {
        processor = new XalanXslProcessorBean();
    }

    public void doGet (HttpServletRequest request,
                                HttpServletResponse response)
             throws ServletException, IOException {

        //sets the Content-Type portion of the HTTP header to text/html
        response.setContentType("text/html");
        try {
            processor.process(new StreamSource("slashdot.xml"), new StreamSource("slashdot.xsl"), request, response);
        }
        catch (Exception e) {

        }
    }
}


Since slashdot.xml is often updated,  you may prefer to fetch it directly from the slashdot.org site:  you then need to change the processor.process(...) line to: processor.process(new StreamSource(new InputStreamReader((new URL("http://slashdot.org/slashdot.xml")).openStream())), new StreamSource("slashdot.xsl"), request, response);
Then restart your servlet container if needed, and reload the page.
 

Outputting HTML and WML with a servlet


Suppose that you want to make your content available to both HTML and WML navigators. Basically, you just need a XSLT stylesheet that can transform XML to HTML, and another one that can transform XML to WML (Wireless Meta Language). You then need to implement a mechanism that can use the appropriate stylesheet, depending on the navigator information contained in the HTTP request header.

Here is the WML stylesheet. Note the xsl:output tag, which is the only way to produce the <!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml"> string in the WML output.



<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml"
                  doctype-public="-//WAPFORUM//DTD WML 1.1//EN"
                  media-type="text/vnd.wap.wml"
                  doctype-system="http://www.wapforum.org/DTD/wml_1.1.xml"
                  encoding="ISO-8859-1"/>

<xsl:template match="/">
<wml>

    <template>
        <do type="prev" name="Previous" label="Back">
            <prev/>
        </do>
    </template>

    <card id="card1" title="Slashdot news">
        <p>
            <xsl:apply-templates select="backslash/story"/>
        </p>
    </card>

</wml>
</xsl:template>
 

<xsl:template match="backslash/story">
  <a href="{url}"><xsl:value-of select="title"/></a><br/>
</xsl:template>

</xsl:stylesheet>


Note that the following servlet code now contains some code to fetch the user agent from the HTTP header, and uses the WML stylesheet when the user agent string contains the word (Nokia). Obviously, this only works with a Nokia phone or with some Nokia emulator.



import java.io.*;
import java.net.*;
import javax.servlet.*;
import javax.servlet.http.*;

import javax.xml.transform.stream.*;

public class XslProcessorServlet extends HttpServlet {

    XalanXslProcessorBean processor;

    public void init(ServletConfig config) {
        processor = new XalanXslProcessorBean();
    }

    public void doGet (HttpServletRequest request,
                                HttpServletResponse response)
        throws ServletException, IOException {

        //fetch the user agent part of the HTTP header
        String useragent = request.getHeader("user-agent");

        //if the user agent contains the string "Nokia", then use the WML stylesheet, otherwise use the HTML one
        StreamSource xslsource;
        if (useragent.indexOf("Nokia") >= 0) {
            //send the correct Content-Type
            response.setContentType("text/vnd.wap.wml");
            xslsource = new StreamSource("slashdot_wml.xsl");
        } else {
            response.setContentType("text/html");
            xslsource = new StreamSource("slashdot_html.xsl");
        }

        try {
            processor.process(new StreamSource("slashdot.xml"), xslsource, request, response);
        }
        catch (Exception e) {

        }
    }
}




blogspirit
xanga
g-blog
blog-city
blogsome
blogg
msn
oldiblog
blogeasy
joueb
alfablog
avatale
blogstudio
blog.ca
blog.com
bloghi.com
ebloggy.com
blogigo
blogsharing
blogsource
blogspot
bloxster
cool-blog
ALV Ringtone NBA Petites annonces - sonneries - annonces immobilieres - sonneries Alicia keys
Echange de liens - page 1 - page 2 - page 3 - page 4 - page 5 - page 6 - page 7 - page 8 - page 9 - page 10 - le top ten | les nouveaux sites - . Le forum - .


les categories de mon annuaire

fossil
fossil
fossil
fossil
fossile
fossile
fossiles
fossiles
fossili
fossilien
fossilien
foster
foster
fotógrafo
fotógrafos
foto's van
foto's
foto 3
foto di
foto e
foto foto's
foto3
fotoagentur
fotoagentur
fotoalbum
fotoalbum
fotoalbum
fotoarchiv
fotoarchiv
fotoatelier
fotoatelier
fotocamere
fotoclub
fotoclub
fotoclub
fotocopiadoras
fotocopiatrici
fotodesign
fotodesign
fotodesigner
fotodesigner
fotoentwicklung
fotoentwicklung
fotogalerie
fotogalerie
fotográfico
fotográficos
fotograaf
fotografía de
fotografía
fotografías de
fotografías
fotograf
fotograf
fotografen
fotografen
fotografen
fotografi
fotografia di
fotografia
fotografia
fotografias
fotografica
fotografiche
fotografici
fotografico
fotografie und
fotografie und
fotografie
fotografie
fotografie
fotografie
fotografien
fotografien
fotografieren
fotografieren
fotografin
fotografin
fotografo
fotografo
fotografos
fotogrammetria
fotograph
fotograph
fotographie
fotographie
fotogroep
fotokalender
fotokalender
fotokunst
fotokunst
fotokurs
fotokurs
fotokurse
fotokurse
fotolabor
fotolabor
fotolog
fotomodel
fotomodel
fotomodel
fotomodell
fotomodell
fotomodelle
fotomodelle
fotopapier
fotopapier
fotoreise
fotoreise
fotoreisen
fotoreisen
fotoreportage
fotoreportage
fotoreportages
fotorural
fotos aus
fotos aus
fotos de
fotos und
fotos und
fotos von
fotos von
fotos
fotos
fotos
fotos
fotos
fotos
fotoservice
fotoservice
fotoshooting
fotoshooting
fotostudio
fotostudio
fotostudio
fototaschen
fototaschen
fotovoltaici
fotovoltaico
fotovoltaik
fotovoltaik
foucault
foucault
foucault
foudre
foudre
fouesnant
fouesnant
fougères
fougères
fouille
fouille
fouilles
fouilles
foulard
foulard
found
found
found
found
found
found
found
foundation for sustainable
foundation for sustainable
foundation for
foundation for
foundation
foundation
foundation
foundation
foundation
foundation
fountain
fountain
fountain
fountain
fouras
fouras
fourche
fourche
fourgon
fourgon
fourmi
fourmi
fourmis
fourmis
fournaise
fournaise
fourneau
fourneau
fourneaux
fourneaux
fournier
fournier
fournisseur
fournisseur
fournisseurs
fournisseurs
fourniture
fourniture
fournitures de bureau
fournitures de bureau
fournitures de
fournitures de
fournitures
fournitures
fourrure
fourrure
fours
fours
foxpro
foxpro
foxterrier
foxterrier
foyer
foyer
foyer
foyer
foyers
foyers
fränkisch
fränkisch
fränkische schweiz
fränkische schweiz
fränkische
fränkische
fränkischen schweiz
fränkischen schweiz
fränkischen seenland
fränkischen seenland
fränkischen
fränkischen
fränkisches
fränkisches
fräse
fräse
fräsen
fräsen
fräser
fräser
fräsmaschine
fräsmaschine
fräsmaschinen
fräsmaschinen
frästeile
frästeile
frères
frères
frédéric beigbeder
frédéric beigbeder
frédéric
frédéric
frédéric
frédéric
fréhel
fréhel
fréjus
fréjus
fréquence
fréquence
fréquences
fréquences
fröhlich
fröhlich
frösche
frösche
früchte
früchte
früchtetee
früchtetee
frühchen
frühchen
frühe
frühe
frühen
frühen
früherkennung
früherkennung
frühförderung
frühförderung
frühgeborene
frühgeborene
frühling
frühling
frühschoppen
frühschoppen
frühstück
frühstück
frühstück
frühstücksbuffet
frühstücksbuffet
frühstückspension
frühstückspension
fracht
fracht
frachter
frachter
frachtschiff
frachtschiff
frachtschiffreise
frachtschiffreise
frachtschiffreisen
frachtschiffreisen
fractal
fractal
fractal
fractal
fractal
fractales
fractales
fractales
fractie
fractura
fraese
fraese
fraesen
fraesen
frage
frage
fragebogen
fragebogen
fragen und
fragen und
fragen zu
fragen zu
fragen
fragen
fragole
fragua
fraile
frailes
frailty
frailty
frais de
frais de
frais
frais
fraisage
fraisage
fraise
fraise
fraktion im
fraktion im
fraktion
fraktion
frame
frame
frame
frame
frame
frame
frame
framemaker
framemaker
frames
frames
frames
frames
frames
frameset
frameset
framework
framework
framework
framework
frammenti
franã
franã
français
français
français de
français de
français des
français des
français du
français du
français langue
français langue
français
français
français
français
français
français
française
française
française de
française de
française des
française des
française
française
françaises
françaises
françois bon
françois bon
françois truffaut
françois
françois
françois
françois
françois
françoise
françoise
francés
francés
francés
franc
franc
franc
franca
francais
francais
francais
francais
francaise
francaise
francavilla
france à
france à
france
france
france 2
france 2
france 3
france 3
france 5
france 5
france au
france au
france de
france de
france en
france en
france et en
france et en
france et
france et
france in
france in
france télécom
france télécom
france telecom
france telecom
france
france
france
france
france
france
france
frances
frances
frances
frances
francesa
francesca
francescana
francesco giuseppe
francesco guccini
francesco
francese
francese
francesi
franche comté
franche comté
franche comte
franche comte
franche
franche
franche
franche
franchi
franchisé
franchisé
franchise
franchise
franchise
franchise
franchise
franchises
franchises
franchiseur
franchiseur
franchiseurs
franchiseurs
franchising
franchising
franchising
francia
francia
francia
francia
francia
francia
franciacorta
francine
francine
francis kaplan
francis kaplan
francis kaplan
francis kaplan
francis
francis
francis
francis
francis
francis
franciscano
francisco de asís
francisco de borja
francisco de
francisco javier
francisco
francisco
francisco
francisco
francisco
francisco
franciscus
franck
franck
francke
francke
franco
franco
franco
franco
franco
franco
francobolli
francois truffaut
francois truffaut
francois
francois
francois
francois
franconia
franconia
franconville
franconville
francophone de
francophone de
francophone
francophone
francophones
francophones
francophonie
francophonie
francorchamps
francs
francs
franeker
frank miller
frank zappa
frank zappa
frank
frank
frank
frank
frank
frank
frank
franka potente
franka potente
franka
franka
franke
franke
franke
franken bayern
franken bayern
franken
franken
frankenberg
frankenberg
frankenhausen
frankenhausen
frankenstein
frankenstein
frankenthal
frankenthal
frankenthaler
frankenthaler
frankenwald
frankenwald
frankenwein
frankenwein
frankfurt
frankfurt
frankfurt am main
frankfurt am main
frankfurt am
frankfurt am
frankfurt
frankfurt
frankfurt
frankfurter rundschau
frankfurter rundschau
frankfurter
frankfurter
frankiermaschine
frankiermaschine
frankiermaschinen
frankiermaschinen
franklin
franklin
frankreich
frankreich
frankreich
frankreich
frankrijk
frankrijk
frankrijk
frankrijk
frankrijk
franquicia
franquicias
franquin
franquin
frans
frans
frans
franse
frantoi
frantoio
frantz
frantz
französisch
französisch
französisch
französisch
französische
französische
französischen
französischen
franz josef
franz josef
franz kafka
franz kafka
franz liszt
franz liszt
franz marc
franz marc
franz von
franz von
franz xaver
franz xaver
franz
franz
franz
franz
franz
franzen
franzen
franzis
franzis
franziska
franziska
franziskanerinnen
franziskanerinnen
franziskus
franziskus
frappe
frappe
frascati
frase
frases de
frases
frasi
frasne
frasne
fratelli
fratello
fraternidad
fraternité
fraternité
frati
fratres
fratta
frattamaggiore
frau der woche
frau der woche
frau der
frau der
frau und
frau und
fraude
fraude
fraude
fraude
fraudes
frauen
frauen
frauen aus
frauen aus
frauen in
frauen in
frauen und
frauen und
frauen wollen
frauen wollen
frauen
frauen
frauenarzt
frauenarzt
frauenbeauftragte
frauenbeauftragte
frauenchor
frauenchor
frauenfeld
frauenfeld
frauenfu
frauenfu
frauenfussball
frauenfussball
frauengesundheit
frauengesundheit
frauenhaus
frauenhaus
frauenheilkunde
frauenheilkunde
frauenkirche
frauenkirche
frauenklinik
frauenklinik
frauenlauf
frauenlauf
frauenrechte
frauenrechte
frauenselbstverteidigung
frauenselbstverteidigung
frauenstein
frauenstein
fraunhofer
fraunhofer
freak
freak
freak
freaks
freaks
frears
freche
freche
frechen
frechen
freckenhorst
freckenhorst
fredda
freddo
freddy vs
freddy vs
freddy
freddy
freddy
fredenbeck
fredenbeck
frederic
frederic
frederic
frederic
frederick
frederik
frederik
fredersdorf
fredersdorf
free sex
free sms
free sms
free software
free web
free xxx
freebsd
freebsd
freebsd
freebsd
freebsd
freebsd
freecity
freecity
freedom
freedom
freedom
freedom
freegames
freegames
freehand
freelance webdeveloper
freelance
freelance
freelance
freelance
freelance
freelance
freelancer
freelancer
freelancer
freelancers
freelances
freelances
freeman
freenet
freenet
freenet
freeonline
freeride
freeride
freeride
freeride
freeride
freeski
freeski
freestyle
freestyle
freestyle
freestyle
freestyle
freestyle
freestyle
freeware
freeware
freeware
freeware
freeware
freeware
freeware
freewares
freewares
freeway
freeway
freeweb
frei haus
frei haus
freibad
freibad
freiberg
freiberg
freiberger
freiberger
freiberufler
freiberufler
freiburg
freiburg
freiburg im breisgau
freiburg im breisgau
freiburg im
freiburg im
freiburg
freiburg
freiburg
freiburg
freiburger
freiburger
freidenker
freidenker
freie evangelische gemeinde
freie evangelische gemeinde
freie evangelische
freie evangelische
freie schule
freie schule
freie software
freie software
freie wähler
freie wähler
freie waldorfschule
freie waldorfschule
freie zimmer
freie zimmer
freie
freie
freien
freien
freienbach
freienbach
freienwalde
freienwalde
freiepresse
freiepresse
freier software
freier software
freier
freier
freies
freies
freiform
freiform
freight
freight
freiheit
freiheit
freiherr
freiherr
freihof
freihof
freikirche
freikirche
freikirchlich
freikirchlich
freikirchliche gemeinde
freikirchliche gemeinde
freikirchliche
freikirchliche
freikirchlicher gemeinden
freikirchlicher gemeinden
freikirchlicher
freikirchlicher
freiland
freiland
freilassing
freilassing
freilichtbühne
freilichtbühne
freilichtmuseum kiekeberg
freilichtmuseum kiekeberg
freilichtmuseum
freilichtmuseum
freilingen
freilingen
freimaurer
freimaurer
freimaurerei
freimaurerei
freimaurerloge
freimaurerloge
freinet
freinet
freins
freins
freinsheim
freinsheim
freiraum
freiraum
freiraumplanung
freiraumplanung
freising
freising
freisprecheinrichtung
freisprecheinrichtung
freistaat
freistaat
freistadt
freistadt
freitag
freitag
freital
freital
freiw
freiw
freiwillig
freiwillig
freiwillige feuerwehr
freiwillige feuerwehr
freiwillige
freiwillige
freiwilligen feuerwehr
freiwilligen feuerwehr
freiwilligen
freiwilligen
freiwilligendienst
freiwilligendienst
freiwilligendienste
freiwilligendienste
freizeit und
freizeit und
freizeit
freizeit
freizeitanlagen
freizeitanlagen
freizeitbad
freizeitbad
freizeitclub
freizeitclub
freizeiten
freizeiten
freizeitheim
freizeitheim
freizeitkarte
freizeitkarte
freizeitpark
freizeitpark
freizeitparks
freizeitparks
freizeitreiten
freizeitreiten
freizeitsport
freizeitsport
freizeitzentrum
freizeitzentrum
frejus
frejus
fremd
fremd
fremde
fremde
fremden
fremden
fremdenführer
fremdenführer
fremdenverkehr
fremdenverkehr
fremdenzimmer
fremdenzimmer
fremdsprache
fremdsprache
fremdsprachen
fremdsprachen
french courses
french courses
french in
french in
french language
french language
french manicure
french riviera
french riviera
french riviera
french riviera
french translation
french translation
french wine
french wine
french
french
french
french
french
french
french
freni
freno
frenos
frente a
frente
frenzel
frenzel
frequency
frequency
frequency
frequentie
frequenz
frequenz
frequenza
frequenzen
frequenzen
fresatrici
fresatura
fresca
freschi
fresco
fresco
frese
fresh
fresh
fresh
fresh
fresh
fresh
fresno
fresque
fresque
fresques
fresques
frett
frett
frettchen
frettchen
fretten
freud
freud
freud
freud
freude
freude
freudenberg
freudenberg
freudenstadt
freudenstadt
freuen uns
freuen uns
freuen
freuen
freund
freund
freunde der
freunde der
freunde und förderer
freunde und förderer
freunde und
freunde und
freunde
freunde
freunden
freunden
freundes
freundes
freundeskreis
freundeskreis
freundin
freundin
freundlich
freundlich
freundliche
freundliche
freundschaft
freundschaft
freyer
freyer
freystadt
freystadt
freyung
freyung
frezen
friûl
friaul
friaul
fribourg suisse
fribourg suisse
fribourg
fribourg
fribourg
fribourg
frica
frick
frick
fricke
fricke
fricktal
fricktal
frida
frida
fridericiana
fridericiana
fried
fried
friedberg
friedberg
friede
friede
friedel
friedel
frieden
frieden
friedenau
friedenau
friedens
friedens
friedensbündnis
friedensbündnis
friedensbewegung
friedensbewegung
friedensdienst
friedensdienst
friedensforschung
friedensforschung
friedensforum
friedensforum
friedensinitiative
friedensinitiative
friedenskirche
friedenskirche
friedensnetz
friedensnetz
friedensplenum
friedensplenum
friedensratschlag
friedensratschlag
friedensreich
friedensreich
friederike
friederike
friedetzky
friedetzky
friedhöfe
friedhöfe
friedhelm
friedhelm
friedhof
friedhof
friedhofsgärtnerei
friedhofsgärtnerei
friedl
friedl
friedland
friedland
friedr
friedr
friedrich wilhelm
friedrich wilhelm
friedrich
friedrich
friedrich
friedrich
friedrich
friedrich
friedrich
friedrichs
friedrichs
friedrichsdorf
friedrichsdorf
friedrichshafen
friedrichshafen
friedrichshain
friedrichshain
friedrichskoog
friedrichskoog
friedrichstadt
friedrichstadt
friend
friend
friend
friendly
friends
friends
friends
friends
friends
friends
friends
fries
fries
fries
friesach
friesach
friesch
friese meren
friese
friese
friese
friesen
friesen
friesenheim
friesenheim
friesenhof
friesenhof
friesenpferde
friesenpferde
friesisch
friesisch
friesische
friesische
friesland
friesland
friesland
friesland
friesoythe
friesoythe
frigento
frigiliana
frigo
frigo
frigo
frigorifere
frigoriferi
frigorifique
frigorifique
frigorifiques
frigorifiques
friki
frings
frings
frisör
frisör
frisbee
frisbee
frisbee
frisbee
frisbee
frisch
frisch
frische
frische
frischer
frischer
friseur
friseur
friseurbedarf
friseurbedarf
friseure
friseure
friseursalon
friseursalon
frisia
frisia
frisoer
frisoer
frison
frison
frisse
frist
frist
fristen
fristen
frisur
frisur
frisuren
frisuren
friteuse
friteuse
frits
fritsch
fritsch
fritsche
fritsche
fritz lang
fritz lang
fritz
fritz
fritzlar
fritzlar
fritzsche
fritzsche
friul
friulana
friuli venezia giulia
friuli venezia giulia
friuli venezia giulia
friuli venezia
friuli venezia
friuli venezia
friuli
friuli
friuli
frogs
frogs
frohburg
frohburg
frohnau
frohnau
frohsinn
frohsinn
froid
froid
froide
froide
from hell
from hell
from the
from the
from the
from the
from the
from the
fromage aoc
fromage aoc
fromage
fromage
fromager
fromager
fromagerie
fromagerie
fromages
fromages
froment
froment
fromm
fromm
front
front
front
front
front
front
front
frontalier
frontalier
frontaliers
frontaliers
fronte mare
fronte
frontera
fronteras
frontière
frontière
frontières
frontières
frontiere
fronton
fronton
frontpage
frontpage
frontpage
frontpage
frontpage
frontpage
frontpage
frontplatten
frontplatten
frosch
frosch
frosinone
frosinone
frostfutter
frostfutter
frozen
frozen
frucht
frucht
fruehstueck
fruehstueck
fruit
fruit
fruit
fruit
fruit
fruit
fruitier
fruitier
fruits de mer
fruits de mer
fruits de
fruits de
fruits et légumes
fruits et légumes
fruits et
fruits et
fruits
fruits
fruits
fruitteelt
frumento
fruta
frutas
frutos secos
frutos
frutta secca
frutta verdura
frutta
fruttero
fruttero
frutti
frutto
frysk
fryslân
fryslan
fucecchio
fuchs
fuchs
fuchsbau
fuchsbau
fuchsia
fuchsia
fuchsias
fuchsias
fucili
fucinaweb
fucine
fuego
fuegos
fuehrer
fuehrer
fuengirola
fuenlabrada
fuente de
fuente
fuenteheridos
fuentes de
fuentes
fuera de servicio
fuera de
fuera
fuerte
fuerte
fuerte
fuertes
fuerteventura
fuerteventura
fuerteventura
fuerza de ley
fuerza de
fuerza
fuerzas
fugen
fugen
fuhrmann
fuhrmann
fuhrpark
fuhrpark
fuissé
fuissé
fuite
fuite
fuiven
fujitsu siemens
fujitsu siemens
fujitsu
fujitsu
fujitsu
fujitsu
fujitsu
fujitsu
fulda
fulda
fulfillment
fulfillment
full colour
full service
full service
full service
fullservice
fullservice
fulltime
fully
fully
fully
fully
fulpmes
fulpmes
fumée
fumée
fumadores
fumar
fumare
fumaria
fumarie
fumatori
fumer
fumer
fumetti
fumetto
funès
funès
funéraire
funéraire
funambule
funambule
funboard
funboard
funciona
funcional
funcionamiento
funcionarios
funciones
functie
functiebeperking
functies
function
function
functioneel
functioneringsgesprekken
fundaciã
fundació
fundación para la
fundación para
fundación
fundacion
fundaciones
fundador
fundamental
fundas
fundbüro
fundbüro
fundgrube
fundgrube
fundicion
fundraising
fundraising
funds
funds
funds
funds
fundus
fundus
funebri
funeraria
funerarias
funerario
funghi e
funghi porcini
funghi
fungo
funicolare
funke
funke
funken
funken
funkenerosion
funkenerosion
funkgerät
funkgerät
funkgeräte
funkgeräte
funkkamera
funkkamera
funktie
funktion
funktion
funktionen
funktionen
funktions
funktions
funkuhren
funkuhren
funky
funky
funky
funny
funny
funny
funny
funpic
funpic
funpics
funpics
funsport
funsport
funtastic
funzioni
fuochi d'artificio
fuochi
fuoco
fuori
fuoristrada
furcht
furcht
furet
furet
furgone
furgonetas
furgoni
furia
furious
furious
furlan
furnace
furnace
furnier
furnier
furnished apartment
furnished apartment
furnished
furnished
furnished
furnished
furnished
furnishing
furniture
furniture
furniture
furniture
furniture
furniture
furniture
furrer
furrer
furth
furth
furti
furto
furtwangen
furtwangen
fuschl am see
fuschl am see
fuschl am
fuschl am
fuschl
fuschl
fuschlsee
fuschlsee
fushigi
fusie
fusil
fusil
fusing
fusing
fusion
fusion
fusion
fusion
fusion
fusion
fusione
fusioni
fussball
fussball
fussboden
fussboden
fussbodenheizung
fussbodenheizung
fusspflege
fusspflege
fusti
futbol
futon
futon
futon
futon
futsal
futsal
futsal
futsal
futter
futter
futtermittel
futtermittel
futtertiere
futtertiere
futuna
futuna
futur
futur
futur
futur
futura
futura
futura
futura
futurama
futurama
futurama
future
future
future
future
future
future
futures
futures
futures
futures
futures
futurismo
futurista
futuro
futuro
futuro
futuro
futuros
futuroscope
futuroscope
fysica
fysio
fysiotherapeut
fysiotherapie
gállego
gâteau
gâteau
gâteaux
gâteaux
gâtinais
gâtinais
gänse
gänse
gänserndorf
gänserndorf
gärten
gärten
gärtner
gärtner
gärtnerei
gärtnerei
gäste
gäste
gästebücher
gästebücher
gästebuch
gästebuch
gästeführer
gästeführer
gästefarm
gästefarm
gästehäuser
gästehäuser
gästehaus
gästehaus
gästezimmer
gästezimmer
géant
géant
géants
géants
généalogie des
généalogie des
généalogie
généalogie
généalogique
généalogique
généalogiques
généalogiques
général de france
général de france
général de
général de
général du
général du
général
général
générale de
générale de
générale
générale
générales
générales
générateur
générateur
génération
génération
généraux
généraux
génériques
génériques
génétique
génétique
género
géneros
génie civil
génie civil
génie
génie
génocide
génocide
géographie
géographie
géographique
géographique
géologie
géologie
géologique
géologique
géomètre
géomètre
géomètres
géomètres
géométrie
géométrie
géomatique
géomatique
géopolitique
géopolitique
géorgie
géorgie
géothermie
géothermie
gérance
gérance
gérard
gérard
gérardmer
gérardmer
gérer
gérer
gériatrie
gériatrie
gévaudan
gévaudan
gîte de france
gîte de france
gîte de
gîte de
gîte du
gîte du
gîte rural
gîte rural
gîtes de france
gîtes de france
gîtes de
gîtes de
gîtes ruraux
gîtes ruraux
gîtes
gîtes
gîtes
gîtes
gîtes
gómez
göbel
göbel
gögging
gögging
göhren
göhren
göppingen
göppingen
görlitz
görlitz
götter
götter
göttin
göttin
göttingen
göttingen
göttingen
göttingen
göttinger
göttinger
göttlichen geheimnisse
göttlichen geheimnisse
göttlichen
göttlichen
götzis
götzis
güglingen
güglingen
gülle
gülle
gültige
gültige
günstig
günstig
günstige gelegenheit
günstige gelegenheit
günstige
günstige
günstigen preisen
günstigen preisen
günstigen
günstigen
günstiger
günstiger
günstiges
günstiges
günstigste
günstigste
günter grass
günter grass
günter grass
günter
günter
günter
günther
günther
günzburg
günzburg
günzburg
günzburg
gürtel
gürtel
güssing
güssing
güstrow
güstrow
güter
güter
gütersloh
gütersloh
gaarden
gaarden
gaarder
gaarder
gaasterland
gabón
gabaldon
gabaldon
gabbana
gabbana
gabber
gabbiani
gabbiano
gabel
gabel
gabele
gabele
gabelstapler
gabelstapler
gabicce mare
gabicce
gabinete de
gabinete
gabionen
gabionen
gables
gabon
gabon
gabriel marcel
gabriel marcel
gabriel
gabriel
gabriel
gabriel
gabriel
gabriel
gabriela
gabriela
gabriela
gabriele muccino
gabriele salvatores
gabriele
gabriele
gabriele
gabrielli
gaceta
gadamer
gadamer
gadamer
gadda
gadget
gadget
gadget
gadget
gadgets
gadgets
gadgets
gadgets
gaestebuch
gaestebuch
gaestehaus
gaestehaus
gaestezimmer
gaestezimmer
gaeta
blogspirit
xanga
g-blog
blog-city
blogsome
blogg
msn
oldiblog
blogeasy
joueb
alfablog
avatale
blogstudio
blog.ca
blog.com
bloghi.com
ebloggy.com
blogigo
blogsharing
blogsource
blogspot
bloxster
cool-blog


Wednesday, January 18, 2006

Using the Xalan XSLT engine within a java servlet

Using the Xalan XSLT engine within a java servlet

Introduction

Separation of style from content allows for the same data to be presented in different ways and is the clear answer to the multiplication of connected devices (Palm, Pocket PC, Interactive TV) that can access networked ressources using their own language (WML, WebClipping, HTML, XHTML, cHTML, etc..).
In this article, we show how to produce HTML and WML content from an XML data source, and the appropriate XSLT stylesheets. The XSLT transformation is done using the Xalan transformation engine, an open-source java project hosted by the Apache foundation. The Xalan engine is called from a java servlet, running in the Tomcat servlet engine.
 

Requirements

In this article, I will assume that you have installed the Tomcat servlet engine, and the Xalan XSLT engine. Both are available from java.apache.org and xml.apache.org. I also assume that xalan.jar, xerces.jar (the XML parser bundled with Xalan) and the servlet classes are present in your classpath. If not, try something like:

XALAN_HOME=/path/to/xalan.jar
XERCES_HOME=/path/to/xerces.jar
export CLASSPATH=$CLASSPATH:$XALAN_HOME:$XERCES_HOME
 
 

Creating a new web application within Tomcat

Although you could install your java classes in an existing web application (the one called "examples", for instance), it is probably better to create a new web application.  This is nicely explained in "Deploying web applications to Tomcat" by James Goodwill.
Assuming $TOMCAT_HOME is the path to the Tomcat directory, first change directory to webapps (the root of all web applications) and create the following directories:

/xslt
/xslt/WEB-INF
/xslt/WEB-INF/classes

To do so, type the following commands:
> cd $TOMCAT_HOME/webapps
> mkdir xslt
> cd xslt
> mkdir WEB-INF
> cd WEB-INF
> mkdir classes
> cd classes

The /xslt/WEB-INF/classes directory is the place where you will store all the servlets classes described below.

Once the directories are created, you should install a servlet context, by editing the file $TOMCAT_HOME/conf/server.xml, and adding the following lines:

<Context path="/xslt" docBase="webapps/xslt" debug="0" reloadable="true" >
</Context>

path="/xslt" tells Tomcat that all requests starting with /onjava belong to the onjava web application.
docBase="webapps/xslt" tells the servlet container that the web application is located on webapps/xslt"
 

Once you have done these operations, you need to restart Tomcat.
 

Xalan-J : a Java XSLT engine

We use Xalan as our XSLT engine. While we embed Xalan within our servlet, Xalan-J can also be used in a command line way to perform XSLT transformation and produce static output files. For example, imagine you want to produce a static HTML file called slashdot.html from a XML file called slashdot.xml.
You just need to type the following line:
> java org.apache.xalan.xslt.Process -in slashdot.xml -xsl slashdot.xsl -out slashdot.html

If you want the output to be displayed on the screen, simply omit the -out flag and argument.

The XSLT processor class

Xalan-J implements the TrAX (Transformation API for XML) interface. From the Xalan documentation: "A TRaX TransformerFactory is an object that processes transformation instructions, and produces Templates (in the technical terminology). A Templates object provides a Transformer, which transforms one or more Sources into one or more Results. To use the TRaX interface, you create a TransformerFactory, which may directly provide a Transformers, or which can provide Templates from a variety of Sources. The Templates object is a processed or compiled representation of the transformation instructions, and provides a Transformer. The Transformer processes a Source according to the instructions found in the Templates, and produces a Result".
In the code below, the XSLT processor class contains a method that takes as input a XML source, a XSL source, a servlet request (it is not used here) and a servlet response, and it returns the output of the transformation to the servlet output stream.


import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

import org.xml.sax.SAXException;

import javax.xml.transform.*;
import javax.xml.transform.stream.*;

public class XalanXslProcessorBean {

    TransformerFactory tFactory;

    //the constructor simply gets a new TransformerFactory instance
    public XalanXslProcessorBean() {
        tFactory = TransformerFactory.newInstance();
    }

    //this method takes as input a XML source, a XSL source, and returns the output of the transformation to the servlet output stream
    public void process(StreamSource xmlSource,
                                  StreamSource xslSource,
                                  HttpServletRequest request,
                                  HttpServletResponse response)
             throws ServletException, IOException, SAXException {
        try {
            Templates templates = tFactory.newTemplates(xslSource);
            Transformer transformer = templates.newTransformer();
             transformer.transform(xmlSource, new StreamResult(response.getOutputStream()));
        }
        catch (Exception e) {
           //should log some message here
        }
    }
}



 
 

The XML data

The XML file we will use was grabbed from the slashdot.org site, and contains the slashdot news in XML form. It needs to be saved to your disk (and called slashdot.xml for example).


<?xml version="1.0"?><backslash xmlns:backslash="http://slashdot.org/backslash.dtd">

 <story>
  <title>NASA Proposes Launch Solar Sail Vehicle For 2010</title>
  <url>http://slashdot.org/article.pl?sid=00/05/15/058238</url>
  <time>2000-05-15 07:54:15</time>
  <author>timothy</author>
  <department>ralph-nader-will-have-to-hire-a-chase-car</department>
  <topic>space</topic>
  <comments>99</comments>
  <section>articles</section>
  <image>topicspace.gif</image>
 </story>

 <story>
  <title>Linuxcare Responds To Tim O'Reilly's Article</title>
  <url>http://slashdot.org/article.pl?sid=00/05/15/0254252</url>
  <time>2000-05-15 02:57:07</time>
  <author>timothy</author>
  <department>consider-source-horses-mouth-grain-of-salt</department>
  <topic>linuxbiz</topic>
  <comments>142</comments>
  <section>articles</section>
  <image>topiclinuxbiz.gif</image>
 </story>

 <story>
  <title>New Internet VCR Service</title>
  <url>http://slashdot.org/article.pl?sid=00/05/14/2048217</url>
  <time>2000-05-14 20:51:57</time>
  <author>timothy</author>
  <department>this-is-cool-but-can-they-do-that?</department>
  <topic>news</topic>
  <comments>189</comments>
  <section>articles</section>
  <image>topicnews.gif</image>
 </story>

 <story>
  <title>Google Releases WAP Search Tool</title>
  <url>http://slashdot.org/article.pl?sid=00/05/14/1240252</url>
  <time>2000-05-14 17:49:11</time>
  <author>emmett</author>
  <department>wireless</department>
  <topic>internet</topic>
  <comments>141</comments>
  <section>articles</section>
  <image>topicinternet.jpg</image>
 </story>

 <story>
  <title>No More Unreal Ports For Linux?</title>
  <url>http://slashdot.org/article.pl?sid=00/05/14/1439224</url>
  <time>2000-05-14 16:32:11</time>
  <author>timothy</author>
  <department>one-web-one-program-happy-mothers-day</department>
  <topic>games</topic>
  <comments>250</comments>
  <section>articles</section>
  <image>topicgames.jpg</image>
 </story>

 <story>
  <title>Pioneer Introduces 1st DVD Recorder (In Japan)</title>
  <url>http://slashdot.org/article.pl?sid=00/05/14/152210</url>
  <time>2000-05-14 15:50:48</time>
  <author>CmdrTaco</author>
  <department>steam-rising-from-the-riaas-forehead</department>
  <topic>tv</topic>
  <comments>98</comments>
  <section>articles</section>
  <image>topictv.jpg</image>
 </story>

 <story>
  <title>QuakeForge And QuakeWorld Forever Merge</title>
  <url>http://slashdot.org/article.pl?sid=00/05/14/1447248</url>
  <time>2000-05-14 15:07:27</time>
  <author>CmdrTaco</author>
  <department>and-then-there-was-one</department>
  <topic>quake</topic>
  <comments>57</comments>
  <section>articles</section>
  <image>topicquake.gif</image>
 </story>

 <story>
  <title>What Happens When Open Source And Work Collide?</title>
  <url>http://slashdot.org/article.pl?sid=00/05/09/016208</url>
  <time>2000-05-14 14:04:07</time>
  <author>Cliff</author>
  <department>sticky-situations</department>
  <topic>programming</topic>
  <comments>170</comments>
  <section>askslashdot</section>
  <image>topicprogramming.gif</image>
 </story>

 <story>
  <title>Black Holes Don't Exist???</title>
  <url>http://slashdot.org/article.pl?sid=00/05/14/1339252</url>
  <time>2000-05-14 13:39:24</time>
  <author>Roblimo</author>
  <department>pop-science-can-be-fun</department>
  <topic>science</topic>
  <comments>162</comments>
  <section>articles</section>
  <image>topicscience.gif</image>
 </story>

 <story>
  <title>Los Alamos Lab: We're OK, You're OK</title>
  <url>http://slashdot.org/article.pl?sid=00/05/14/0143228</url>
  <time>2000-05-14 04:44:44</time>
  <author>timothy</author>
  <department>sir-please-step-*away*-from-the-plutonium-bin</department>
  <topic>news</topic>
  <comments>278</comments>
  <section>articles</section>
  <image>topicnews.gif</image>
 </story>

</backslash>



 

The XSLT stylesheet

An XSL stylesheet basically consists of a set of templates. Each template "matches" some set of elements in the original XML data and then describes the contribution that the matched element makes to the final output.
An XSLT template is defined by a xsl:template tag, whose "match" parameter determines where this template applies. For example <xsl:template match="/"> ... </xsl:template> applies to the root element of the XML document, while <xsl:template match="backslash/story"> matches every story element that has backslash as father. Templates are generally applied recursively, i.e. a template calls another templates using the xsl:apply-templates tag.
<xsl:value-of> inserts the value of an expression to the final output. Note that {element} can also be used to insert the value of element.

Here is the HTML stylesheet (named slashdot.xsl) we will use:



<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">

<xsl:template match="/">
<html>
<body>
<xsl:apply-templates select="backslash/story"/>
</body>
</html>
</xsl:template>

<xsl:template match="backslash/story">
  <li><a href="{url}"><xsl:value-of select="title"/></a></li>
</xsl:template>

</xsl:stylesheet>


Outputting HTML with a servlet

This java code implements a basic servlet, which uses the XalanXslProcessorBean class defined above. It sets the Content-Type portion of the HTTP header to text/html, creates two StreamSources objects from both the xml and the xsl files, and perform the transformation


import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;

import javax.xml.transform.stream.*;

public class XslProcessorServlet extends HttpServlet {

    XalanXslProcessorBean processor;

    public void init(ServletConfig config) {
        processor = new XalanXslProcessorBean();
    }

    public void doGet (HttpServletRequest request,
                                HttpServletResponse response)
             throws ServletException, IOException {

        //sets the Content-Type portion of the HTTP header to text/html
        response.setContentType("text/html");
        try {
            processor.process(new StreamSource("slashdot.xml"), new StreamSource("slashdot.xsl"), request, response);
        }
        catch (Exception e) {

        }
    }
}


Since slashdot.xml is often updated,  you may prefer to fetch it directly from the slashdot.org site:  you then need to change the processor.process(...) line to: processor.process(new StreamSource(new InputStreamReader((new URL("http://slashdot.org/slashdot.xml")).openStream())), new StreamSource("slashdot.xsl"), request, response);
Then restart your servlet container if needed, and reload the page.
 

Outputting HTML and WML with a servlet


Suppose that you want to make your content available to both HTML and WML navigators. Basically, you just need a XSLT stylesheet that can transform XML to HTML, and another one that can transform XML to WML (Wireless Meta Language). You then need to implement a mechanism that can use the appropriate stylesheet, depending on the navigator information contained in the HTTP request header.

Here is the WML stylesheet. Note the xsl:output tag, which is the only way to produce the <!DOCTYPE wml PUBLIC "-//WAPFORUM//DTD WML 1.1//EN" "http://www.wapforum.org/DTD/wml_1.1.xml"> string in the WML output.



<?xml version="1.0"?>
<xsl:stylesheet xmlns:xsl="http://www.w3.org/1999/XSL/Transform" version="1.0">
<xsl:output method="xml"
                  doctype-public="-//WAPFORUM//DTD WML 1.1//EN"
                  media-type="text/vnd.wap.wml"
                  doctype-system="http://www.wapforum.org/DTD/wml_1.1.xml"
                  encoding="ISO-8859-1"/>

<xsl:template match="/">
<wml>

    <template>
        <do type="prev" name="Previous" label="Back">
            <prev/>
        </do>
    </template>

    <card id="card1" title="Slashdot news">
        <p>
            <xsl:apply-templates select="backslash/story"/>
        </p>
    </card>

</wml>
</xsl:template>
 

<xsl:template match="backslash/story">
  <a href="{url}"><xsl:value-of select="title"/></a><br/>
</xsl:template>

</xsl:stylesheet>


Note that the following servlet code now contains some code to fetch the user agent from the HTTP header, and uses the WML stylesheet when the user agent string contains the word (Nokia). Obviously, this only works with a Nokia phone or with some Nokia emulator.



import java.io.*;
import java.net.*;
import javax.servlet.*;
import javax.servlet.http.*;

import javax.xml.transform.stream.*;

public class XslProcessorServlet extends HttpServlet {

    XalanXslProcessorBean processor;

    public void init(ServletConfig config) {
        processor = new XalanXslProcessorBean();
    }

    public void doGet (HttpServletRequest request,
                                HttpServletResponse response)
        throws ServletException, IOException {

        //fetch the user agent part of the HTTP header
        String useragent = request.getHeader("user-agent");

        //if the user agent contains the string "Nokia", then use the WML stylesheet, otherwise use the HTML one
        StreamSource xslsource;
        if (useragent.indexOf("Nokia") >= 0) {
            //send the correct Content-Type
            response.setContentType("text/vnd.wap.wml");
            xslsource = new StreamSource("slashdot_wml.xsl");
        } else {
            response.setContentType("text/html");
            xslsource = new StreamSource("slashdot_html.xsl");
        }

        try {
            processor.process(new StreamSource("slashdot.xml"), xslsource, request, response);
        }
        catch (Exception e) {

        }
    }
}




Tuesday, January 17, 2006

J'ai crée un petit annuaire que vous pouvez visiter :

http://www.aidezmoi.org/