1. // XMLReaderAdapter.java - adapt an SAX2 XMLReader to a SAX1 Parser
  2. // Written by David Megginson, sax@megginson.com
  3. // NO WARRANTY! This class is in the public domain.
  4. // $Id: XMLReaderAdapter.java,v 1.2 2001/08/01 06:43:19 tcng Exp $
  5. package org.xml.sax.helpers;
  6. import java.io.IOException;
  7. import java.util.Locale;
  8. import org.xml.sax.Parser; // deprecated
  9. import org.xml.sax.Locator;
  10. import org.xml.sax.InputSource;
  11. import org.xml.sax.AttributeList; // deprecated
  12. import org.xml.sax.EntityResolver;
  13. import org.xml.sax.DTDHandler;
  14. import org.xml.sax.DocumentHandler; // deprecated
  15. import org.xml.sax.ErrorHandler;
  16. import org.xml.sax.SAXException;
  17. import org.xml.sax.XMLReader;
  18. import org.xml.sax.Attributes;
  19. import org.xml.sax.ContentHandler;
  20. import org.xml.sax.SAXNotSupportedException;
  21. /**
  22. * Adapt a SAX2 XMLReader as a SAX1 Parser.
  23. *
  24. * <blockquote>
  25. * <em>This module, both source code and documentation, is in the
  26. * Public Domain, and comes with <strong>NO WARRANTY</strong>.</em>
  27. * </blockquote>
  28. *
  29. * <p>This class wraps a SAX2 {@link org.xml.sax.XMLReader XMLReader}
  30. * and makes it act as a SAX1 {@link org.xml.sax.Parser Parser}. The XMLReader
  31. * must support a true value for the
  32. * http://xml.org/sax/features/namespace-prefixes property or parsing will fail
  33. * with a {@link org.xml.sax.SAXException SAXException}; if the XMLReader
  34. * supports a false value for the http://xml.org/sax/features/namespaces
  35. * property, that will also be used to improve efficiency.</p>
  36. *
  37. * @since SAX 2.0
  38. * @author David Megginson,
  39. * <a href="mailto:sax@megginson.com">sax@megginson.com</a>
  40. * @version 2.0
  41. * @see org.xml.sax.Parser
  42. * @see org.xml.sax.XMLReader
  43. */
  44. public class XMLReaderAdapter implements Parser, ContentHandler
  45. {
  46. ////////////////////////////////////////////////////////////////////
  47. // Constructor.
  48. ////////////////////////////////////////////////////////////////////
  49. /**
  50. * Create a new adapter.
  51. *
  52. * <p>Use the "org.xml.sax.driver" property to locate the SAX2
  53. * driver to embed.</p>
  54. *
  55. * @exception org.xml.sax.SAXException If the embedded driver
  56. * cannot be instantiated or if the
  57. * org.xml.sax.driver property is not specified.
  58. */
  59. public XMLReaderAdapter ()
  60. throws SAXException
  61. {
  62. setup(XMLReaderFactory.createXMLReader());
  63. }
  64. /**
  65. * Create a new adapter.
  66. *
  67. * <p>Create a new adapter, wrapped around a SAX2 XMLReader.
  68. * The adapter will make the XMLReader act like a SAX1
  69. * Parser.</p>
  70. *
  71. * @param xmlReader The SAX2 XMLReader to wrap.
  72. * @exception java.lang.NullPointerException If the argument is null.
  73. */
  74. public XMLReaderAdapter (XMLReader xmlReader)
  75. {
  76. setup(xmlReader);
  77. }
  78. /**
  79. * Internal setup.
  80. *
  81. * @param xmlReader The embedded XMLReader.
  82. */
  83. private void setup (XMLReader xmlReader)
  84. {
  85. if (xmlReader == null) {
  86. throw new NullPointerException("XMLReader must not be null");
  87. }
  88. this.xmlReader = xmlReader;
  89. qAtts = new AttributesAdapter();
  90. }
  91. ////////////////////////////////////////////////////////////////////
  92. // Implementation of org.xml.sax.Parser.
  93. ////////////////////////////////////////////////////////////////////
  94. /**
  95. * Set the locale for error reporting.
  96. *
  97. * <p>This is not supported in SAX2, and will always throw
  98. * an exception.</p>
  99. *
  100. * @param The locale for error reporting.
  101. * @see org.xml.sax.Parser#setLocale
  102. */
  103. public void setLocale (Locale locale)
  104. throws SAXException
  105. {
  106. throw new SAXNotSupportedException("setLocale not supported");
  107. }
  108. /**
  109. * Register the entity resolver.
  110. *
  111. * @param resolver The new resolver.
  112. * @see org.xml.sax.Parser#setEntityResolver
  113. */
  114. public void setEntityResolver (EntityResolver resolver)
  115. {
  116. xmlReader.setEntityResolver(resolver);
  117. }
  118. /**
  119. * Register the DTD event handler.
  120. *
  121. * @param handler The new DTD event handler.
  122. * @see org.xml.sax.Parser#setDTDHandler
  123. */
  124. public void setDTDHandler (DTDHandler handler)
  125. {
  126. xmlReader.setDTDHandler(handler);
  127. }
  128. /**
  129. * Register the SAX1 document event handler.
  130. *
  131. * <p>Note that the SAX1 document handler has no Namespace
  132. * support.</p>
  133. *
  134. * @param handler The new SAX1 document event handler.
  135. * @see org.xml.sax.Parser#setDocumentHandler
  136. */
  137. public void setDocumentHandler (DocumentHandler handler)
  138. {
  139. documentHandler = handler;
  140. }
  141. /**
  142. * Register the error event handler.
  143. *
  144. * @param handler The new error event handler.
  145. * @see org.xml.sax.Parser#setErrorHandler
  146. */
  147. public void setErrorHandler (ErrorHandler handler)
  148. {
  149. xmlReader.setErrorHandler(handler);
  150. }
  151. /**
  152. * Parse the document.
  153. *
  154. * <p>This method will throw an exception if the embedded
  155. * XMLReader does not support the
  156. * http://xml.org/sax/features/namespace-prefixes property.</p>
  157. *
  158. * @param systemId The absolute URL of the document.
  159. * @exception java.io.IOException If there is a problem reading
  160. * the raw content of the document.
  161. * @exception org.xml.sax.SAXException If there is a problem
  162. * processing the document.
  163. * @see #parse(org.xml.sax.InputSource)
  164. * @see org.xml.sax.Parser#parse(java.lang.String)
  165. */
  166. public void parse (String systemId)
  167. throws IOException, SAXException
  168. {
  169. parse(new InputSource(systemId));
  170. }
  171. /**
  172. * Parse the document.
  173. *
  174. * <p>This method will throw an exception if the embedded
  175. * XMLReader does not support the
  176. * http://xml.org/sax/features/namespace-prefixes property.</p>
  177. *
  178. * @param input An input source for the document.
  179. * @exception java.io.IOException If there is a problem reading
  180. * the raw content of the document.
  181. * @exception org.xml.sax.SAXException If there is a problem
  182. * processing the document.
  183. * @see #parse(java.lang.String)
  184. * @see org.xml.sax.Parser#parse(org.xml.sax.InputSource)
  185. */
  186. public void parse (InputSource input)
  187. throws IOException, SAXException
  188. {
  189. setupXMLReader();
  190. xmlReader.parse(input);
  191. }
  192. /**
  193. * Set up the XML reader.
  194. */
  195. private void setupXMLReader ()
  196. throws SAXException
  197. {
  198. xmlReader.setFeature("http://xml.org/sax/features/namespace-prefixes", true);
  199. try {
  200. xmlReader.setFeature("http://xml.org/sax/features/namespaces",
  201. false);
  202. } catch (SAXException e) {
  203. // NO OP: it's just extra information, and we can ignore it
  204. }
  205. xmlReader.setContentHandler(this);
  206. }
  207. ////////////////////////////////////////////////////////////////////
  208. // Implementation of org.xml.sax.ContentHandler.
  209. ////////////////////////////////////////////////////////////////////
  210. /**
  211. * Set a document locator.
  212. *
  213. * @param locator The document locator.
  214. * @see org.xml.sax.ContentHandler#setDocumentLocator
  215. */
  216. public void setDocumentLocator (Locator locator)
  217. {
  218. documentHandler.setDocumentLocator(locator);
  219. }
  220. /**
  221. * Start document event.
  222. *
  223. * @exception org.xml.sax.SAXException The client may raise a
  224. * processing exception.
  225. * @see org.xml.sax.ContentHandler#startDocument
  226. */
  227. public void startDocument ()
  228. throws SAXException
  229. {
  230. documentHandler.startDocument();
  231. }
  232. /**
  233. * End document event.
  234. *
  235. * @exception org.xml.sax.SAXException The client may raise a
  236. * processing exception.
  237. * @see org.xml.sax.ContentHandler#endDocument
  238. */
  239. public void endDocument ()
  240. throws SAXException
  241. {
  242. documentHandler.endDocument();
  243. }
  244. /**
  245. * Adapt a SAX2 start prefix mapping event.
  246. *
  247. * @param prefix The prefix being mapped.
  248. * @param uri The Namespace URI being mapped to.
  249. * @see org.xml.sax.ContentHandler#startPrefixMapping
  250. */
  251. public void startPrefixMapping (String prefix, String uri)
  252. {
  253. }
  254. /**
  255. * Adapt a SAX2 end prefix mapping event.
  256. *
  257. * @param prefix The prefix being mapped.
  258. * @see org.xml.sax.ContentHandler#endPrefixMapping
  259. */
  260. public void endPrefixMapping (String prefix)
  261. {
  262. }
  263. /**
  264. * Adapt a SAX2 start element event.
  265. *
  266. * @param uri The Namespace URI.
  267. * @param localName The Namespace local name.
  268. * @param qName The qualified (prefixed) name.
  269. * @param atts The SAX2 attributes.
  270. * @exception org.xml.sax.SAXException The client may raise a
  271. * processing exception.
  272. * @see org.xml.sax.ContentHandler#endDocument
  273. */
  274. public void startElement (String uri, String localName,
  275. String qName, Attributes atts)
  276. throws SAXException
  277. {
  278. qAtts.setAttributes(atts);
  279. documentHandler.startElement(qName, qAtts);
  280. }
  281. /**
  282. * Adapt a SAX2 end element event.
  283. *
  284. * @param uri The Namespace URI.
  285. * @param localName The Namespace local name.
  286. * @param qName The qualified (prefixed) name.
  287. * @exception org.xml.sax.SAXException The client may raise a
  288. * processing exception.
  289. * @see org.xml.sax.ContentHandler#endElement
  290. */
  291. public void endElement (String uri, String localName,
  292. String qName)
  293. throws SAXException
  294. {
  295. documentHandler.endElement(qName);
  296. }
  297. /**
  298. * Adapt a SAX2 characters event.
  299. *
  300. * @param ch An array of characters.
  301. * @param start The starting position in the array.
  302. * @param length The number of characters to use.
  303. * @exception org.xml.sax.SAXException The client may raise a
  304. * processing exception.
  305. * @see org.xml.sax.ContentHandler#characters
  306. */
  307. public void characters (char ch[], int start, int length)
  308. throws SAXException
  309. {
  310. documentHandler.characters(ch, start, length);
  311. }
  312. /**
  313. * Adapt a SAX2 ignorable whitespace event.
  314. *
  315. * @param ch An array of characters.
  316. * @param start The starting position in the array.
  317. * @param length The number of characters to use.
  318. * @exception org.xml.sax.SAXException The client may raise a
  319. * processing exception.
  320. * @see org.xml.sax.ContentHandler#ignorableWhitespace
  321. */
  322. public void ignorableWhitespace (char ch[], int start, int length)
  323. throws SAXException
  324. {
  325. documentHandler.ignorableWhitespace(ch, start, length);
  326. }
  327. /**
  328. * Adapt a SAX2 processing instruction event.
  329. *
  330. * @param target The processing instruction target.
  331. * @param data The remainder of the processing instruction
  332. * @exception org.xml.sax.SAXException The client may raise a
  333. * processing exception.
  334. * @see org.xml.sax.ContentHandler#processingInstruction
  335. */
  336. public void processingInstruction (String target, String data)
  337. throws SAXException
  338. {
  339. documentHandler.processingInstruction(target, data);
  340. }
  341. /**
  342. * Adapt a SAX2 skipped entity event.
  343. *
  344. * @param name The name of the skipped entity.
  345. * @see org.xml.sax.ContentHandler#skippedEntity
  346. */
  347. public void skippedEntity (String name)
  348. throws SAXException
  349. {
  350. }
  351. ////////////////////////////////////////////////////////////////////
  352. // Internal state.
  353. ////////////////////////////////////////////////////////////////////
  354. XMLReader xmlReader;
  355. DocumentHandler documentHandler;
  356. AttributesAdapter qAtts;
  357. ////////////////////////////////////////////////////////////////////
  358. // Internal class.
  359. ////////////////////////////////////////////////////////////////////
  360. /**
  361. * Internal class to wrap a SAX2 Attributes object for SAX1.
  362. */
  363. final class AttributesAdapter implements AttributeList
  364. {
  365. AttributesAdapter ()
  366. {
  367. }
  368. /**
  369. * Set the embedded Attributes object.
  370. *
  371. * @param The embedded SAX2 Attributes.
  372. */
  373. void setAttributes (Attributes attributes)
  374. {
  375. this.attributes = attributes;
  376. }
  377. /**
  378. * Return the number of attributes.
  379. *
  380. * @return The length of the attribute list.
  381. * @see org.xml.sax.AttributeList#getLength
  382. */
  383. public int getLength ()
  384. {
  385. return attributes.getLength();
  386. }
  387. /**
  388. * Return the qualified (prefixed) name of an attribute by position.
  389. *
  390. * @return The qualified name.
  391. * @see org.xml.sax.AttributeList#getName
  392. */
  393. public String getName (int i)
  394. {
  395. return attributes.getQName(i);
  396. }
  397. /**
  398. * Return the type of an attribute by position.
  399. *
  400. * @return The type.
  401. * @see org.xml.sax.AttributeList#getType(int)
  402. */
  403. public String getType (int i)
  404. {
  405. return attributes.getType(i);
  406. }
  407. /**
  408. * Return the value of an attribute by position.
  409. *
  410. * @return The value.
  411. * @see org.xml.sax.AttributeList#getValue(int)
  412. */
  413. public String getValue (int i)
  414. {
  415. return attributes.getValue(i);
  416. }
  417. /**
  418. * Return the type of an attribute by qualified (prefixed) name.
  419. *
  420. * @return The type.
  421. * @see org.xml.sax.AttributeList#getType(java.lang.String)
  422. */
  423. public String getType (String qName)
  424. {
  425. return attributes.getType(qName);
  426. }
  427. /**
  428. * Return the value of an attribute by qualified (prefixed) name.
  429. *
  430. * @return The value.
  431. * @see org.xml.sax.AttributeList#getValue(java.lang.String)
  432. */
  433. public String getValue (String qName)
  434. {
  435. return attributes.getValue(qName);
  436. }
  437. private Attributes attributes;
  438. }
  439. }
  440. // end of XMLReaderAdapter.java