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