You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

DocumentReader.java 17KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520
  1. /*
  2. * Copyright (C) 2001 The Apache Software Foundation. All rights reserved.
  3. * For details on use and redistribution please refer to the
  4. * LICENSE file included with these sources."
  5. */
  6. package org.apache.fop.tools;
  7. import java.io.IOException;
  8. //import java.util.*;
  9. // DOM
  10. import org.w3c.dom.*;
  11. // SAX
  12. import org.xml.sax.*;
  13. import org.xml.sax.helpers.AttributesImpl;
  14. /**
  15. * This presents a DOM as an XMLReader to make it easy to use a Document
  16. * with a SAX-based implementation.
  17. *
  18. * @author Kelly A Campbell
  19. *
  20. */
  21. public class DocumentReader implements XMLReader
  22. {
  23. ////////////////////////////////////////////////////////////////////
  24. // Configuration.
  25. ////////////////////////////////////////////////////////////////////
  26. private boolean _namespaces = true;
  27. private boolean _namespace_prefixes = true;
  28. /**
  29. * Look up the value of a feature.
  30. *
  31. * <p>The feature name is any fully-qualified URI. It is
  32. * possible for an XMLReader to recognize a feature name but
  33. * to be unable to return its value; this is especially true
  34. * in the case of an adapter for a SAX1 Parser, which has
  35. * no way of knowing whether the underlying parser is
  36. * performing validation or expanding external entities.</p>
  37. *
  38. * <p>All XMLReaders are required to recognize the
  39. * http://xml.org/sax/features/namespaces and the
  40. * http://xml.org/sax/features/namespace-prefixes feature names.</p>
  41. *
  42. * <p>Some feature values may be available only in specific
  43. * contexts, such as before, during, or after a parse.</p>
  44. *
  45. * <p>Typical usage is something like this:</p>
  46. *
  47. * <pre>
  48. * XMLReader r = new MySAXDriver();
  49. *
  50. * // try to activate validation
  51. * try {
  52. * r.setFeature("http://xml.org/sax/features/validation", true);
  53. * } catch (SAXException e) {
  54. * System.err.println("Cannot activate validation.");
  55. * }
  56. *
  57. * // register event handlers
  58. * r.setContentHandler(new MyContentHandler());
  59. * r.setErrorHandler(new MyErrorHandler());
  60. *
  61. * // parse the first document
  62. * try {
  63. * r.parse("http://www.foo.com/mydoc.xml");
  64. * } catch (IOException e) {
  65. * System.err.println("I/O exception reading XML document");
  66. * } catch (SAXException e) {
  67. * System.err.println("XML exception reading document.");
  68. * }
  69. * </pre>
  70. *
  71. * <p>Implementors are free (and encouraged) to invent their own features,
  72. * using names built on their own URIs.</p>
  73. *
  74. * @param name The feature name, which is a fully-qualified URI.
  75. * @return The current state of the feature (true or false).
  76. * @exception org.xml.sax.SAXNotRecognizedException When the
  77. * XMLReader does not recognize the feature name.
  78. * @exception org.xml.sax.SAXNotSupportedException When the
  79. * XMLReader recognizes the feature name but
  80. * cannot determine its value at this time.
  81. * @see #setFeature
  82. */
  83. public boolean getFeature (String name)
  84. throws SAXNotRecognizedException, SAXNotSupportedException
  85. {
  86. if ("http://xml.org/sax/features/namespaces".equals(name)) {
  87. return _namespaces;
  88. }
  89. else if ("http://xml.org/sax/features/namespace-prefixes".equals(name)) {
  90. return _namespace_prefixes;
  91. }
  92. else {
  93. throw new SAXNotRecognizedException("Feature '"+name+"' not recognized or supported by Document2SAXAdapter");
  94. }
  95. }
  96. /**
  97. * Set the state of a feature.
  98. *
  99. * <p>The feature name is any fully-qualified URI. It is
  100. * possible for an XMLReader to recognize a feature name but
  101. * to be unable to set its value; this is especially true
  102. * in the case of an adapter for a SAX1 {@link org.xml.sax.Parser Parser},
  103. * which has no way of affecting whether the underlying parser is
  104. * validating, for example.</p>
  105. *
  106. * <p>All XMLReaders are required to support setting
  107. * http://xml.org/sax/features/namespaces to true and
  108. * http://xml.org/sax/features/namespace-prefixes to false.</p>
  109. *
  110. * <p>Some feature values may be immutable or mutable only
  111. * in specific contexts, such as before, during, or after
  112. * a parse.</p>
  113. *
  114. * @param name The feature name, which is a fully-qualified URI.
  115. * @param state The requested state of the feature (true or false).
  116. * @exception org.xml.sax.SAXNotRecognizedException When the
  117. * XMLReader does not recognize the feature name.
  118. * @exception org.xml.sax.SAXNotSupportedException When the
  119. * XMLReader recognizes the feature name but
  120. * cannot set the requested value.
  121. * @see #getFeature
  122. */
  123. public void setFeature (String name, boolean value)
  124. throws SAXNotRecognizedException, SAXNotSupportedException
  125. {
  126. if ("http://xml.org/sax/features/namespaces".equals(name)) {
  127. _namespaces = value;
  128. }
  129. else if ("http://xml.org/sax/features/namespace-prefixes".equals(name)) {
  130. _namespace_prefixes = value;
  131. }
  132. else {
  133. throw new SAXNotRecognizedException("Feature '"+name+"' not recognized or supported by Document2SAXAdapter");
  134. }
  135. }
  136. /**
  137. * Look up the value of a property.
  138. *
  139. * <p>The property name is any fully-qualified URI. It is
  140. * possible for an XMLReader to recognize a property name but
  141. * to be unable to return its state; this is especially true
  142. * in the case of an adapter for a SAX1 {@link org.xml.sax.Parser
  143. * Parser}.</p>
  144. *
  145. * <p>XMLReaders are not required to recognize any specific
  146. * property names, though an initial core set is documented for
  147. * SAX2.</p>
  148. *
  149. * <p>Some property values may be available only in specific
  150. * contexts, such as before, during, or after a parse.</p>
  151. *
  152. * <p>Implementors are free (and encouraged) to invent their own properties,
  153. * using names built on their own URIs.</p>
  154. *
  155. * @param name The property name, which is a fully-qualified URI.
  156. * @return The current value of the property.
  157. * @exception org.xml.sax.SAXNotRecognizedException When the
  158. * XMLReader does not recognize the property name.
  159. * @exception org.xml.sax.SAXNotSupportedException When the
  160. * XMLReader recognizes the property name but
  161. * cannot determine its value at this time.
  162. * @see #setProperty
  163. */
  164. public Object getProperty (String name)
  165. throws SAXNotRecognizedException, SAXNotSupportedException
  166. {
  167. throw new SAXNotRecognizedException("Property '"+name+"' not recognized or supported by Document2SAXAdapter");
  168. }
  169. /**
  170. * Set the value of a property.
  171. *
  172. * <p>The property name is any fully-qualified URI. It is
  173. * possible for an XMLReader to recognize a property name but
  174. * to be unable to set its value; this is especially true
  175. * in the case of an adapter for a SAX1 {@link org.xml.sax.Parser
  176. * Parser}.</p>
  177. *
  178. * <p>XMLReaders are not required to recognize setting
  179. * any specific property names, though a core set is provided with
  180. * SAX2.</p>
  181. *
  182. * <p>Some property values may be immutable or mutable only
  183. * in specific contexts, such as before, during, or after
  184. * a parse.</p>
  185. *
  186. * <p>This method is also the standard mechanism for setting
  187. * extended handlers.</p>
  188. *
  189. * @param name The property name, which is a fully-qualified URI.
  190. * @param state The requested value for the property.
  191. * @exception org.xml.sax.SAXNotRecognizedException When the
  192. * XMLReader does not recognize the property name.
  193. * @exception org.xml.sax.SAXNotSupportedException When the
  194. * XMLReader recognizes the property name but
  195. * cannot set the requested value.
  196. */
  197. public void setProperty (String name, Object value)
  198. throws SAXNotRecognizedException, SAXNotSupportedException
  199. {
  200. throw new SAXNotRecognizedException("Property '"+name+"' not recognized or supported by Document2SAXAdapter");
  201. }
  202. ////////////////////////////////////////////////////////////////////
  203. // Event handlers.
  204. ////////////////////////////////////////////////////////////////////
  205. private EntityResolver _entityResolver = null;
  206. private DTDHandler _dtdHandler = null;
  207. private ContentHandler _contentHandler = null;
  208. private ErrorHandler _errorHandler = null;
  209. /**
  210. * Allow an application to register an entity resolver.
  211. *
  212. * <p>If the application does not register an entity resolver,
  213. * the XMLReader will perform its own default resolution.</p>
  214. *
  215. * <p>Applications may register a new or different resolver in the
  216. * middle of a parse, and the SAX parser must begin using the new
  217. * resolver immediately.</p>
  218. *
  219. * @param resolver The entity resolver.
  220. * @exception java.lang.NullPointerException If the resolver
  221. * argument is null.
  222. * @see #getEntityResolver
  223. */
  224. public void setEntityResolver (EntityResolver resolver)
  225. {
  226. _entityResolver = resolver;
  227. }
  228. /**
  229. * Return the current entity resolver.
  230. *
  231. * @return The current entity resolver, or null if none
  232. * has been registered.
  233. * @see #setEntityResolver
  234. */
  235. public EntityResolver getEntityResolver ()
  236. {
  237. return _entityResolver;
  238. }
  239. /**
  240. * Allow an application to register a DTD event handler.
  241. *
  242. * <p>If the application does not register a DTD handler, all DTD
  243. * events reported by the SAX parser will be silently ignored.</p>
  244. *
  245. * <p>Applications may register a new or different handler in the
  246. * middle of a parse, and the SAX parser must begin using the new
  247. * handler immediately.</p>
  248. *
  249. * @param handler The DTD handler.
  250. * @exception java.lang.NullPointerException If the handler
  251. * argument is null.
  252. * @see #getDTDHandler
  253. */
  254. public void setDTDHandler (DTDHandler handler)
  255. {
  256. _dtdHandler = handler;
  257. }
  258. /**
  259. * Return the current DTD handler.
  260. *
  261. * @return The current DTD handler, or null if none
  262. * has been registered.
  263. * @see #setDTDHandler
  264. */
  265. public DTDHandler getDTDHandler ()
  266. {
  267. return _dtdHandler;
  268. }
  269. /**
  270. * Allow an application to register a content event handler.
  271. *
  272. * <p>If the application does not register a content handler, all
  273. * content events reported by the SAX parser will be silently
  274. * ignored.</p>
  275. *
  276. * <p>Applications may register a new or different handler in the
  277. * middle of a parse, and the SAX parser must begin using the new
  278. * handler immediately.</p>
  279. *
  280. * @param handler The content handler.
  281. * @exception java.lang.NullPointerException If the handler
  282. * argument is null.
  283. * @see #getContentHandler
  284. */
  285. public void setContentHandler (ContentHandler handler)
  286. {
  287. _contentHandler = handler;
  288. }
  289. /**
  290. * Return the current content handler.
  291. *
  292. * @return The current content handler, or null if none
  293. * has been registered.
  294. * @see #setContentHandler
  295. */
  296. public ContentHandler getContentHandler ()
  297. {
  298. return _contentHandler;
  299. }
  300. /**
  301. * Allow an application to register an error event handler.
  302. *
  303. * <p>If the application does not register an error handler, all
  304. * error events reported by the SAX parser will be silently
  305. * ignored; however, normal processing may not continue. It is
  306. * highly recommended that all SAX applications implement an
  307. * error handler to avoid unexpected bugs.</p>
  308. *
  309. * <p>Applications may register a new or different handler in the
  310. * middle of a parse, and the SAX parser must begin using the new
  311. * handler immediately.</p>
  312. *
  313. * @param handler The error handler.
  314. * @exception java.lang.NullPointerException If the handler
  315. * argument is null.
  316. * @see #getErrorHandler
  317. */
  318. public void setErrorHandler (ErrorHandler handler)
  319. {
  320. _errorHandler = handler;
  321. }
  322. /**
  323. * Return the current error handler.
  324. *
  325. * @return The current error handler, or null if none
  326. * has been registered.
  327. * @see #setErrorHandler
  328. */
  329. public ErrorHandler getErrorHandler ()
  330. {
  331. return _errorHandler;
  332. }
  333. ////////////////////////////////////////////////////////////////////
  334. // Parsing.
  335. ////////////////////////////////////////////////////////////////////
  336. /**
  337. * Parse an XML DOM document.
  338. *
  339. *
  340. *
  341. * @param source The input source for the top-level of the
  342. * XML document.
  343. * @exception org.xml.sax.SAXException Any SAX exception, possibly
  344. * wrapping another exception.
  345. * @exception java.io.IOException An IO exception from the parser,
  346. * possibly from a byte stream or character stream
  347. * supplied by the application.
  348. * @see org.xml.sax.InputSource
  349. * @see #parse(java.lang.String)
  350. * @see #setEntityResolver
  351. * @see #setDTDHandler
  352. * @see #setContentHandler
  353. * @see #setErrorHandler
  354. */
  355. public void parse (InputSource input)
  356. throws IOException, SAXException
  357. {
  358. if (input instanceof DocumentInputSource) {
  359. Document document = ((DocumentInputSource)input).getDocument();
  360. if (_contentHandler == null) {
  361. throw new SAXException("ContentHandler is null. Please use setContentHandler()");
  362. }
  363. // refactored from org.apache.fop.apps.Driver
  364. /* most of this code is modified from John Cowan's */
  365. Node currentNode;
  366. AttributesImpl currentAtts;
  367. /* temporary array for making Strings into character arrays */
  368. char[] array = null;
  369. currentAtts = new AttributesImpl();
  370. /* start at the document element */
  371. currentNode = document;
  372. while (currentNode != null) {
  373. switch (currentNode.getNodeType()) {
  374. case Node.DOCUMENT_NODE:
  375. _contentHandler.startDocument();
  376. break;
  377. case Node.CDATA_SECTION_NODE:
  378. case Node.TEXT_NODE:
  379. String data = currentNode.getNodeValue();
  380. int datalen = data.length();
  381. if (array == null || array.length < datalen) {
  382. /* if the array isn't big enough, make a new
  383. one */
  384. array = new char[datalen];
  385. }
  386. data.getChars(0, datalen, array, 0);
  387. _contentHandler.characters(array, 0, datalen);
  388. break;
  389. case Node.PROCESSING_INSTRUCTION_NODE:
  390. _contentHandler.processingInstruction(currentNode.getNodeName(),
  391. currentNode.getNodeValue());
  392. break;
  393. case Node.ELEMENT_NODE:
  394. NamedNodeMap map = currentNode.getAttributes();
  395. currentAtts.clear();
  396. for (int i = map.getLength() - 1; i >= 0; i--) {
  397. Attr att = (Attr) map.item(i);
  398. currentAtts.addAttribute( att.getNamespaceURI(),
  399. att.getLocalName(), att.getName(),
  400. "CDATA", att.getValue());
  401. }
  402. _contentHandler.startElement(currentNode.getNamespaceURI(),
  403. currentNode.getLocalName(),
  404. currentNode.getNodeName(),
  405. currentAtts);
  406. break;
  407. }
  408. Node nextNode = currentNode.getFirstChild();
  409. if (nextNode != null) {
  410. currentNode = nextNode;
  411. continue;
  412. }
  413. while (currentNode != null) {
  414. switch (currentNode.getNodeType()) {
  415. case Node.DOCUMENT_NODE:
  416. _contentHandler.endDocument();
  417. break;
  418. case Node.ELEMENT_NODE:
  419. _contentHandler.endElement(currentNode.getNamespaceURI(),
  420. currentNode.getLocalName(),
  421. currentNode.getNodeName());
  422. break;
  423. }
  424. nextNode = currentNode.getNextSibling();
  425. if (nextNode != null) {
  426. currentNode = nextNode;
  427. break;
  428. }
  429. currentNode = currentNode.getParentNode();
  430. }
  431. }
  432. }
  433. else {
  434. throw new SAXException("DocumentReader only supports parsing of a DocumentInputSource");
  435. }
  436. }
  437. /**
  438. * DocumentReader requires a DocumentInputSource, so this is not
  439. * implements and simply throws a SAXException. Use parse(DocumentInputSource)
  440. * instead
  441. *
  442. * @param systemId The system identifier (URI).
  443. * @exception org.xml.sax.SAXException Any SAX exception, possibly
  444. * wrapping another exception.
  445. * @exception java.io.IOException An IO exception from the parser,
  446. * possibly from a byte stream or character stream
  447. * supplied by the application.
  448. * @see #parse(org.xml.sax.InputSource)
  449. */
  450. public void parse (String systemId)
  451. throws IOException, SAXException
  452. {
  453. throw new SAXException("DocumentReader only supports parsing of a DocumentInputSource");
  454. }
  455. }