/*
 * Fichero:     AnalizadorXML.java
 * Fecha:       20/10/06
 * Autor:       Alvaro Sarmiento losada
 * Asignatura:  Proyecto Fin de Carrera
 * Descripción: Contiene la clase AnalizadorXML, que proporciona métodos de
 *              validación y comprobación de bien formado de documentos XML.
 *
 * Este fichero pertenece al proyecto fin de carrera del autor,
 * consistente en el estudio de JXTA y su aplicación al comercio 
 * electrónico b2b.
 */

package com.pfc.lib.xml;

import java.io.InputStream;
import java.io.IOException;

import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.DefaultHandler;

/**
 * Colección de métodos útiles para comprobar si un documento XML es
 * bien-formado (well-formed) según la sintaxis XML, y/o válido (valid) 
 * según un DTD (Document Type Definition).
 * <b>Nota:</b>
 * <i>El analizador XML usado en esta clase es el SAX.</i>
 *
 * @author  Alvaro Sarmiento Losada
 */
public abstract class AnalizadorXML {
    
    /**
     * Realiza una análisis de sintaxis y/o validación con DTD de un 
     * documento XML, a través de un analizador SAX. Si ocurre cualquier 
     * tipo de error relacionado con la sintaxis XML o validación durante 
     * el análisis, se lanzará  una excepción <code>SAXException</code>.
     * 
     * @param  entrada un flujo <code>InputStream</code> que contiene el
     *                 documento XML que se quiere analizar (bien-formado
     *                 y/o valido).
     * @param  validar <code>false</code> si sólo se desea un análisis
     *                 de bien formado. <br>
     *                 <code>true</code> si además se desea una análisis
     *                 de validación.
     *@throws SAXException si ocurre un error de sintaxis o validación 
     *                     durante el análisis.
     */
    protected static void analizar(InputStream entrada, boolean validar) throws SAXException {
        try {
            //Se crea una factoría de parsers SAX
            SAXParserFactory factoria = SAXParserFactory.newInstance();
            factoria.setValidating(validar);
            //Se crea el analizador SAX
            SAXParser analizador = factoria.newSAXParser();
            
            /*
             * Se realiza el análisis con el parser SAX. 
             * Un parser SAX necesita un manejador de errores: se le
             * proporciona uno implementado como clase anónima.
             */
            analizador.parse(entrada, new DefaultHandler() {
                /*
                 * Esta clase anónima sólo va a implementar un método de manejo
                 * de errores básico. No se va a realizar ningún procesamiento
                 * del error, solamente se relanzará la excepción en forma de
                 * SAXException para que pueda ser relanzada de nuevo por el 
                 * método principal.
                 */
                public void error(SAXParseException spe) throws SAXException {
                    throw new SAXException(spe);
                }
            });
            
        } catch (ParserConfigurationException pce) {
            //Error fatal: el parser no se puede configurar como se desea
            throw new SAXException(pce);
        } catch (IOException ioe){
            /*
             * Un error de I/O se considera fatal, pero no se relanza la
             * excepción puesto que no es error de sintaxis y/o validación.
             */
        }
    }
    
    /**
     * Devuelve si el documento XML especificado es bien-formado, es decir, 
     * si cumple con la sintaxis XML.
     * 
     * @param  entrada un flujo que contiene un documento XML
     * @return         si el documento especificado es bien-formado según
     *                 la sintaxis XML.
     */
    public static boolean esBienFormado(InputStream entrada) {
        boolean resultado;
        
        try {
            //Analizamos sin validación
            analizar(entrada, false);
            resultado = true;
        } catch (SAXException se) {
            resultado = false;
        }
        
        return resultado;
    }
    
    /**
     * Devuelve si el documento XML especificado es válido, es decir, si
     * cumple con la sintaxis XML (bien-formado) y además cumple con la 
     * sintaxis definida en el DTD (Document Type Definition) incorporado 
     * en el propio documento, o definido como DTD externo. <br>
     * En caso de ser DTD externo y localizado en disco, éste debe ser
     * accesible.
     *
     * @param  entrada un flujo que contiene un documento XML
     * @return         si el documento especificado es válido según
     *                 la sintaxis XML y el DTD especificado en el documento.
     */
    public static boolean esValido(InputStream entrada) {
        boolean resultado;
        
        try {
            //Analizamos con validación
            analizar(entrada, true);
            resultado = true;
        } catch (SAXException se) {
            resultado = false;
        }
        
        return resultado;
    }
    
}