From 5f8d917af607b5a8a0f5d5a40d95257705ef48dd Mon Sep 17 00:00:00 2001 From: Peter Bernard West Date: Tue, 7 May 2002 16:40:46 +0000 Subject: [PATCH] New files for SAX XML event serialisation. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/FOP_0-20-0_Alt-Design@194800 13f79535-47bb-0310-9956-ffa450edef68 --- src/org/apache/fop/xml/XMLEvent.java | 809 +++++++++++++++++++ src/org/apache/fop/xml/XMLSerialHandler.java | 192 +++++ src/org/apache/fop/xml/package.html | 6 + 3 files changed, 1007 insertions(+) create mode 100644 src/org/apache/fop/xml/XMLEvent.java create mode 100644 src/org/apache/fop/xml/XMLSerialHandler.java create mode 100644 src/org/apache/fop/xml/package.html diff --git a/src/org/apache/fop/xml/XMLEvent.java b/src/org/apache/fop/xml/XMLEvent.java new file mode 100644 index 000000000..1d614f841 --- /dev/null +++ b/src/org/apache/fop/xml/XMLEvent.java @@ -0,0 +1,809 @@ + +package org.apache.fop.xml; + +import org.apache.fop.apps.FOPException; +import org.apache.fop.datatypes.Ints; +import org.apache.fop.datastructs.SyncedCircularBuffer; + +import java.util.HashMap; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.Iterator; +import java.util.NoSuchElementException; + +import org.xml.sax.helpers.AttributesImpl; + +/* + * XMLEvent.java + * + * Created: Thu Nov 8 13:38:17 2001 + * + * Copyright (C) 2001 The Apache Software Foundation. All rights reserved. + * For details on use and redistribution please refer to the + * LICENSE file included with these sources. + * @author Peter B. West + * @version $Revision$ $Name$ + */ +/** + * This is a data class to encapsulate the data of an individual XML + * parse event. The current version, while defining accessor methods, + * leaves the component data of the event as public. The + * XMLSerialHandler methods set the values directly. + * This is Very Bad. + */ + +public class XMLEvent { + public static final int NOEVENT = 0; + + public static final int STARTDOCUMENT = 1; + public static final int ENDDOCUMENT = 2; + public static final int STARTELEMENT = 3; + public static final int ENDELEMENT = 4; + public static final int CHARACTERS = 5; + + private static final int MIN_XML_EV_TYPE = NOEVENT; + private static final int MAX_XML_EV_TYPE = CHARACTERS; + + // These are made public specifically so the the values of individual + // XMLEvent instances can be changed directly, on the assumption that + // the basic XML events are unlikely to change. + public int type = NOEVENT; + public String chars; + public int uriIndex; + public String localName; + public String qName; + public AttributesImpl attributes; + + public static final String DefAttrNSpace = ""; + public static final String XSLNamespace = + "http://www.w3.org/1999/XSL/Format"; + public static final String SVGNamespace = "http://www.w3.org/2000/svg"; + public static final String XlinkNamespace = + "http://www.w3.org/1999/xlink"; + public static final int DefAttrNSIndex = 0; + public static final int XSLNSpaceIndex = 1; + + /** + * A HashMap mapping a namespace URI to an int + * index. The HashMap is initialized with a few well-known URIs. As + * URIs are encountered in parsing, they are converted to an integer + * index by lookup in this HashMap. If the URI has not been seen, it + * is added to the uriIndices and uris for future reference. + *

+ * This is a private static + * maintained across all documents that may be processed in a single + * invocation. It is vital that no URI, once added, ever be deleted + * from this HashMap. + *

+ * HashMap is unsynchronized, so accesses and updates must be + * protected. + *

+ * Updates will be very rare, and accesses are directly related to the + * number of elements (and attributes) encountered. + */ + private static HashMap uriIndices = new HashMap(4); + /** + * A ArrayList of namespace URIs. Effectively, a mapping of + * an int index onto a URI. + * ArrayList is initialized with a few well-known URIs. As + * URIs are encountered in parsing, they are converted to an integer + * index by lookup in the uriIndices Hashmap. If the URI has not + * been seen, it is added to uriIndices and uris + * for future reference. + *

+ * This is a private static + * maintained across all documents that may be processed in a single + * invocation. + *

+ * ArrayList is unsynchronized, so access and updates must be + * protected. Both will be more rare than accesses to uriIndices. + */ + private static ArrayList uris = new ArrayList(4); + static { + uriIndices.put(DefAttrNSpace, Ints.consts.get(DefAttrNSIndex)); + uris.add(DefAttrNSIndex, DefAttrNSpace); + uriIndices.put(XSLNamespace, Ints.consts.get(XSLNSpaceIndex)); + uris.add(XSLNSpaceIndex, XSLNamespace); + uriIndices.put(SVGNamespace, Ints.consts.get(2)); + uris.add(2, SVGNamespace); + uriIndices.put(XlinkNamespace, Ints.consts.get(3)); + uris.add(3, XlinkNamespace); + } + + /** + * @return size of the uris . + */ + public static int getUrisSize() { + return uris.size(); + } + + /** + * If the URI is not pre-defined, and has not been seen before, add + * it to the stored namespaces, and return the index. + * @param uri the namespace uri + * @return integer index of the namespace URI + */ + public static int getURIIndex(String uri) { + synchronized (uriIndices) { + int i; + Integer intg = (Integer)uriIndices.get(uri); + if (intg == null) { + // update the indices + i = uris.size(); + uriIndices.put(uri, Ints.consts.get(i)); + return i; + } + // not null - found the integer + return intg.intValue(); + } + } + + /** + * @param index the integer index of the namespace URI + * @return the corresponding namespace URI + */ + public static String getIndexURI(int index) { + synchronized (uriIndices) { + return (String)uris.get(index); + } + } + + /** + * @param events the buffer in which events have been stored + * @return next event from the SyncedCircularBuffer + * @exception FOPException. The purpose of this method is to catch + * and transform any InterruptedException exceptions thrown by the + * SyncedCircularBuffer. + */ + public static XMLEvent getEvent(SyncedCircularBuffer events) + throws FOPException + { + XMLEvent ev; + try { + ev = (XMLEvent)events.get(); + //System.out.println("getEvent: " + ev); + return ev; + } catch (InterruptedException e) { + throw new FOPException("InterruptedException"); + } + } + + /** + * @param events the buffer in which events have been stored + * @return an ENDDOCUMENT event + * @exception FOPException if buffer errors or interrupts occur + * @exception NoSuchElementException if the event is not found + */ + public static XMLEvent getEndDocument(SyncedCircularBuffer events) + throws FOPException + { + XMLEvent ev = getEvent(events); + while (ev != null && ev.type != XMLEvent.ENDDOCUMENT) { + ev = getEvent(events); + } + if (ev == null) { + throw new NoSuchElementException("EndDocument not found."); + } + return ev; + } + + /** + * @param events the buffer in which events have been stored + * @return an ENDDOCUMENT event + * @exception FOPException if buffer errors or interrupts occur + * @exception NoSuchElementException if ENDDOCUMENT is not the next + * event detected. The erroneous event is pushed back. + */ + public static XMLEvent expectEndDocument(SyncedCircularBuffer events) + throws FOPException + { + XMLEvent ev = getEvent(events); + if (ev != null && ev.type == XMLEvent.ENDDOCUMENT) { + return ev; + } + events.pushBack(ev); + throw new NoSuchElementException("EndDocument not found."); + } + + /** + * @param events the buffer in which events have been stored + * @return a STARTELEMENT event + * @exception FOPException if buffer errors or interrupts occur + * @exception NoSuchElementException if the event is not found + */ + public static XMLEvent getStartElement(SyncedCircularBuffer events) + throws FOPException + { + XMLEvent ev = getEvent(events); + while (ev != null && ev.type != XMLEvent.STARTELEMENT) { + ev = getEvent(events); + } + if (ev == null) { + throw new NoSuchElementException("StartElement not found."); + } + return ev; + } + + /** + * @param events the buffer in which events have been stored + * @return a STARTELEMENT event + * @exception FOPException if buffer errors or interrupts occur + * @exception NoSuchElementException if STARTELEMENT is not the next + * event detected. The erroneous event is pushed back. + */ + public static XMLEvent expectStartElement(SyncedCircularBuffer events) + throws FOPException + { + XMLEvent ev = getEvent(events); + if (ev != null && ev.type == XMLEvent.STARTELEMENT) { + return ev; + } + events.pushBack(ev); + throw new NoSuchElementException("StartElement not found."); + } + + /** + * @param events the buffer in which events have been stored + * @param qName a String with the QName of the + * required STARTELEMENT + * @return a STARTELEMENT event + * @exception FOPException if buffer errors or interrupts occur + * @exception NoSuchElementException if the event is not found + */ + public static XMLEvent getStartElement + (SyncedCircularBuffer events, String qName) throws FOPException + { + XMLEvent ev = getEvent(events); + while (ev != null && + ! (ev.type == XMLEvent.STARTELEMENT + && ev.qName.equals(qName))) { + ev = getEvent(events); + } + if (ev == null) { + throw new NoSuchElementException + ("StartElement "+ qName + " not found."); + } + return ev; + } + + /** + * @param events the buffer in which events have been stored + * @param qName a String with the QName of the + * required STARTELEMENT + * @return a STARTELEMENT event + * @exception FOPException if buffer errors or interrupts occur + * @exception NoSuchElementException if STARTELEMENT is not the next + * event detected. The erroneous event is pushed back. + */ + public static XMLEvent expectStartElement + (SyncedCircularBuffer events, String qName) throws FOPException + { + XMLEvent ev = getEvent(events); + if (ev != null && + (ev.type == XMLEvent.STARTELEMENT && ev.qName.equals(qName))) { + return ev; + } + events.pushBack(ev); + throw new NoSuchElementException + ("StartElement "+ qName + " not found."); + } + + /** + * @param events the buffer in which events have been stored + * @param uriIndex an int with the index of the URI of the + * required URI + * @param localName a String with the local name of the + * required STARTELEMENT + * @return a STARTELEMENT event + * @exception FOPException if buffer errors or interrupts occur + * @exception NoSuchElementException if the event is not found + */ + public static XMLEvent getStartElement + (SyncedCircularBuffer events, int uriIndex, String localName) + throws FOPException + { + XMLEvent ev = getEvent(events); + while (ev != null && + ! (ev.type == XMLEvent.STARTELEMENT + && ev.localName.equals(localName) + && ev.uriIndex == uriIndex)) { + ev = getEvent(events); + } + if (ev == null) { + throw new NoSuchElementException + ("StartElement " + XMLEvent.getIndexURI(uriIndex) + + ":" + localName + " not found."); + } + return ev; + } + + /** + * @param events the buffer in which events have been stored + * @param uriIndex an int with the index of the URI of the + * required URI + * @param localName a String with the local name of the + * required STARTELEMENT + * @return a STARTELEMENT event + * @exception FOPException if buffer errors or interrupts occur + * @exception NoSuchElementException if STARTELEMENT is not the next + * event detected. The erroneous event is pushed back. + */ + public static XMLEvent expectStartElement + (SyncedCircularBuffer events, int uriIndex, String localName) + throws FOPException + { + XMLEvent ev = getEvent(events); + if (ev != null && + (ev.type == XMLEvent.STARTELEMENT + && ev.localName.equals(localName) + && ev.uriIndex == uriIndex)) { + return ev; + } + events.pushBack(ev); + throw new NoSuchElementException + ("StartElement " + XMLEvent.getIndexURI(uriIndex) + + ":" + localName + " not found."); + } + + /** + * Get one of a list of possible STARTELEMENT events. + * @param events the buffer in which events have been stored + * @param list a LinkedList containing either Strings + * with the QName, or UriLocalName + * objects with the URI index and local name of one of the required + * STARTELEMENT events. + * @return a STARTELEMENT event + * @exception FOPException if buffer errors or interrupts occur + * @exception NoSuchElementException if the event is not found + */ + public static XMLEvent getStartElement + (SyncedCircularBuffer events, LinkedList list) + throws FOPException + { + XMLEvent ev; + do { + try { + ev = expectStartElement(events, list); + return ev; + } catch (NoSuchElementException e) { + // keep trying + } + // The non-matching event has been pushed back. + // Get it and discard. Note that if the first attempt to + // getEvent() returns null, the expectStartElement() calls + // will throw a NoSuchElementException + ev = getEvent(events); + } while (ev != null); + // Exit from this while loop is only by discovery of null event + throw new NoSuchElementException + ("StartElement from list not found."); + } + + /** + * Get one of a list of possible STARTELEMENT events. + * @param events the buffer in which events have been stored + * @param list a LinkedList containing either Strings + * with the QName, or UriLocalName + * objects with the URI index and local name of one of the required + * STARTELEMENT events. + * @return a STARTELEMENT event + * @exception FOPException if buffer errors or interrupts occur + * @exception NoSuchElementException if the event is not found + */ + public static XMLEvent expectStartElement + (SyncedCircularBuffer events, LinkedList list) + throws FOPException + { + XMLEvent ev; + Iterator elements = list.iterator(); + while (elements.hasNext()) { + Object o = elements.next(); + if (o instanceof String) { + try { + ev = expectStartElement(events, (String) o); + // Found it! + return ev; + } catch (NoSuchElementException e) { + // Keep trying + } + } else if (o instanceof UriLocalName) { + try { + ev = expectStartElement + (events, ((UriLocalName) o).getUriIndex(), + ((UriLocalName) o).getLocalName()); + // Found it! + return ev; + } catch (NoSuchElementException e) { + // Keep trying + } + } else + throw new FOPException + ("Invalid list elements for getStartElement"); + } + throw new NoSuchElementException + ("StartElement from list not found."); + } + + /** + * @param events the buffer in which events have been stored + * @return an ENDELEMENT event + * @exception FOPException if buffer errors or interrupts occur + * @exception NoSuchElementException if the event is not found + */ + public static XMLEvent getEndElement(SyncedCircularBuffer events) + throws FOPException + { + XMLEvent ev = getEvent(events); + while (ev != null && ev.type != XMLEvent.ENDELEMENT) { + ev = getEvent(events); + } + if (ev == null) { + throw new NoSuchElementException("EndElement not found."); + } + return ev; + } + + /** + * @param events the buffer in which events have been stored + * @return an ENDELEMENT event + * @exception FOPException if buffer errors or interrupts occur + * @exception NoSuchElementException if ENDELEMENT is not the next + * event detected. The erroneous event is pushed back. + */ + public static XMLEvent expectEndElement(SyncedCircularBuffer events) + throws FOPException + { + XMLEvent ev = getEvent(events); + if (ev != null && ev.type == XMLEvent.ENDELEMENT) { + return ev; + } + events.pushBack(ev); + throw new NoSuchElementException("EndElement not found."); + } + + /** + * @param events the buffer in which events have been stored + * @param qName a String with the QName of the + * required STARTELEMENT + * @return an ENDELEMENT event + * @exception FOPException if buffer errors or interrupts occur + * @exception NoSuchElementException if the event is not found + */ + public static XMLEvent getEndElement + (SyncedCircularBuffer events, String qName) throws FOPException + { + XMLEvent ev = getEvent(events); + while (ev != null && + ! (ev.type == XMLEvent.ENDELEMENT && ev.qName.equals(qName))) { + ev = getEvent(events); + } + if (ev == null) { + throw new NoSuchElementException + ("EndElement "+ qName + " not found."); + } + return ev; + } + + /** + * @param events the buffer in which events have been stored + * @param qName a String with the QName of the + * required STARTELEMENT + * @return an ENDELEMENT event + * @exception FOPException if buffer errors or interrupts occur + * @exception NoSuchElementException if STARTELEMENT is not the next + * event detected. The erroneous event is pushed back. + */ + public static XMLEvent expectEndElement + (SyncedCircularBuffer events, String qName) throws FOPException + { + XMLEvent ev = getEvent(events); + if (ev != null && + (ev.type == XMLEvent.ENDELEMENT && ev.qName.equals(qName))) { + return ev; + } + events.pushBack(ev); + throw new NoSuchElementException + ("EndElement "+ qName + " not found."); + } + + /** + * @param events the buffer in which events have been stored + * @param uriIndex an int with the index of the URI of the + * required URI + * @param localName a String with the local name of the + * required STARTELEMENT + * @return an ENDELEMENT event + * @exception FOPException if buffer errors or interrupts occur + * @exception NoSuchElementException if the event is not found + */ + public static XMLEvent getEndElement + (SyncedCircularBuffer events, int uriIndex, String localName) + throws FOPException + { + XMLEvent ev = getEvent(events); + while (ev != null && + ! (ev.type == XMLEvent.ENDELEMENT + && ev.localName.equals(localName) + && ev.uriIndex == uriIndex)) { + ev = getEvent(events); + } + if (ev == null) { + throw new NoSuchElementException + ("EndElement " + XMLEvent.getIndexURI(uriIndex) + + ":" + localName + " not found."); + } + return ev; + } + + /** + * @param events the buffer in which events have been stored + * @param uriIndex an int with the index of the URI of the + * required URI + * @param localName a String with the local name of the + * required STARTELEMENT + * @return an ENDELEMENT event + * @exception FOPException if buffer errors or interrupts occur + * @exception NoSuchElementException if STARTELEMENT is not the next + * event detected. The erroneous event is pushed back. + */ + public static XMLEvent expectEndElement + (SyncedCircularBuffer events, int uriIndex, String localName) + throws FOPException + { + XMLEvent ev = getEvent(events); + if (ev != null && + (ev.type == XMLEvent.ENDELEMENT + && ev.localName.equals(localName) + && ev.uriIndex == uriIndex)) { + return ev; + } + events.pushBack(ev); + throw new NoSuchElementException + ("EndElement " + XMLEvent.getIndexURI(uriIndex) + + ":" + localName + " not found."); + } + + /** + * @param events the buffer in which events have been stored + * @param event an XMLEvent. Only the uriIndex and the + * localName from the event are used. It is intended that the XMLEvent + * returned to the corresponding get/expectStartElement() call be used. + * @return an ENDELEMENT event + * @exception FOPException if buffer errors or interrupts occur + * @exception NoSuchElementException if the event is not found + */ + public static XMLEvent getEndElement + (SyncedCircularBuffer events, XMLEvent event) + throws FOPException + { + XMLEvent ev = getEvent(events); + while (ev != null && + ! (ev.type == XMLEvent.ENDELEMENT + && ev.localName.equals(event.localName) + && ev.uriIndex == event.uriIndex)) { + ev = getEvent(events); + } + if (ev == null) { + throw new NoSuchElementException + ("EndElement " + XMLEvent.getIndexURI(event.uriIndex) + + ":" + event.localName + " not found."); + } + return ev; + } + + /** + * @param events the buffer in which events have been stored + * @param event an XMLEvent. Only the uriIndex and the + * localName from the event are used. It is intended that the XMLEvent + * returned to the corresponding get/expectStartElement() call be used. + * @return an ENDELEMENT event + * @exception FOPException if buffer errors or interrupts occur + * @exception NoSuchElementException if STARTELEMENT is not the next + * event detected. The erroneous event is pushed back. + */ + public static XMLEvent expectEndElement + (SyncedCircularBuffer events, XMLEvent event) + throws FOPException + { + XMLEvent ev = getEvent(events); + if (ev != null && + (ev.type == XMLEvent.ENDELEMENT + && ev.localName.equals(event.localName) + && ev.uriIndex == event.uriIndex)) { + return ev; + } + events.pushBack(ev); + throw new NoSuchElementException + ("EndElement " + XMLEvent.getIndexURI(event.uriIndex) + + ":" + event.localName + " not found."); + } + + /** + * @param events the buffer in which events have been stored + * @return a CHARACTERS event + * @exception FOPException if buffer errors or interrupts occur + * @exception NoSuchElementException if the event is not found + */ + public static XMLEvent getCharacters(SyncedCircularBuffer events) + throws FOPException + { + XMLEvent ev = getEvent(events); + while (ev != null && ev.type != XMLEvent.CHARACTERS) { + ev = getEvent(events); + } + if (ev == null) { + throw new NoSuchElementException("Characters not found."); + } + return ev; + } + + /** + * @param events the buffer in which events have been stored + * @return a CHARACTERS event + * @exception FOPException if buffer errors or interrupts occur + * @exception NoSuchElementException if CHARACTERS is not the next + * event detected. The erroneous event is pushed back. + */ + public static XMLEvent expectCharacters(SyncedCircularBuffer events) + throws FOPException + { + XMLEvent ev = getEvent(events); + if (ev != null && ev.type == XMLEvent.CHARACTERS) { + return ev; + } + events.pushBack(ev); + throw new NoSuchElementException("Characters not found."); + } + + /** + * The no-argument constructor uses the default initialization values + * of the data members: NOEVENT for the event type, and null references + * for all others. + */ + public XMLEvent (){} + + /** + * The fully defined constructor takes values for each of the data + * elements. + */ + public XMLEvent(int type, String chars, int uriIndex, + String localName, String qName, AttributesImpl attributes) + { + this.type = type; + this.chars = chars; + this.uriIndex = uriIndex; + this.localName = localName; + this.qName = qName; + this.attributes = attributes; + } + + /** + * The cloning constructor takes a reference to an existing + * XMLEvent object. + */ + public XMLEvent(XMLEvent ev) { + type = ev.type; + chars = ev.chars; + uriIndex = ev.uriIndex; + localName = ev.localName; + qName = ev.qName; + attributes = ev.attributes; + } + + public int getType() { return type; } + public void setType(int type) { + if (type < MIN_XML_EV_TYPE || type > MAX_XML_EV_TYPE) { + throw new IllegalArgumentException( + "XML event type out of range."); + } + this.type = type; + } + + public String getChars() { return chars; } + public void setChars(String chars) { + this.chars = chars; + } + public void setChars(char[] ch, int start, int length) { + chars = new String(ch, start, length); + } + + public String getUri() { return getIndexURI(uriIndex); } + public int getUriIndex() { return uriIndex; } + public void setUriIndex(int uriIndex) { + this.uriIndex = uriIndex; + } + + public String getLocalName() { return localName; } + public void setLocalName(String localName) { + this.localName = localName; + } + + public String getQName() { return qName; } + + public String getQNamePrefix() { + int i; + if ((i = qName.indexOf(':')) == -1) { + return ""; + } else { + return qName.substring(0, i); + } + } + + public void setQName(String QName) { + this.qName = qName; + } + + public AttributesImpl getAttributes() { return attributes; } + public void setAttributes(AttributesImpl attributes) { + this.attributes = attributes; + } + + public String toString() { + String tstr; + switch (type) { + case NOEVENT: + tstr = "NOEVENT"; + break; + case STARTDOCUMENT: + tstr = "STARTDOCUMENT"; + break; + case ENDDOCUMENT: + tstr = "ENDDOCUMENT"; + break; + case STARTELEMENT: + tstr = "STARTELEMENT"; + break; + case ENDELEMENT: + tstr = "ENDELEMENT"; + break; + case CHARACTERS: + tstr = "CHARACTERS"; + break; + default: + tstr = "Unknown type " + type; + } + tstr = tstr + "\nURI " + + uriIndex + " " + getIndexURI(uriIndex); + tstr = tstr + "\n" + "Local Name " + localName; + tstr = tstr + "\n" + "QName " + qName; + tstr = tstr + "\n" + "Chars <<<" + chars + ">>>"; + if (attributes == null) { + tstr = tstr + "\n" + "Attributes null"; + } else { + int len = attributes.getLength(); + tstr = tstr + "\n" + "No. of attributes " + len; + for (int i = 0; i < len; i++) { + tstr = tstr + "\n" + " URI: " + attributes.getURI(i); + tstr = tstr + "\n" + " QName: " + attributes.getQName(i); + tstr = tstr + "\n" + " LocalName: " + + attributes.getLocalName(i); + tstr = tstr + "\n" + " type: " + attributes.getType(i); + tstr = tstr + "\n" + " value: " + attributes.getValue(i); + } + } + return tstr; + } + + /** + * A nested class for holding an passing a URI index and local name + * pair, as used in the contain XMLEvent class. + */ + public static class UriLocalName { + private int uriIndex; + private String localName; + + public UriLocalName(int uriIndex, String localName) { + this.uriIndex = uriIndex; + this.localName = localName; + } + + public int getUriIndex() { + return uriIndex; + } + + public String getLocalName() { + return localName; + } + } + +} diff --git a/src/org/apache/fop/xml/XMLSerialHandler.java b/src/org/apache/fop/xml/XMLSerialHandler.java new file mode 100644 index 000000000..3ad7b97e4 --- /dev/null +++ b/src/org/apache/fop/xml/XMLSerialHandler.java @@ -0,0 +1,192 @@ + +package org.apache.fop.xml; + +import org.apache.fop.datastructs.SyncedCircularBuffer; +import org.apache.fop.apps.FOPException; +import org.apache.fop.apps.Driver; +import org.apache.fop.configuration.Configuration; + +import org.xml.sax.helpers.DefaultHandler; +import org.xml.sax.Attributes; +import org.xml.sax.helpers.AttributesImpl; +import org.xml.sax.SAXException; +import org.xml.sax.XMLReader; +import org.xml.sax.InputSource; + +import java.io.IOException; +import java.util.NoSuchElementException; + +/* + * XMLSerialHandler.java + * Created: Thu Nov 8 15:41:40 2001 + * + * Copyright (C) 2001 The Apache Software Foundation. All rights reserved. + * For details on use and redistribution please refer to the + * LICENSE file included with these sources. + * + * @author Peter B. West + * @version $Revision$ $Name$ + */ +/** + * XMLSerialHandler is the ContentHandler for the + * background XMLReader thread. + */ + +public class XMLSerialHandler extends DefaultHandler implements Runnable { + + private SyncedCircularBuffer events; + private XMLReader parser; + private InputSource source; + private Thread foThread; + private boolean errorDump; + + /** + * @param events the events buffer. + * @param parser the xml parser. + * @param source the parser input source. + */ + public XMLSerialHandler + (SyncedCircularBuffer events, XMLReader parser, InputSource source) { + this.events = events; + this.parser = parser; + this.source = source; + parser.setContentHandler(this); + errorDump = Configuration.getBooleanValue("debugMode").booleanValue(); + } + + public void setFoThread(Thread foThread) { + this.foThread = foThread; + } + + /** + * This is the run method for the callback parser thread. + */ + public void run() { + // I''m in the thread - run the parser + try { + parser.parse(source); + } catch (Exception e) { + if (errorDump) Driver.dumpError(e); + if (foThread != null) { + try { + foThread.interrupt(); + } catch (Exception ex) {} //ignore + } + throw new RuntimeException(e.getMessage()); + } + } + + /** + * Utility routine for the callback methods. It captures the + * InterruptedException that is possible from the put + * method of a SyncedCircularBuffer. + */ + public void putEvent(XMLEvent event) throws NoSuchElementException { + synchronized (events) { + try { + events.put(event); + } catch (InterruptedException e) { + throw new RuntimeException + ("Producer interrupted: " +e.getMessage()); + } + } + } + + /** + * Callback routine for the parser. + */ + public void startDocument() throws NoSuchElementException { + synchronized (events) { + XMLEvent event = new XMLEvent(); + //System.out.println("StartDocument thread " + // + Thread.currentThread().getName()); + event.type = XMLEvent.STARTDOCUMENT; + //System.out.println("SerialHandler: " + event); + putEvent(event); + } + } + + /** + * Callback routine for the parser. + */ + public void endDocument() throws NoSuchElementException { + synchronized (events) { + XMLEvent event = new XMLEvent(); + //System.out.println("EndDocument thread " + // + Thread.currentThread().getName()); + event.type = XMLEvent.ENDDOCUMENT; + //System.out.println("SerialHandler: " + event); + putEvent(event); + events.flushBuffer(); + } + } + + /** + * Callback routine for the parser. + * @param uri the URI of the element name + * @param localName the localname of the element + * @param qName the (prefix) qualified name of the element + * @param attributes the attribute set of the element, as an object + * implementing the Attributes interface. + */ + public void startElement(String uri, String localName, + String qName, Attributes attributes) + throws NoSuchElementException + { + synchronized (events) { + XMLEvent event = new XMLEvent(); + //System.out.println("StartElement thread " + // + Thread.currentThread().getName()); + event.type = XMLEvent.STARTELEMENT; + event.uriIndex = XMLEvent.getURIIndex(uri); + event.localName = localName; + event.qName = qName; + event.attributes = new AttributesImpl(attributes); + //System.out.println("SerialHandler: " + event); + putEvent(event); + } + } + + /** + * Callback routine for parser. + * @param uri the URI of this element name + * @param localName the unqualified localname of this element + * @param qName the (prefix) qualified name of this element + */ + public void endElement(String uri, String localName, + String qName) + throws NoSuchElementException + { + synchronized (events) { + XMLEvent event = new XMLEvent(); + //System.out.println("EndElement thread " + // + Thread.currentThread().getName()); + event.type = XMLEvent.ENDELEMENT; + event.uriIndex = XMLEvent.getURIIndex(uri); + event.localName = localName; + event.qName = qName; + putEvent(event); + } + } + + /** + * Callback routine for parser to handle characters. + * @param ch the array of characters + * @param start starting position of this set of characters in the + * ch array. + * @param length number of characters in this set + */ + public void characters(char[] ch, int start, int length) + throws NoSuchElementException + { + synchronized (events) { + XMLEvent event = new XMLEvent(); + //System.out.println("characters thread " + // + Thread.currentThread().getName()); + event.type = XMLEvent.CHARACTERS; + event.chars = new String(ch, start, length); + //System.out.println("SerialHandler: " + event); + putEvent(event); + } + } +} diff --git a/src/org/apache/fop/xml/package.html b/src/org/apache/fop/xml/package.html new file mode 100644 index 000000000..733ed1b92 --- /dev/null +++ b/src/org/apache/fop/xml/package.html @@ -0,0 +1,6 @@ + +org.apache.fop.datastructs Package + +

Classes for FO parsing and XML event serialisation.

+ + -- 2.39.5