package context.arch.comm.language; import org.xml.sax.helpers.DefaultHandler; import org.xml.sax.helpers.XMLReaderFactory; import org.xml.sax.Attributes; import org.xml.sax.ContentHandler; import org.xml.sax.SAXException; import org.xml.sax.InputSource; import org.xml.sax.XMLReader; import java.io.IOException; import java.io.Reader; import java.util.Hashtable; import javax.xml.parsers.SAXParserFactory; import context.arch.comm.DataObject; /** * This class provides access to the SAX XML parsing code using the specified * XML parser class/driver. It implements ParserInterface and extends * HandlerBase * * @see context.arch.comm.language.DecoderInterface * @see org.xml.sax.HandlerBase * * Updated to adhere to SAX2 * * @author Anind Dey * @author Brian Y. Lim * */ public class SAX_XMLDecoder extends DefaultHandler implements DecoderInterface { /** * Debug flag. Set to true to see debug messages. */ public static boolean DEBUG = false; public static final String AELFRED_SAX_XML_DECODER = "com.microstar.xml.SAXDriver"; // this parser hasn't been updated since 2002, so I think let's upgrade to Xerces public static final String XERCES_SAX_XML_DECODER = "org.apache.xerces.parsers.SAXParser"; // the Xerces parser is bundled with JDK 1.5 onwards, so we should use this /** * The language for this class is XML */ public static final String LANGUAGE = "XML"; private XMLReader parser; private String decoderDriver = XERCES_SAX_XML_DECODER; private DataObject data; /** * Basic constructor which uses the default XML parser and sets the * document handler to this class * * @exception context.arch.comm.language.InvalidDecoderException when the * given decoder can not be created * @see #DEFAULT_SAX_XML_DECODER */ public SAX_XMLDecoder() throws InvalidDecoderException { try { parser = XMLReaderFactory.createXMLReader(decoderDriver); } catch (SAXException e) { try { // If unable to create an instance, let's try to use // the XMLReader from JAXP SAXParserFactory m_parserFactory = SAXParserFactory.newInstance(); m_parserFactory.setNamespaceAware(true); parser = m_parserFactory.newSAXParser().getXMLReader(); } catch (Exception e1) { e1.printStackTrace(); return; } } ContentHandler handler = this; parser.setContentHandler(handler); } /** * This method decodes the given XML data and returns the result in * a DataObject. It calls the parser created in the constructor * * @param XMLdata XML data to be decoded * @return the DataObject containing the results of the decoded XML data * @exception context.arch.comm.language.DecodeException when the * given XML data can not be decoded * @see org.xml.sax.Parser#parse(InputSource) */ public DataObject decodeData(Reader XMLdata) throws DecodeException { try { parser.parse(new InputSource(XMLdata)); return data; } catch (IOException ioe) { System.out.println("SAX_XMLParser parse IOException: "+ioe); throw new DecodeException(); } catch (SAXException se) { System.out.println("SAX_XMLParser parse SAXException: "+se); throw new DecodeException(); } } /** * Returns the language being used in encoding and decoding * * @return the language being used in encoding and decoding * @see #LANGUAGE */ public String getLanguage() { return LANGUAGE; } /** * Returns the name of the parser driver being used for encoding and decoding * * @return the name of the parser driver being used for encoding and decoding */ public String getClassName() { return this.getClass().getName(); } /** * Receive notification of the beginning of the document. * Creates a new DataObject * * @see context.arch.comm.DataObject */ @Override public void startDocument() { data = new DataObject(); } /** * Receive notification of the end of the document. Empty method. */ @Override public void endDocument() { } /** * Receive notification of the start of a new element. * Adds attributes to the DataObject * * @param name String name of new element * @param attributes Attributes object containing CTK attributes for new element * @see context.arch.comm.DataObject#addElement(String,Hashtable) */ @Override public void startElement(String uri, String localName, String qName, Attributes attributes) { Hashtable<String, String> hash = new Hashtable<String, String>(); for (int i = 0; i < attributes.getLength(); i++) { hash.put(attributes.getQName(i).trim(), attributes.getValue(i).trim()); } data.addElement(qName.trim(), hash); } /** * Receive notification of the end of an element. Closes the DataObject. * * @param name String name of ended element * @see context.arch.comm.DataObject#closeElement(String) */ @Override public void endElement(String uri, String localName, String qName) { data.closeElement(qName.trim()); } /** * Receive notification of non-element and non-attribute characters ignoring whitespace. * Adds the value to the current element * * @param ch array of characters read in * @param start start position in the array * @param length number of characters to read in from the array * @see context.arch.comm.DataObject#addValue(String) */ @Override public void characters(char ch[], int start, int length) { String chars = new String(ch, start, length).trim(); if (chars.length() > 0) { data.addValue(chars); } } }