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.1 2001/05/20 03:12:58 curcuru 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.0r2pre
  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. if (documentHandler != null)
  219. documentHandler.setDocumentLocator(locator);
  220. }
  221. /**
  222. * Start document event.
  223. *
  224. * @exception org.xml.sax.SAXException The client may raise a
  225. * processing exception.
  226. * @see org.xml.sax.ContentHandler#startDocument
  227. */
  228. public void startDocument ()
  229. throws SAXException
  230. {
  231. if (documentHandler != null)
  232. documentHandler.startDocument();
  233. }
  234. /**
  235. * End document event.
  236. *
  237. * @exception org.xml.sax.SAXException The client may raise a
  238. * processing exception.
  239. * @see org.xml.sax.ContentHandler#endDocument
  240. */
  241. public void endDocument ()
  242. throws SAXException
  243. {
  244. if (documentHandler != null)
  245. documentHandler.endDocument();
  246. }
  247. /**
  248. * Adapt a SAX2 start prefix mapping event.
  249. *
  250. * @param prefix The prefix being mapped.
  251. * @param uri The Namespace URI being mapped to.
  252. * @see org.xml.sax.ContentHandler#startPrefixMapping
  253. */
  254. public void startPrefixMapping (String prefix, String uri)
  255. {
  256. }
  257. /**
  258. * Adapt a SAX2 end prefix mapping event.
  259. *
  260. * @param prefix The prefix being mapped.
  261. * @see org.xml.sax.ContentHandler#endPrefixMapping
  262. */
  263. public void endPrefixMapping (String prefix)
  264. {
  265. }
  266. /**
  267. * Adapt a SAX2 start element event.
  268. *
  269. * @param uri The Namespace URI.
  270. * @param localName The Namespace local name.
  271. * @param qName The qualified (prefixed) name.
  272. * @param atts The SAX2 attributes.
  273. * @exception org.xml.sax.SAXException The client may raise a
  274. * processing exception.
  275. * @see org.xml.sax.ContentHandler#endDocument
  276. */
  277. public void startElement (String uri, String localName,
  278. String qName, Attributes atts)
  279. throws SAXException
  280. {
  281. if (documentHandler != null) {
  282. qAtts.setAttributes(atts);
  283. documentHandler.startElement(qName, qAtts);
  284. }
  285. }
  286. /**
  287. * Adapt a SAX2 end element event.
  288. *
  289. * @param uri The Namespace URI.
  290. * @param localName The Namespace local name.
  291. * @param qName The qualified (prefixed) name.
  292. * @exception org.xml.sax.SAXException The client may raise a
  293. * processing exception.
  294. * @see org.xml.sax.ContentHandler#endElement
  295. */
  296. public void endElement (String uri, String localName,
  297. String qName)
  298. throws SAXException
  299. {
  300. if (documentHandler != null)
  301. documentHandler.endElement(qName);
  302. }
  303. /**
  304. * Adapt a SAX2 characters event.
  305. *
  306. * @param ch An array of characters.
  307. * @param start The starting position in the array.
  308. * @param length The number of characters to use.
  309. * @exception org.xml.sax.SAXException The client may raise a
  310. * processing exception.
  311. * @see org.xml.sax.ContentHandler#characters
  312. */
  313. public void characters (char ch[], int start, int length)
  314. throws SAXException
  315. {
  316. if (documentHandler != null)
  317. documentHandler.characters(ch, start, length);
  318. }
  319. /**
  320. * Adapt a SAX2 ignorable whitespace event.
  321. *
  322. * @param ch An array of characters.
  323. * @param start The starting position in the array.
  324. * @param length The number of characters to use.
  325. * @exception org.xml.sax.SAXException The client may raise a
  326. * processing exception.
  327. * @see org.xml.sax.ContentHandler#ignorableWhitespace
  328. */
  329. public void ignorableWhitespace (char ch[], int start, int length)
  330. throws SAXException
  331. {
  332. if (documentHandler != null)
  333. documentHandler.ignorableWhitespace(ch, start, length);
  334. }
  335. /**
  336. * Adapt a SAX2 processing instruction event.
  337. *
  338. * @param target The processing instruction target.
  339. * @param data The remainder of the processing instruction
  340. * @exception org.xml.sax.SAXException The client may raise a
  341. * processing exception.
  342. * @see org.xml.sax.ContentHandler#processingInstruction
  343. */
  344. public void processingInstruction (String target, String data)
  345. throws SAXException
  346. {
  347. if (documentHandler != null)
  348. documentHandler.processingInstruction(target, data);
  349. }
  350. /**
  351. * Adapt a SAX2 skipped entity event.
  352. *
  353. * @param name The name of the skipped entity.
  354. * @see org.xml.sax.ContentHandler#skippedEntity
  355. */
  356. public void skippedEntity (String name)
  357. throws SAXException
  358. {
  359. }
  360. ////////////////////////////////////////////////////////////////////
  361. // Internal state.
  362. ////////////////////////////////////////////////////////////////////
  363. XMLReader xmlReader;
  364. DocumentHandler documentHandler;
  365. AttributesAdapter qAtts;
  366. ////////////////////////////////////////////////////////////////////
  367. // Internal class.
  368. ////////////////////////////////////////////////////////////////////
  369. /**
  370. * Internal class to wrap a SAX2 Attributes object for SAX1.
  371. */
  372. final class AttributesAdapter implements AttributeList
  373. {
  374. AttributesAdapter ()
  375. {
  376. }
  377. /**
  378. * Set the embedded Attributes object.
  379. *
  380. * @param The embedded SAX2 Attributes.
  381. */
  382. void setAttributes (Attributes attributes)
  383. {
  384. this.attributes = attributes;
  385. }
  386. /**
  387. * Return the number of attributes.
  388. *
  389. * @return The length of the attribute list.
  390. * @see org.xml.sax.AttributeList#getLength
  391. */
  392. public int getLength ()
  393. {
  394. return attributes.getLength();
  395. }
  396. /**
  397. * Return the qualified (prefixed) name of an attribute by position.
  398. *
  399. * @return The qualified name.
  400. * @see org.xml.sax.AttributeList#getName
  401. */
  402. public String getName (int i)
  403. {
  404. return attributes.getQName(i);
  405. }
  406. /**
  407. * Return the type of an attribute by position.
  408. *
  409. * @return The type.
  410. * @see org.xml.sax.AttributeList#getType(int)
  411. */
  412. public String getType (int i)
  413. {
  414. return attributes.getType(i);
  415. }
  416. /**
  417. * Return the value of an attribute by position.
  418. *
  419. * @return The value.
  420. * @see org.xml.sax.AttributeList#getValue(int)
  421. */
  422. public String getValue (int i)
  423. {
  424. return attributes.getValue(i);
  425. }
  426. /**
  427. * Return the type of an attribute by qualified (prefixed) name.
  428. *
  429. * @return The type.
  430. * @see org.xml.sax.AttributeList#getType(java.lang.String)
  431. */
  432. public String getType (String qName)
  433. {
  434. return attributes.getType(qName);
  435. }
  436. /**
  437. * Return the value of an attribute by qualified (prefixed) name.
  438. *
  439. * @return The value.
  440. * @see org.xml.sax.AttributeList#getValue(java.lang.String)
  441. */
  442. public String getValue (String qName)
  443. {
  444. return attributes.getValue(qName);
  445. }
  446. private Attributes attributes;
  447. }
  448. }
  449. // end of XMLReaderAdapter.java