[jdom-interest] How to kill a parser - nicely

Alex Rosen arosen at silverstream.com
Tue Aug 14 07:53:04 PDT 2001


Specifically, you should throw a particular subclass of SAXParseException,
so you can tell it from a real error. Here's the code I use to retrieve only
up to the root element (i.e. it stops processing when it hits the root
element's closing >.) It seems to work fine.

Alex

		// Setup the SAXBuilder.
		StoppableSAXBuilder builder = new StoppableSAXBuilder();
		builder.setValidation(false);

		// Parse the document.
		InputStream in = null;
		try
		{
			in = new BufferedInputStream(instream);
			m_document = builder.build(in);
			m_gotEntireDocument = true;
		}
		catch(JDOMException ex)
		{
			m_document = builder.getDocument();
			m_gotEntireDocument = false;
			// This exception was thrown to tell us that the root node was found,
			// and to halt further processing (to save time). This indicates success,
			// not failure, so we just swallow the exception here.
			if (!(ex.getRootCause() instanceof RootFoundException))
				throw ex;
		}
		finally
		{
			if (in != null)
				in.close();
		}
	}

			// Subclass of SAXBuilder that creates our special SAXHandler.
			private class StoppableSAXBuilder extends SAXBuilder
			{
				protected SAXHandler createContentHandler() throws Exception
				{
					m_handler = new StoppableSAXHandler(factory);
					return m_handler;
				}

				// If we've at least finished with the root element, then we return
				// the document that's been built so far.
				Document getDocument()
				{
					if (m_handler.m_gotRootElementEnd)
						return m_handler.getDocument();
					else
						return null;
				}

				private StoppableSAXHandler		m_handler;
			}

			// Subclass of SAXHandler that stops the build process after the
			// root element has been found.
			private class StoppableSAXHandler extends SAXHandler
			{
				public StoppableSAXHandler(JDOMFactory factory) throws IOException
				{
					super(factory);
				}

				public void startElement(String uri, String localName, String qName,
Attributes attributes)
							throws SAXException
				{
					checkRoot();
					// Record the fact that we've gotten to the root element.
					if (!m_gotRootElementStart)
						m_gotRootElementStart = true;
					super.startElement(uri, localName, qName, attributes);
				}

				public void characters(char[] ch, int start, int length) throws
SAXException
				{
					checkRoot();
					super.characters(ch, start, length);
				}

				public void ignorableWhitespace(char[] ch, int start, int length) throws
SAXException
				{
					checkRoot();
					super.ignorableWhitespace(ch, start, length);
				}
				public void comment(char[] ch, int start, int length) throws
SAXException
				{
					checkRoot();
					super.comment(ch, start, length);
				}
				public void startEntity(String name) throws SAXException
				{
					checkRoot();
					super.startEntity(name);
				}
				public void processingInstruction(String target, String data) throws
SAXException
				{
					checkRoot();
					super.processingInstruction(target, data);
				}

				private void checkRoot() throws RootFoundException
				{
					// If we've started the root, then we now know that we've finished it.
					// Record that fact, and throw a RootFoundException if we only need
					// the root node. This will halt the parsing.
					if (m_gotRootElementStart && !m_gotRootElementEnd)
					{
						m_gotRootElementEnd = true;
						throw new RootFoundException();
					}
				}

				private boolean			m_gotRootElementStart;
				private boolean			m_gotRootElementEnd;
			}

			private static class RootFoundException extends SAXException
			{
				RootFoundException()
				{
					// This should never be visible to the user.
					super("Root element was successfully found. (This is not an error.)");
				}
			}



More information about the jdom-interest mailing list