// external validation with a DTD // it is a hack // - create a stream with the original document but inserting a DOCTYPE processing instruction // - validate this stream // - source and validation are put in separate threads // Adapted from http://xmlfr.org/documentations/faq/040720-0001#N410 // by HervŽ AGNOUX, de la SARL diaam informatique (hence some French variable names) // (http://www.diaam-informatique.com/). // mardi 20 juillet 2004 import java.io.File; import java.io.FileInputStream; import java.io.FileReader; import java.io.FilterOutputStream; import java.io.InputStream; import java.io.PipedOutputStream; import java.io.PipedInputStream; import java.io.PrintStream; import javax.xml.parsers.SAXParserFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.parsers.SAXParser; import javax.xml.transform.OutputKeys; import javax.xml.transform.Result; import javax.xml.transform.Transformer; import javax.xml.transform.TransformerFactory; import javax.xml.transform.Source; import javax.xml.transform.sax.SAXSource; import javax.xml.transform.stream.StreamResult; import javax.xml.transform.stream.StreamSource; import org.xml.sax.helpers.DefaultHandler; import org.xml.sax.InputSource; import org.xml.sax.SAXParseException; import org.xml.sax.SAXException; public class ValidateDTD { public static void main(String[] argv) throws Exception{ File XMLFile; PipedOutputStream writePipe; PipedInputStream readPipe; FilterOutputStream DTDstream; StreamResult DTDresultStream; InputSource DTDinput; Thread aDTDThread; Thread aValidateThread; Runnable runDTD; Runnable runValidate; if(argv.length==0 || argv.length>2){ System.out.println("usage: ValidateExternalDTD DTDfile [XMLfile]"); return; } // create pipe between the task that adds the DTD and the validating task writePipe = new PipedOutputStream(); readPipe = new PipedInputStream(writePipe); DTDstream = new PrintStream(writePipe); DTDresultStream = new StreamResult(DTDstream); DTDinput = new InputSource(readPipe); if(argv.length==2){ XMLFile = new File(argv[1]); XMLFile = XMLFile.getCanonicalFile(); DTDinput.setSystemId(XMLFile.getParentFile().toURL().toString()); } // launch the tasks runDTD = new DTDThread(argv[0],argv.length==2?argv[1]:null, DTDresultStream); runValidate = new ValidateThread(DTDinput); aDTDThread = new Thread(runDTD); aValidateThread = new Thread(runValidate); aDTDThread.start(); aValidateThread.start(); } //Thread to launch the DTD. private static class DTDThread implements java.lang.Runnable{ private Transformer m_transfo; private Source m_source; private Result m_resultat; DTDThread (String DTDfileName, String XMLfileName, Result resultat) throws Exception { TransformerFactory fabrique; InputStream XMLFile = XMLfileName==null ? System.in : new FileInputStream(XMLfileName); fabrique = TransformerFactory.newInstance(); m_transfo = fabrique.newTransformer(); // here is the hack m_transfo.setOutputProperty(OutputKeys.DOCTYPE_SYSTEM, DTDfileName); // m_source = new StreamSource(XMLFile); m_resultat = resultat; } public void run(){ try{ m_transfo.transform(m_source, m_resultat); ((StreamResult)m_resultat).getOutputStream().close(); }catch (Exception e){ System.out.println("Error in DTDThread"+e.getMessage()); System.exit(1); } } } // Validation thread private static class ValidateThread implements java.lang.Runnable{ private SAXParser m_pilote; private InputSource m_fluxLecture; ValidateThread(InputSource fluxAValider) throws Exception{ SAXParserFactory fabriquePilotes; SAXParser piloteValidant; fabriquePilotes = SAXParserFactory.newInstance(); fabriquePilotes.setValidating(true); m_pilote = fabriquePilotes.newSAXParser(); m_fluxLecture = fluxAValider; } public void run(){ try{ m_pilote.parse(m_fluxLecture, new PrintErrors()); System.out.println("End of parse"); } catch (Exception e){ System.out.println("Error in ValidateThread"+e.getMessage()); System.exit(1); } } private class PrintErrors extends org.xml.sax.helpers.DefaultHandler{ public void error(SAXParseException e) throws SAXException{ System.err.println("-- INVALID DOCUMENT -- PublicId : "+e.getPublicId()+" SystemId : "+e.getSystemId()); System.err.println(e.getMessage()); System.err.println(" line,column : "+e.getLineNumber()+":"+e.getColumnNumber()); } } } }