001: /*
002: * Copyright 1999-2004 The Apache Software Foundation
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.apache.commons.jxpath.xml;
017:
018: import java.io.InputStream;
019: import java.net.URL;
020: import java.util.HashMap;
021:
022: import org.apache.commons.jxpath.Container;
023: import org.apache.commons.jxpath.JXPathException;
024:
025: /**
026: * An XML document container reads and parses XML only when it is
027: * accessed. JXPath traverses Containers transparently -
028: * you use the same paths to access objects in containers as you
029: * do to access those objects directly. You can create
030: * XMLDocumentContainers for various XML documents that may or
031: * may not be accessed by XPaths. If they are, they will be automatically
032: * read, parsed and traversed. If they are not - they won't be
033: * read at all.
034: *
035: * @author Dmitri Plotnikov
036: * @version $Revision: 1.9 $ $Date: 2004/02/29 14:17:37 $
037: */
038: public class DocumentContainer extends XMLParser2 implements Container {
039:
040: public static final String MODEL_DOM = "DOM";
041: public static final String MODEL_JDOM = "JDOM";
042:
043: private Object document;
044: private URL xmlURL;
045: private String model;
046:
047: private static HashMap parserClasses = new HashMap();
048: static {
049: parserClasses.put(MODEL_DOM,
050: "org.apache.commons.jxpath.xml.DOMParser");
051: parserClasses.put(MODEL_JDOM,
052: "org.apache.commons.jxpath.xml.JDOMParser");
053: }
054:
055: private static HashMap parsers = new HashMap();
056:
057: /**
058: * Add an XML parser. Parsers for the models "DOM" and "JDOM" are
059: * pre-registered.
060: */
061: public static void registerXMLParser(String model, XMLParser parser) {
062: parsers.put(model, parser);
063: }
064:
065: /**
066: * Add a class of a custom XML parser.
067: * Parsers for the models "DOM" and "JDOM" are pre-registered.
068: */
069: public static void registerXMLParser(String model,
070: String parserClassName) {
071: parserClasses.put(model, parserClassName);
072: }
073:
074: /**
075: * Use this constructor if the desired model is DOM.
076: *
077: * @param URL is a URL for an XML file.
078: * Use getClass().getResource(resourceName) to load XML from a
079: * resource file.
080: */
081: public DocumentContainer(URL xmlURL) {
082: this (xmlURL, MODEL_DOM);
083: }
084:
085: /**
086: * @param URL is a URL for an XML file. Use getClass().getResource
087: * (resourceName) to load XML from a resource file.
088: *
089: * @param model is one of the MODEL_* constants defined in this class. It
090: * determines which parser should be used to load the XML.
091: */
092: public DocumentContainer(URL xmlURL, String model) {
093: this .xmlURL = xmlURL;
094: if (xmlURL == null) {
095: throw new JXPathException("XML URL is null");
096: }
097: this .model = model;
098: }
099:
100: /**
101: * Reads XML, caches it internally and returns the Document.
102: */
103: public Object getValue() {
104: if (document == null) {
105: try {
106: InputStream stream = null;
107: try {
108: if (xmlURL != null) {
109: stream = xmlURL.openStream();
110: }
111: document = parseXML(stream);
112: } finally {
113: if (stream != null) {
114: stream.close();
115: }
116: }
117: } catch (Exception ex) {
118: throw new JXPathException("Cannot read XML from: "
119: + xmlURL.toString(), ex);
120: }
121: }
122: return document;
123: }
124:
125: /**
126: * Parses XML using the parser for the specified model.
127: */
128: public Object parseXML(InputStream stream) {
129: XMLParser parser = getParser(model);
130: if (parser instanceof XMLParser2) {
131: XMLParser2 parser2 = (XMLParser2) parser;
132: parser2.setValidating(isValidating());
133: parser2.setNamespaceAware(isNamespaceAware());
134: parser2
135: .setIgnoringElementContentWhitespace(isIgnoringElementContentWhitespace());
136: parser2
137: .setExpandEntityReferences(isExpandEntityReferences());
138: parser2.setIgnoringComments(isIgnoringComments());
139: parser2.setCoalescing(isCoalescing());
140: }
141: return parser.parseXML(stream);
142: }
143:
144: /**
145: * Throws an UnsupportedOperationException
146: */
147: public void setValue(Object value) {
148: throw new UnsupportedOperationException();
149: }
150:
151: /**
152: * Maps a model type to a parser.
153: */
154: private static final XMLParser getParser(String model) {
155: XMLParser parser = (XMLParser) parsers.get(model);
156: if (parser == null) {
157: String className = (String) parserClasses.get(model);
158: if (className == null) {
159: throw new JXPathException("Unsupported XML model: "
160: + model);
161: }
162: try {
163: Class clazz = Class.forName(className);
164: parser = (XMLParser) clazz.newInstance();
165: } catch (Exception ex) {
166: throw new JXPathException("Cannot allocate XMLParser: "
167: + className);
168: }
169: parsers.put(model, parser);
170: }
171: return parser;
172: }
173: }
|