/** * */ package net.sourceforge.dita4publishers.util; import java.io.File; import java.util.ArrayList; import java.util.List; import java.util.StringTokenizer; import net.sourceforge.dita4publishers.util.xml.XmlFormatSaxErrorHandlingXMLFilter; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import org.apache.xerces.util.XMLCatalogResolver; import org.w3c.dom.Document; import org.xml.sax.EntityResolver; import org.xml.sax.InputSource; import org.xml.sax.XMLReader; import org.xml.sax.helpers.XMLReaderFactory; /** * Utilities for doing SAX parsing and validation. */ public class SaxUtil { private static final Log log = LogFactory.getLog(SaxUtil.class); /** * Get an XML Reader that uses the default catalogs as defined by various environment variables. * @param log * @param logDoc * @param validate * @return Logging XML reader * @throws Exception */ public static XMLReader getXMLFormatLoggingXMLReader(Log log, Document logDoc, boolean validate) throws Exception { return getXMLFormatLoggingXMLReader(log, logDoc, validate, getCatalogs()); } public static XMLReader getXMLFormatLoggingXMLReader(Log log, Document logDoc, boolean validate, String[] catalogs) throws Exception { log.debug("SAX Parser factory class=" + System.getProperty("javax.xml.parsers.SAXParserFactory")); XMLReader baseReader = null;; try { baseReader = XMLReaderFactory.createXMLReader(); } catch (Exception e) { throw new Exception("Exception constructing new SAX parser: " + e.getMessage(), e); } XMLReader reader = new XmlFormatSaxErrorHandlingXMLFilter(baseReader, log, logDoc); try { reader.setFeature("http://xml.org/sax/features/validation", validate); reader.setFeature("http://apache.org/xml/features/nonvalidating/load-external-dtd", validate); reader.setEntityResolver(getCatalogResolver(catalogs)); } catch (Exception e) { String msg = "Failed to set features on XMLReader instance: " + e.getMessage(); log.error(msg); throw new Exception(msg, e); } return reader; } /** * Validates an XML document and returns the DOM containing the parsing result as a * set of <message> elements. * @param input * @return * @throws Exception */ public static Document validateDocument(InputSource input) throws Exception { Document logDoc = null; XMLReader reader = getXMLFormatLoggingXMLReader(log, logDoc, true); reader.parse(input); return logDoc; } /** * Validates an XML document and returns the DOM containing the parsing result as a * set of <message> elements. * @param input * @return * @throws Exception */ public static Document validateDocument(InputSource input, String[] catalogs) throws Exception { Document logDoc = null; XMLReader reader = getXMLFormatLoggingXMLReader(log, logDoc, true, catalogs); reader.parse(input); return logDoc; } public static EntityResolver getCatalogResolver(String[] catalogs) { XMLCatalogResolver resolver = new XMLCatalogResolver(); resolver.setCatalogList(catalogs); return resolver; } /** * Tries to find the relevant entity resolution catalogs. */ protected static String[] getCatalogs() { List<String> catalogs = new ArrayList<String>(); String catalogList = System.getProperty("xml.catalog.files"); if (catalogList != null && !"".equals(catalogList)) { StringTokenizer tokens = new StringTokenizer(catalogList, ";"); if (tokens.hasMoreTokens()) { while (tokens.hasMoreTokens()) { catalogs.add(tokens.nextToken()); } } } String toolkitCatalogUri = getDitaOpenToolkitCatalog(); if (toolkitCatalogUri != null) { catalogs.add(toolkitCatalogUri); } String[] array = new String[catalogs.size()]; catalogs.toArray(array); return array; } /** * @return */ private static String getDitaOpenToolkitCatalog() { File catalogFile = null; String ditaHome = System.getenv("DITA_HOME"); if (ditaHome != null && !"".equals(ditaHome.trim())) { File ditaDir = new File(ditaHome); catalogFile = new File(ditaDir, "catalog-dita.xml"); } else { System.err.println("DITA_HOME environment variable not set. Cannot find DITA Open Toolkit catalog-dita.xml file"); } if (catalogFile != null) { try { checkExistsAndCanRead(catalogFile); } catch (Exception e) { System.err.println("Catalog file \"" + catalogFile.getAbsolutePath() + "\" does not exist or cannot be read."); System.exit(1); } return catalogFile.getAbsolutePath(); } return null; } /** * @param file */ private static void checkExistsAndCanRead(File file) { if (!file.exists()) { throw new RuntimeException("File " + file.getAbsolutePath() + " does not exist."); } if (!file.canRead()) { throw new RuntimeException("File " + file.getAbsolutePath() + " exists but cannot be read."); } } }