/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.commons.jxpath.xml; import java.io.IOException; import java.io.InputStream; import java.net.URL; import java.util.HashMap; import org.apache.commons.jxpath.Container; import org.apache.commons.jxpath.JXPathException; /** * An XML document container reads and parses XML only when it is * accessed. JXPath traverses Containers transparently - * you use the same paths to access objects in containers as you * do to access those objects directly. You can create * XMLDocumentContainers for various XML documents that may or * may not be accessed by XPaths. If they are, they will be automatically * read, parsed and traversed. If they are not - they won't be * read at all. * * @author Dmitri Plotnikov * @version $Revision: 668329 $ $Date: 2008-06-16 16:59:48 -0500 (Mon, 16 Jun 2008) $ */ public class DocumentContainer extends XMLParser2 implements Container { /** DOM constant */ public static final String MODEL_DOM = "DOM"; /** JDOM constant */ public static final String MODEL_JDOM = "JDOM"; private static final long serialVersionUID = -8713290334113427066L; private static HashMap parserClasses = new HashMap(); static { parserClasses.put(MODEL_DOM, "org.apache.commons.jxpath.xml.DOMParser"); parserClasses.put(MODEL_JDOM, "org.apache.commons.jxpath.xml.JDOMParser"); } private static HashMap parsers = new HashMap(); private Object document; private URL xmlURL; private String model; /** * Add an XML parser. Parsers for the models "DOM" and "JDOM" are * pre-registered. * @param model model name * @param parser parser */ public static void registerXMLParser(String model, XMLParser parser) { parsers.put(model, parser); } /** * Add a class of a custom XML parser. * Parsers for the models "DOM" and "JDOM" are pre-registered. * @param model model name * @param parserClassName parser classname */ public static void registerXMLParser(String model, String parserClassName) { parserClasses.put(model, parserClassName); } /** * Use this constructor if the desired model is DOM. * * @param xmlURL is a URL for an XML file. * Use getClass().getResource(resourceName) to load XML from a * resource file. */ public DocumentContainer(URL xmlURL) { this(xmlURL, MODEL_DOM); } /** * Construct a new DocumentContainer. * @param xmlURL is a URL for an XML file. Use getClass().getResource * (resourceName) to load XML from a resource file. * * @param model is one of the MODEL_* constants defined in this class. It * determines which parser should be used to load the XML. */ public DocumentContainer(URL xmlURL, String model) { this.xmlURL = xmlURL; if (xmlURL == null) { throw new JXPathException("XML URL is null"); } this.model = model; } /** * Reads XML, caches it internally and returns the Document. * @return Object */ public Object getValue() { if (document == null) { try { InputStream stream = null; try { if (xmlURL != null) { stream = xmlURL.openStream(); } document = parseXML(stream); } finally { if (stream != null) { stream.close(); } } } catch (IOException ex) { throw new JXPathException( "Cannot read XML from: " + xmlURL.toString(), ex); } } return document; } /** * Parses XML using the parser for the specified model. * @param stream InputStream * @return Object */ public Object parseXML(InputStream stream) { XMLParser parser = getParser(model); if (parser instanceof XMLParser2) { XMLParser2 parser2 = (XMLParser2) parser; parser2.setValidating(isValidating()); parser2.setNamespaceAware(isNamespaceAware()); parser2.setIgnoringElementContentWhitespace( isIgnoringElementContentWhitespace()); parser2.setExpandEntityReferences(isExpandEntityReferences()); parser2.setIgnoringComments(isIgnoringComments()); parser2.setCoalescing(isCoalescing()); } return parser.parseXML(stream); } /** * Throws an UnsupportedOperationException. * @param value value (not) to set */ public void setValue(Object value) { throw new UnsupportedOperationException(); } /** * Maps a model type to a parser. * @param model input model type * @return XMLParser */ private static XMLParser getParser(String model) { XMLParser parser = (XMLParser) parsers.get(model); if (parser == null) { String className = (String) parserClasses.get(model); if (className == null) { throw new JXPathException("Unsupported XML model: " + model); } try { Class clazz = Class.forName(className); parser = (XMLParser) clazz.newInstance(); } catch (Exception ex) { throw new JXPathException( "Cannot allocate XMLParser: " + className, ex); } parsers.put(model, parser); } return parser; } }