// SAXDriver.java: The SAX driver for AElfred.
// NO WARRANTY! See README, and copyright below.
// $Id$
package com.microstar.xml.driver;
import java.io.IOException;
import java.util.Enumeration;
import java.util.Hashtable;
import java.util.Locale;
import java.util.Stack;
import java.util.Vector;
import org.xml.sax.Attributes;
import org.xml.sax.ContentHandler;
import org.xml.sax.DTDHandler;
import org.xml.sax.EntityResolver;
import org.xml.sax.ErrorHandler;
import org.xml.sax.InputSource;
import org.xml.sax.Locator;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.XMLReader;
import org.xml.sax.helpers.DefaultHandler;
import com.microstar.xml.XmlHandler;
import com.microstar.xml.XmlParser;
/**
* A SAX driver for Microstar's Ælfred XML parser.
*
* <p>This driver acts as a front-end for Ælfred, and
* translates Ælfred's events into SAX events. It
* implements the SAX parser interface, and you can use it without
* directly calling Ælfred at all:</p>
*
* <pre>
* org.xml.sax.Parser parser = new com.microstar.xml.SAXDriver();
* </pre>
*
* <p>When you are using SAX, you do not need to use the
* <code>XmlParser</code> or <code>XmlHandler</code> classes at
* all: this class is your entry point.</p>
*
* <p>This driver is based on the 1.0gamma version of SAX,
* available from http://www.megginson.com/SAX/</p>
*
* @author Copyright (c) 1998 by Microstar Software Ltd.
* @author written by David Megginson <dmeggins@microstar.com>
* @version 1.1
* @since Ptolemy II 0.2
* @see XmlParser
*/
public class SAXDriver implements XmlHandler, Locator, Attributes, XMLReader //implements XmlHandler, Locator, AttributeList, Parser
{
//
// Variables.
//
//private HandlerBase base = new HandlerBase();
private DefaultHandler base = new DefaultHandler();
private XmlParser parser;
private boolean seenDTDEvents = false;
// Encapsulate the default behaviour
// from HandlerBase
private EntityResolver entityResolver = base;
private DTDHandler dtdHandler = base;
private ContentHandler documentHandler = base;
private ErrorHandler errorHandler = base;
private String elementName = null;
private Stack entityStack = new Stack();
private Vector attributeNames = new Vector();
private Vector attributeValues = new Vector();
private Hashtable properties = new Hashtable();
private Hashtable features = new Hashtable();
//
// Constructor.
//
public SAXDriver() {
}
//
// Implementation of org.xml.sax.Parser.
//
/**
* Set the locale.
*/
public void setLocale(Locale locale) throws SAXException {
throw new SAXException(
"AElfred driver does not yet have locale support.");
}
/**
* Set the entity resolver for this parser.
* @param handler The object to receive entity events.
*/
public void setEntityResolver(EntityResolver resolver) {
this.entityResolver = resolver;
}
/**
* Set the DTD handler for this parser.
* @param handler The object to receive DTD events.
*/
public void setDTDHandler(DTDHandler handler) {
this.dtdHandler = handler;
}
/**
* Set the document handler for this parser.
* @param handler The object to receive document events.
*/
public void setDocumentHandler(ContentHandler handler) {
this.documentHandler = handler;
}
/**
* Set the error handler for this parser.
* @param handler The object to receive error events.
*/
public void setErrorHandler(ErrorHandler handler) {
this.errorHandler = handler;
}
/**
* Parse a document.
* <p>If you want anything useful to happen, you should set
* at least one type of handler.
* @param source The XML input source.
* @see #setEntityResolver
* @see #setDTDHandler
* @see #setDocumentHandler
* @see #setErrorHandler
* @exception SAXException The handlers may throw any exception.
*/
public void parse(InputSource source) throws SAXException {
parser = new XmlParser();
parser.setHandler(this);
try {
if (source.getCharacterStream() != null) {
parser.parse(source.getSystemId(), source.getPublicId(), source
.getCharacterStream());
} else if (source.getByteStream() != null) {
parser.parse(source.getSystemId(), source.getPublicId(), source
.getByteStream(), source.getEncoding());
} else {
parser.parse(source.getSystemId(), source.getPublicId(), source
.getEncoding());
}
} catch (SAXException e) {
throw e;
} catch (Exception e) {
throw new SAXException(e);
} finally {
try {
closeStreams(source);
} catch (Exception e) {
throw new SAXException(e);
}
;
}
try {
closeStreams(source);
} catch (IOException e) {
throw new SAXException(e);
}
}
/**
* Parse an XML document from a system identifier (URI).
*/
public void parse(String systemId) throws SAXException {
parse(new InputSource(systemId));
}
/**
* Close any streams provided.
*/
private void closeStreams(InputSource source) throws IOException {
if (source.getCharacterStream() != null) {
source.getCharacterStream().close();
}
if (source.getByteStream() != null) {
source.getByteStream().close();
}
}
//
// Implementation of com.microstar.xml.XmlHandler.
// This is where the driver receives AElfred events and translates
// them into SAX events.
//
/**
* Implement com.microstar.xml.XmlHandler#startDocument.
* <p>Translate to the SAX interface.
* <p>Users should never invoke this method directly.
* @see com.microstar.xml.XmlHandler#startDocument
* @exception SAXException May throw any exception.
*/
public void startDocument() throws SAXException {
documentHandler.setDocumentLocator(this);
documentHandler.startDocument();
attributeNames.removeAllElements();
attributeValues.removeAllElements();
}
/**
* Implement com.microstar.xml.XmlHandler#endDocument.
* <p>Translate to the SAX interface.
* <p>Users should never invoke this method directly.
* @see com.microstar.xml.XmlHandler#endDocument
* @exception SAXException May throw any exception.
*/
public void endDocument() throws SAXException {
documentHandler.endDocument();
}
/**
* Implement com.microstar.xml.XmlHandler.resolveSystemId
* <p>Translate to the SAX interface.
* <p>Users should never invoke this method directly.
* @see com.microstar.xml.XmlHandler#resolveEntity
* @exception SAXException May throw any exception.
*/
public Object resolveEntity(String publicId, String systemId)
throws SAXException, IOException {
InputSource source = entityResolver.resolveEntity(publicId, systemId);
if (source == null) {
return null;
} else if (source.getCharacterStream() != null) {
return source.getCharacterStream();
} else if (source.getByteStream() != null) {
return source.getByteStream();
} else {
return source.getSystemId();
}
// FIXME: no way to tell AElfred
// about a new public id.
}
/**
* Implement com.microstar.xml.XmlHandler#startExternalEntity.
* <p>Translate to the SAX interface.
* <p>Users should never invoke this method directly.
* @see com.microstar.xml.XmlHandler#startExternalEntity
* @exception SAXException May throw any exception.
*/
public void startExternalEntity(String systemId) throws SAXException {
entityStack.push(systemId);
}
/**
* Implement com.microstar.xml.XmlHandler#endExternalEntity.
* <p>Translate to the SAX interface.
* <p>Users should never invoke this method directly.
* @see com.microstar.xml.XmlHandler#endExternalEntity
* @exception SAXException May throw any exception.
*/
public void endExternalEntity(String systemId) throws SAXException {
entityStack.pop();
}
/**
* Implement com.microstar.xml.XmlHandler#doctypeDecl.
* <p>Translate to the SAX interface.
* <p>Users should never invoke this method directly.
* @see com.microstar.xml.XmlHandler#doctypeDecl
* @exception SAXException May throw any exception.
*/
public void doctypeDecl(String name, String publicId, String systemId)
throws SAXException {
// no op
}
/**
* Implement com.microstar.xml.XmlHandler#attribute.
* <p>Translate to the SAX interface.
* <p>Users should never invoke this method directly.
* @see com.microstar.xml.XmlHandler#attribute
* @exception SAXException May throw any exception.
*/
public void attribute(String aname, String value, boolean isSpecified)
throws SAXException {
if (value != null) {
attributeNames.addElement(aname);
attributeValues.addElement(value);
}
}
/**
* Implement com.microstar.xml.XmlHandler#startElement.
* <p>Translate to the SAX interface.
* <p>Users should never invoke this method directly.
* @see com.microstar.xml.XmlHandler#startElement
* @exception SAXException May throw any exception.
*/
public void startElement(String elname) throws SAXException {
// We should deliver all DTD events
// before the first startElement event.
if (!seenDTDEvents) {
deliverDTDEvents();
seenDTDEvents = true;
}
elementName = elname;
//documentHandler.startElement(elname, this);
documentHandler.startElement("", elname, "", this);
elementName = null;
attributeNames.removeAllElements();
attributeValues.removeAllElements();
}
/**
* Implement com.microstar.xml.XmlHandler#endElement.
* <p>Translate to the SAX interface.
* <p>Users should never invoke this method directly.
* @see com.microstar.xml.XmlHandler#endElement
* @exception SAXException May throw any exception.
*/
public void endElement(String elname) throws SAXException {
//documentHandler.endElement(elname);
documentHandler.endElement("", elname, "");
}
/**
* Implement com.microstar.xml.XmlHandler#charData.
* <p>Translate to the SAX interface.
* <p>Users should never invoke this method directly.
* @see com.microstar.xml.XmlHandler#charData
* @exception SAXException May throw any exception.
*/
public void charData(char[] ch, int start, int length) throws SAXException {
documentHandler.characters(ch, start, length);
}
/**
* Implement com.microstar.xml.XmlHandler#ignorableWhitespace.
* <p>Translate to the SAX interface.
* <p>Users should never invoke this method directly.
* @see com.microstar.xml.XmlHandler#ignorableWhitespace
* @exception SAXException May throw any exception.
*/
public void ignorableWhitespace(char[] ch, int start, int length)
throws SAXException {
documentHandler.ignorableWhitespace(ch, start, length);
}
/**
* Implement com.microstar.xml.XmlHandler#processingInstruction.
* <p>Translate to the SAX interface.
* <p>Users should never invoke this method directly.
* @see com.microstar.xml.XmlHandler#processingInstruction
* @exception SAXException May throw any exception.
*/
public void processingInstruction(String target, String data)
throws SAXException {
documentHandler.processingInstruction(target, data);
}
/**
* Implement com.microstar.xml.XmlHandler#error.
* <p>Translate to the SAX interface.
* <p>Users should never invoke this method directly.
* @see com.microstar.xml.XmlHandler#error
* @exception SAXException May throw any exception.
*/
public void error(String message, String url, int line, int column)
throws SAXException {
errorHandler.fatalError(new SAXParseException(message, null, url, line,
column));
}
/**
* Before the first startElement event, deliver all notation
* and unparsed entity declarations.
*/
private void deliverDTDEvents() throws SAXException {
String ename;
String nname;
String publicId;
String systemId;
Enumeration notationNames = parser.declaredNotations();
Enumeration entityNames = parser.declaredEntities();
// First, report all notations.
while (notationNames.hasMoreElements()) {
nname = (String) notationNames.nextElement();
publicId = parser.getNotationPublicId(nname);
systemId = parser.getNotationSystemId(nname);
dtdHandler.notationDecl(nname, publicId, systemId);
}
// Next, report all unparsed entities.
while (entityNames.hasMoreElements()) {
ename = (String) entityNames.nextElement();
if (parser.getEntityType(ename) == XmlParser.ENTITY_NDATA) {
publicId = parser.getEntityPublicId(ename);
systemId = parser.getEntitySystemId(ename);
nname = parser.getEntityNotationName(ename);
dtdHandler.unparsedEntityDecl(ename, publicId, systemId, nname);
}
}
}
//
// Implementation of org.xml.sax.AttributeList.
//
public int getLength() {
return attributeNames.size();
}
public String getName(int i) {
return (String) (attributeNames.elementAt(i));
}
public String getType(int i) {
switch (parser.getAttributeType(elementName, getName(i))) {
case XmlParser.ATTRIBUTE_UNDECLARED:
case XmlParser.ATTRIBUTE_CDATA:
return "CDATA";
case XmlParser.ATTRIBUTE_ID:
return "ID";
case XmlParser.ATTRIBUTE_IDREF:
return "IDREF";
case XmlParser.ATTRIBUTE_IDREFS:
return "IDREFS";
case XmlParser.ATTRIBUTE_ENTITY:
return "ENTITY";
case XmlParser.ATTRIBUTE_ENTITIES:
return "ENTITIES";
case XmlParser.ATTRIBUTE_NMTOKEN:
case XmlParser.ATTRIBUTE_ENUMERATED:
return "NMTOKEN";
case XmlParser.ATTRIBUTE_NMTOKENS:
return "NMTOKENS";
case XmlParser.ATTRIBUTE_NOTATION:
return "NOTATION";
}
return null;
}
public String getValue(int i) {
return (String) (attributeValues.elementAt(i));
}
public String getType(String name) {
for (int i = 0; i < getLength(); i++) {
if (name.equals(getName(i))) {
return getType(i);
}
}
return null;
}
public String getValue(String name) {
for (int i = 0; i < getLength(); i++) {
if (name.equals(getName(i))) {
return getValue(i);
}
}
return null;
}
//
// Implementation of org.xml.sax.Locator.
//
public String getPublicId() {
return null; // TODO
}
public String getSystemId() {
return (String) (entityStack.peek());
}
public int getLineNumber() {
return parser.getLineNumber();
}
public int getColumnNumber() {
return parser.getColumnNumber();
}
public boolean getFeature(String name) {
// Not Yet Implemented
if (features.containsKey(name)) {
return ((Boolean) features.get(name)).booleanValue();
}
return false;
}
public void setFeature(String name, boolean value) {
// Not Yet Implemented
features.put(name, Boolean.valueOf(value));
}
public Object getProperty(String name) {
// Not Yet Implemented
if (properties.containsKey(name)) {
return properties.get(name);
}
return null;
}
public void setProperty(String name, Object value) {
// Not Yet Implemented
properties.put(name, value);
}
public EntityResolver getEntityResolver() {
// Not Yet Implemented
return null;
}
public DTDHandler getDTDHandler() {
// Not Yet Implemented
return null;
}
public void setContentHandler(ContentHandler handler) {
this.documentHandler = handler;
}
public ContentHandler getContentHandler() {
return this.documentHandler;
}
public ErrorHandler getErrorHandler() {
return this.errorHandler;
}
public String getURI(int index) {
// Not Yet Implemented
return "";
}
public String getLocalName(int index) {
// Not Yet Implemented
return "";
}
public String getQName(int index) {
// Not Yet Implemented
return "";
}
public int getIndex(String uri, String localPart) {
// Not Yet Implemented
return -1;
}
public int getIndex(String qName) {
// Not Yet Implemented
return -1;
}
public String getType(String uri, String localName) {
return "";
}
public String getValue(String uri, String localName) {
return "";
}
}