/* This file is part of NanoXML.
*
* $Revision: 1.3 $
* $Date: 2000/11/29 22:02:32 $
* $Name: RELEASE_1_6_8 $
*
* Copyright (C) 2000 Marc De Scheemaecker, All Rights Reserved.
*
* This software is provided 'as-is', without any express or implied warranty.
* In no event will the authors be held liable for any damages arising from the
* use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software in
* a product, an acknowledgment in the product documentation would be
* appreciated but is not required.
*
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
*
* 3. This notice may not be removed or altered from any source distribution.
*/
package tests.nanoxml.sax;
import tests.nanoxml.XMLElement;
import tests.nanoxml.XMLParseException;
import org.xml.sax.*;
import org.xml.sax.helpers.AttributeListImpl;
import java.io.*;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.Enumeration;
import java.util.Locale;
/**
* This is the SAX adapter for NanoXML. Note that this adapter is provided
* to make NanoXML "buzzword compliant". If you're not stuck with SAX
* compatibility, you should use the basic API (nanoxml.NanoXML) which is
* much more programmer-friendly as it doesn't require the cumbersome use
* of event handlers and has more powerful attribute-handling methods, but
* that is just IMHO. If you really want to use the SAX API, I would like you
* to point to the currently available native SAX parsers.
* <P>
* Here are some important notes:
* <UL><LI>The parser is non-validating.
* <LI>The DTD is fully ignored, including <CODE><!ENTITY...></CODE>.
* <LI>SAXParser is reentrant.
* <LI>There is support for a document locator.
* <LI>There is no support for mixed content (elements containing both
* subelements and CDATA elements)
* <LI>There are no ignorableWhitespace() events
* <LI>Attribute types are always reported as CDATA
* </UL>
* <P>
* $Revision: 1.3 $<BR>
* $Date: 2000/11/29 22:02:32 $<P>
*
* @see tests.nanoxml.sax.SAXLocator
* @see tests.nanoxml.XMLElement
*
* @author Marc De Scheemaecker
* <<A HREF="mailto:Marc.DeScheemaecker@advalvas.be"
* >Marc.DeScheemaecker@advalvas.be</A>>
* @version 1.6
*/
public class SAXParser
implements Parser
{
/**
* The associated document handler.
*/
private DocumentHandler documentHandler;
/**
* The associated error handler.
*/
private ErrorHandler errorHandler;
/**
* Initializes the SAX parser adapter.
*/
public SAXParser()
{
this.documentHandler = new HandlerBase();
this.errorHandler = new HandlerBase();
}
/**
* Sets the locale. Only locales using the language english are accepted.
*
* @exception org.xml.sax.SAXException
* if <CODE>locale</CODE> is <CODE>null</CODE> or the associated
* language is not english.
*/
public void setLocale(Locale locale)
throws SAXException
{
if ((locale == null) || (! locale.getLanguage().equals("en")))
{
throw new SAXException("NanoXML/SAX doesn't support locale: "
+ locale);
}
}
/**
* Sets the entity resolver. As the DTD is ignored, this resolver is never
* called.
*/
public void setEntityResolver(EntityResolver resolver)
{
// nothing to do
}
/**
* Sets the DTD handler. As the DTD is ignored, this handler is never
* called.
*/
public void setDTDHandler(DTDHandler handler)
{
// nothing to do
}
/**
* Allows an application to register a document event handler.
*/
public void setDocumentHandler(DocumentHandler handler)
{
this.documentHandler = handler;
}
/**
* Allows an applicaiton to register an error event handler.
*/
public void setErrorHandler(ErrorHandler handler)
{
this.errorHandler = handler;
}
/**
* Handles a subtree of the parsed XML data structure.
*
* @exception org.xml.sax.SAXException
* if one of the handlers throw such exception
*/
private void handleSubTree(XMLElement element,
SAXLocator locator)
throws SAXException
{
AttributeListImpl attrList = new AttributeListImpl();
locator.setLineNr(element.getLineNr());
Enumeration enum2 = element.enumeratePropertyNames();
while (enum2.hasMoreElements())
{
String key = (String)(enum2.nextElement());
String value = element.getProperty(key);
attrList.addAttribute(key, "CDATA", value);
}
this.documentHandler.startElement(element.getTagName(), attrList);
if (element.getContents() == null)
{
enum2 = element.enumerateChildren();
while (enum2.hasMoreElements())
{
this.handleSubTree((XMLElement)(enum2.nextElement()),
locator);
}
}
else
{
char[] chars = element.getContents().toCharArray();
this.documentHandler.characters(chars, 0, chars.length);
}
locator.setLineNr(-1);
this.documentHandler.endElement(element.getTagName());
}
/**
* Creates the top XML element.
* Override this method if you need a different parsing behaviour.<P>
* The default behaviour is:
* <UL><LI>Case insensitive tag and attribute names, names converted to
* uppercase
* <LI>The only initial entities are amp, lt, gt, apos and quot.
* <LI>Skip formatting whitespace in PCDATA elements.
* </UL>
*/
protected XMLElement createTopElement()
{
return new XMLElement();
}
/**
* Parses an XML document.
*
* @exception org.xml.sax.SAXException
* if one of the handlers throws such exception
* @exception java.io.IOException
* if an I/O exception occured while trying to read the document
*/
public void parse(InputSource source)
throws SAXException,
IOException
{
XMLElement topElement = this.createTopElement();
Reader reader = source.getCharacterStream();
SAXLocator locator = new SAXLocator(source.getSystemId());
this.documentHandler.setDocumentLocator(locator);
if (reader == null)
{
InputStream stream = source.getByteStream();
String encoding = source.getEncoding();
if (stream == null)
{
String systemId = source.getSystemId();
if (systemId == null)
{
SAXParseException saxException
= new SAXParseException("Invalid input source",
locator);
this.errorHandler.fatalError(saxException);
return;
}
try
{
URL url = new URL(systemId);
stream = url.openStream();
}
catch (MalformedURLException exception)
{
try
{
stream = new FileInputStream(systemId);
}
catch (FileNotFoundException exception2)
{
SAXParseException saxException
= new SAXParseException(null, locator,
exception2);
this.errorHandler.fatalError(saxException);
return;
}
catch (SecurityException exception2)
{
SAXParseException saxException
= new SAXParseException(null, locator,
exception2);
this.errorHandler.fatalError(saxException);
return;
}
}
}
if (encoding == null)
{
reader = new InputStreamReader(stream);
}
else
{
try
{
reader = new InputStreamReader(stream, encoding);
}
catch (UnsupportedEncodingException exception)
{
SAXParseException saxException
= new SAXParseException(null, locator, exception);
this.errorHandler.fatalError(saxException);
return;
}
}
}
try
{
topElement.parseFromReader(reader);
}
catch (XMLParseException exception)
{
locator.setLineNr(exception.getLineNr());
SAXParseException saxException
= new SAXParseException(null, locator, exception);
this.errorHandler.fatalError(saxException);
this.documentHandler.endDocument();
return;
}
locator.setLineNr(topElement.getLineNr());
this.documentHandler.startDocument();
this.handleSubTree(topElement, locator);
this.documentHandler.endDocument();
}
/**
* Parses an XML document from a system identifier (URI).
*
* @exception org.xml.sax.SAXException
* if one of the handlers throws such exception
* @exception java.io.IOException
* if an I/O exception occured while trying to read the document
*/
public void parse(String systemId)
throws SAXException,
IOException
{
this.parse(new InputSource(systemId));
}
}