/* * Copyright 2007-2009 Sun Microsystems, Inc. All Rights Reserved. * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. * * This code is free software; you can redistribute it and/or modify it * under the terms of the GNU General Public License version 2 only, as * published by the Free Software Foundation. * * This code 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 * version 2 for more details (a copy is included in the LICENSE file that * accompanied this code). * * You should have received a copy of the GNU General Public License version * 2 along with this work; if not, write to the Free Software Foundation, * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. * * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara, * CA 95054 USA or visit www.sun.com if you need additional information or * have any questions. */ package org.visage.ant.docbook; import java.io.File; import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; import java.util.List; import javax.xml.parsers.*; import org.xml.sax.*; import org.xml.sax.helpers.DefaultHandler; /** * Extracts Visage and Java example source files from * DocBook sources. This allows a build to verify that they can be compiled * and possibly executed. * * @author Tom Ball */ public class DocBookTangle { public static void main(String[] args) { DocBookTangle dbt = new DocBookTangle(); boolean ok = dbt.run(args); if ( !ok ) { System.exit(1); } } static interface Log { void info(String msg); void verbose(String msg); void error(String msg, Exception e); void error(Exception e); } private File destDir = tmpDir; private Log log; private boolean quiet = false; private List<String> filenames = new ArrayList<String>(); public void setLog(Log log) { this.log = log; } public boolean run(String[] args) { if (log == null) { log = new Log() { public void error(String msg, Exception e) { System.err.println("ERROR: DocBookTangle: " + msg); if ( e != null ) { error(e); } } public void error(Exception e) { System.err.println("EXCEPTION: " + e.toString()); e.printStackTrace(); } public void info(String msg) { System.out.println(msg); } public void verbose(String msg) { if (!quiet) System.out.println(msg); } }; } boolean ok = parseOptions(args); if ( ok && filenames.isEmpty() ) { log.error("options parsed but no files to process", null); ok = false; } /* Need at least one file. */ if ( !ok ) { usage(log); } else { execute(); } return ok; } void execute() { destDir.mkdirs(); for (String path : filenames) { SAXParserFactory factory = SAXParserFactory.newInstance(); factory.setValidating(false); factory.setNamespaceAware(true); if (path.endsWith(".xml")) { File srcFile = new File(path); String baseName = srcFile.getName(); baseName = baseName.substring(0, baseName.lastIndexOf(".xml")); FileReader srcReader = null; try { XMLReader parser = factory.newSAXParser().getXMLReader(); DocBookXMLHandler handler = new DocBookXMLHandler(baseName); parser.setContentHandler(handler); parser.setErrorHandler(handler); srcReader = new FileReader(srcFile); InputSource is = new InputSource(srcReader); log.info("parsing " + srcFile.getPath()); parser.parse(is); } catch (ParserConfigurationException e) { log.error(e); } catch (IOException e) { log.error(e); } catch (SAXException e) { log.error(e); } finally { if (srcReader != null) try { srcReader.close(); } catch (IOException e) { log.error(e); } } } } } private boolean parseOptions(String[] args) { for (int i = 0; i < args.length; i++) { if (args[i].equals("-o")) { if (++i == args.length) { log.error("no output directory specified", null); return false; } destDir = new File(args[i]); } else filenames.add(args[i]); } return true; } private static void usage(Log log) { log.info("usage:"); log.info(" java DocBookTangle.java [-o output_directory] file.xml [file2.xml, etc.]"); } private class DocBookXMLHandler extends DefaultHandler { private String baseName; private StringBuilder text; private String language; private boolean inProgramListing; private int count; DocBookXMLHandler(String base) { super(); baseName = base; } @Override public void startDocument() throws SAXException { text = new StringBuilder(); inProgramListing = false; count = 0; } @Override public void startElement(String namespaceURI, String localName, String qName, Attributes attrs) throws SAXException { if (qName.equals("programlisting")) { String continuationType = attrs.getValue("continuation"); if ("continues".equals(continuationType)) { inProgramListing = true; } else if ("restarts".equals(continuationType)) { saveText(); inProgramListing = true; } else ; // ignore language = attrs.getValue("language"); } } @Override public void characters(char[] ch, int start, int length) throws SAXException { if (inProgramListing) text.append(ch, start, length); } @Override public void endElement(String namespaceURI, String localName, String qName) throws SAXException { inProgramListing = false; } @Override public void endDocument() { saveText(); } private void saveText() { if (text.length() > 0) { String name = baseName + '-' + ++count; name += "java".equals(language) ? ".java" : ".visage"; log.info("writing " + name); File destFile = new File(destDir, name); try { FileWriter out = new FileWriter(destFile); out.write(text.toString()); out.close(); } catch (IOException e) { log.error(e); } text = new StringBuilder(); } } @Override public void warning(SAXParseException e) throws SAXException { log.info("parser warning: " + e.getMessage()); } @Override public void error(SAXParseException e) throws SAXException { log.error("parser error: ", e); } @Override public void fatalError(SAXParseException e) throws SAXException { log.error("fatal parser error: ", e); } } private static File tmpDir; static { try { File tmpFile = File.createTempFile("xxx", ".tmp"); tmpDir = tmpFile.getParentFile(); } catch (IOException e) {} } }