XPathW3C.java

/*
* XPathW3C.java
* Copyright (C) 2004 Frederic Laurent
* http://www.opikanoba.org
*
* This file is part of the XPath Article.
*
* Lantern is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Lantern is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with the Xpath article; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*
*/

/**
 * Test XPath avec l'API du W3C.
 * Ce programme est volontairement très simple. Le but n'est pas
 * de tester tous les cas possibles et les cas d'erreur mais de 
 * donner rapidement un aperçu des objets à utiliser.
 * 
 * @author Fréderic Laurent
 */

package test;
import java.io.OutputStreamWriter;
import java.net.URL;


import javax.xml.parsers.DocumentBuilderFactory;

import javax.xml.transform.OutputKeys;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.DOMImplementation;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
import org.w3c.dom.xpath.XPathEvaluator;
import org.w3c.dom.xpath.XPathResult;
import org.xml.sax.InputSource;


public class XPathW3C {
    // Document DOM sur lequel les requetes XPAth sont effectuées
    private Document doc = null;
    // Transformateur XSLT
    private Transformer out_ser;
    /**
     * Construction de la classe de test 
     *  - intialisation d'un transfomeur XSLT pour sortir les resultats 
     * sous forme de fragment de document (la transformation identité
     * permet d'avoir le flux XML sur la sortie standard)
     *  
     */
    public XPathW3C() {
        try {
            this.out_ser = TransformerFactory.newInstance().newTransformer();
            this.out_ser.setOutputProperty(OutputKeys.OMIT_XML_DECLARATION, "yes");
        } catch (Exception e) {
            // si une exception quelconque survient, elle est tracée
            // Attention, le traitement est volontairement simple dans un souci
            // d'allègement du code ! un traitement correct serait beaucoup plus
            // détaillé
            System.err.println(e.getMessage());
            e.printStackTrace();
        }
    }
    /**
     * Ecrit sur la sortie standard n'importe quel noeud XML en utilisant la
     * transformation identité si necessaire
     * 
     * @param node noeud à tracer
     */
    public void printResult(Node node) {
        try {
            // test du type de noeud
            int nodeType = node.getNodeType();
            
            // s'il s'gait d'un noeud texte, on l'ecrit sur la sortie standard
            if (nodeType == Node.CDATA_SECTION_NODE || nodeType == Node.TEXT_NODE) {
                
                System.out.println(node.getNodeValue());
                //  il se peut que le noeud ait des noeuds voisins, un meme texte
                // peut etre représenté par plusieurs noeuds adjacents
                Node next = node.getNextSibling();
                if (next != null) {
                    printResult(next);
                }
            } else {
                // sinon on fait appel à la transformation identité
                this.out_ser.transform(new DOMSource(node), new StreamResult(
                        new OutputStreamWriter(System.out)));
            }
        } catch (Exception e) {
            // si une exception quelconque survient, elle est tracée
            // Attention, le traitement est volontairement simple dans un souci
            // d'allègement du code ! un traitement correct serait beaucoup plus
            // détaillé
            System.err.println(e.getMessage());
            e.printStackTrace();
        }
    }
    
    /**
     * Lecture du document avec JAXP
     * 
     * @param xmlbuf buffer XML
     */
    public void loadDocument(String xmlbuf) {
        InputSource is;
        try {
            if (xmlbuf.startsWith("http://") || xmlbuf.startsWith("file:")) {
                is = new InputSource(new URL(xmlbuf).toString());
            } else {
                is = new InputSource(xmlbuf);
            }
            // lecture du document
            DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
            dbf.setNamespaceAware(true);
            dbf.setValidating(false);
            this.doc = dbf.newDocumentBuilder().parse(is);
            
        } catch (Exception e) {
            // si une exception quelconque survient, elle est tracée
            // Attention, le traitement est volontairement simple dans un souci
            // d'allègement du code ! un traitement correct serait beaucoup plus
            // détaillé
            System.err.println(e.getMessage());
            e.printStackTrace();
        }
    }
    /**
     * Evaluation d'une expression XPath 
     * - création d'une évaluateur d'expression à partir du 
     *   document DOM 
     * - parcours de l'ensemble des noeuds résultat et 
     *   affichage de chacun
     * 
     * @param xpath
     *            expression à évaluer
     */
    public void evalXpath(String xpath) {
        // création de l'évaluateur : appel explicite à l'API de Xalan
        // cette expression va évoluer avec la sortie de la recommandation DOM XPath 3
        // et la mise à jour des implementations en conséquence
        XPathEvaluator evaluator = new org.apache.xpath.domapi.XPathEvaluatorImpl(doc);
    
        // évaluation de l'expression XPath
        XPathResult result = (XPathResult) evaluator.evaluate(xpath, doc, null,
                XPathResult.UNORDERED_NODE_ITERATOR_TYPE, null);
        // parcours des noeuds correspondant à l'expression XPath
        // et affichage de chacun
        Node n = result.iterateNext();
        while (!= null) {
            printResult(n);
            n = result.iterateNext();
        }
    }
    /**
     * Programme principal
     * 
     * @param args arguments de la ligne de commande
     */
    public static void main(String[] args) {
        if (args.length < 2) {
            System.err.println("usage: java test.XPathW3C xml xpath");
            System.err.println("   - xml   document XML");
            System.err.println("   - xpath expression XPath");
            System.exit(1);
        }
        
        // Test de l'implementation DOM pour savoir si elle implémente DOM Niveau 3
        DOMImplementation impl=null;
        try {
            // obtention d'une implémentation
            impl = DocumentBuilderFactory.newInstance().newDocumentBuilder().getDOMImplementation();
            // test de la propriété adéquate
            if (!impl.hasFeature("XPath", "3.0")) {
                  System.err.println("Cette implementation ne supporte pas DOM 3 XPath");  
                  System.exit(1);
            } else {
            System.out.println("Cette implementation supporte DOM 3 XPath");  
            }
        } catch (Exception e) {     
            // si une exception quelconque survient, elle est tracée
            // Attention, le traitement est volontairement simple dans un souci
            // d'allègement du code ! un traitement correct serait beaucoup plus
            // détaillé
            System.err.println(e.getMessage());
            e.printStackTrace();
        }
        
        final String uri = args[0];
        final String xpath = args[1];
        // initialisation de la classe de test
        XPathW3C test = new XPathW3C();
        // lecture du document
        test.loadDocument(uri);
        // evaluation de l'expression XPath
        test.evalXpath(xpath);
    }
}