1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.apache.commons.jxpath.xml;
17
18 import java.io.InputStream;
19 import java.net.URL;
20 import java.util.HashMap;
21
22 import org.apache.commons.jxpath.Container;
23 import org.apache.commons.jxpath.JXPathException;
24
25 /***
26 * An XML document container reads and parses XML only when it is
27 * accessed. JXPath traverses Containers transparently -
28 * you use the same paths to access objects in containers as you
29 * do to access those objects directly. You can create
30 * XMLDocumentContainers for various XML documents that may or
31 * may not be accessed by XPaths. If they are, they will be automatically
32 * read, parsed and traversed. If they are not - they won't be
33 * read at all.
34 *
35 * @author Dmitri Plotnikov
36 * @version $Revision: 1.9 $ $Date: 2004/02/29 14:17:37 $
37 */
38 public class DocumentContainer extends XMLParser2 implements Container {
39
40 public static final String MODEL_DOM = "DOM";
41 public static final String MODEL_JDOM = "JDOM";
42
43 private Object document;
44 private URL xmlURL;
45 private String model;
46
47 private static HashMap parserClasses = new HashMap();
48 static {
49 parserClasses.put(MODEL_DOM,
50 "org.apache.commons.jxpath.xml.DOMParser");
51 parserClasses.put(MODEL_JDOM,
52 "org.apache.commons.jxpath.xml.JDOMParser");
53 }
54
55 private static HashMap parsers = new HashMap();
56
57 /***
58 * Add an XML parser. Parsers for the models "DOM" and "JDOM" are
59 * pre-registered.
60 */
61 public static void registerXMLParser(String model, XMLParser parser) {
62 parsers.put(model, parser);
63 }
64
65 /***
66 * Add a class of a custom XML parser.
67 * Parsers for the models "DOM" and "JDOM" are pre-registered.
68 */
69 public static void registerXMLParser(String model, String parserClassName) {
70 parserClasses.put(model, parserClassName);
71 }
72
73 /***
74 * Use this constructor if the desired model is DOM.
75 *
76 * @param URL is a URL for an XML file.
77 * Use getClass().getResource(resourceName) to load XML from a
78 * resource file.
79 */
80 public DocumentContainer(URL xmlURL) {
81 this(xmlURL, MODEL_DOM);
82 }
83
84 /***
85 * @param URL is a URL for an XML file. Use getClass().getResource
86 * (resourceName) to load XML from a resource file.
87 *
88 * @param model is one of the MODEL_* constants defined in this class. It
89 * determines which parser should be used to load the XML.
90 */
91 public DocumentContainer(URL xmlURL, String model) {
92 this.xmlURL = xmlURL;
93 if (xmlURL == null) {
94 throw new JXPathException("XML URL is null");
95 }
96 this.model = model;
97 }
98
99 /***
100 * Reads XML, caches it internally and returns the Document.
101 */
102 public Object getValue() {
103 if (document == null) {
104 try {
105 InputStream stream = null;
106 try {
107 if (xmlURL != null) {
108 stream = xmlURL.openStream();
109 }
110 document = parseXML(stream);
111 }
112 finally {
113 if (stream != null) {
114 stream.close();
115 }
116 }
117 }
118 catch (Exception ex) {
119 throw new JXPathException(
120 "Cannot read XML from: " + xmlURL.toString(),
121 ex);
122 }
123 }
124 return document;
125 }
126
127 /***
128 * Parses XML using the parser for the specified model.
129 */
130 public Object parseXML(InputStream stream) {
131 XMLParser parser = getParser(model);
132 if (parser instanceof XMLParser2) {
133 XMLParser2 parser2 = (XMLParser2) parser;
134 parser2.setValidating(isValidating());
135 parser2.setNamespaceAware(isNamespaceAware());
136 parser2.setIgnoringElementContentWhitespace(
137 isIgnoringElementContentWhitespace());
138 parser2.setExpandEntityReferences(isExpandEntityReferences());
139 parser2.setIgnoringComments(isIgnoringComments());
140 parser2.setCoalescing(isCoalescing());
141 }
142 return parser.parseXML(stream);
143 }
144
145 /***
146 * Throws an UnsupportedOperationException
147 */
148 public void setValue(Object value) {
149 throw new UnsupportedOperationException();
150 }
151
152 /***
153 * Maps a model type to a parser.
154 */
155 private static final XMLParser getParser(String model) {
156 XMLParser parser = (XMLParser) parsers.get(model);
157 if (parser == null) {
158 String className = (String) parserClasses.get(model);
159 if (className == null) {
160 throw new JXPathException("Unsupported XML model: " + model);
161 }
162 try {
163 Class clazz = Class.forName(className);
164 parser = (XMLParser) clazz.newInstance();
165 }
166 catch (Exception ex) {
167 throw new JXPathException(
168 "Cannot allocate XMLParser: " + className);
169 }
170 parsers.put(model, parser);
171 }
172 return parser;
173 }
174 }