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