]> source.dussan.org Git - xmlgraphics-fop.git/commitdiff
Changes involved in introducing XmlEventReader, with
authorPeter Bernard West <pbwest@apache.org>
Tue, 20 Jan 2004 05:45:55 +0000 (05:45 +0000)
committerPeter Bernard West <pbwest@apache.org>
Tue, 20 Jan 2004 05:45:55 +0000 (05:45 +0000)
configurable XmlEventSources

git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/branches/FOP_0-20-0_Alt-Design@197223 13f79535-47bb-0310-9956-ffa450edef68

14 files changed:
src/java/org/apache/fop/apps/Driver.java
src/java/org/apache/fop/datastructs/SyncedCircularBuffer.java
src/java/org/apache/fop/fo/FONode.java
src/java/org/apache/fop/fo/FOTree.java
src/java/org/apache/fop/fo/FoRoot.java
src/java/org/apache/fop/fo/declarations/FoDeclarations.java
src/java/org/apache/fop/fo/pagination/FoLayoutMasterSet.java
src/java/org/apache/fop/fo/pagination/FoPageSequenceMaster.java
src/java/org/apache/fop/fo/pagination/FoSimplePageMaster.java
src/java/org/apache/fop/pool/FopPool.java
src/java/org/apache/fop/xml/ArrayXmlEventsBuffer.java
src/java/org/apache/fop/xml/Namespaces.java
src/java/org/apache/fop/xml/SyncedXmlEventsBuffer.java
src/java/org/apache/fop/xml/XmlEventReader.java [new file with mode: 0644]

index 02c0794bc45f8bc07763ad45f2f8cc672db45359..21cb8aa2177b77e0cf1922e52802a36ec5d4a1be 100644 (file)
@@ -7,10 +7,10 @@
  * 
  * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
  * 
- * Redistribution and use in source and binary forms, with or without modifica-
+ * Redistribution and use in saxSource and binary forms, with or without modifica-
  * tion, are permitted provided that the following conditions are met:
  * 
- * 1. Redistributions of  source code must  retain the above copyright  notice,
+ * 1. Redistributions of  saxSource code must  retain the above copyright  notice,
  *    this list of conditions and the following disclaimer.
  * 
  * 2. Redistributions in binary form must reproduce the above copyright notice,
@@ -63,7 +63,9 @@ import org.apache.fop.layout.AreaTree;
 import org.apache.fop.messaging.MessageHandler;
 import org.apache.fop.version.Version;
 import org.apache.fop.xml.FoXmlSerialHandler;
+import org.apache.fop.xml.Namespaces;
 import org.apache.fop.xml.SyncedXmlEventsBuffer;
+import org.apache.fop.xml.XmlEventReader;
 
 /**
  * Sets up and runs serialized component threads.
@@ -78,10 +80,12 @@ public class Driver {
 
     private InputHandler inputHandler;
     private XMLReader parser;
-    private InputSource source;
+    private InputSource saxSource;
 
     private FoXmlSerialHandler xmlhandler;
-    private SyncedXmlEventsBuffer xmlevents;
+    private SyncedXmlEventsBuffer eventsBuffer;
+    private Namespaces namespaces;
+    private XmlEventReader eventReader;
     private FOTree foTree;
     private AreaTree areaTree = new AreaTree();
 
@@ -105,18 +109,18 @@ public class Driver {
     /**
      * Sets up the environment and start processing threads.
      * The primary elements of the environment include:<br>
-     * the input source, the parser, the
+     * the input saxSource, the parser, the
      * {@link org.apache.fop.xml.SyncedXmlEventsBuffer SyncedXmlEventsBuffer}
-     * (<code>xmlevents</code>), the
+     * (<code>eventsBuffer</code>), the
      * {@link org.apache.fop.xml.FoXmlSerialHandler FoXmlSerialHandler}
      * (<code>xmlhandler</code>) and the
      * {@link org.apache.fop.fo.FOTree FOTree} (<code>foTree</code>).
      * 
-     * <p>The <code>xmlhandler</code> uses the source and the parser to
-     * generate XML events which it stores in <code>xmlevents</code>.
+     * <p>The <code>xmlhandler</code> uses the saxSource and the parser to
+     * generate XML events which it stores in <code>eventsBuffer</code>.
      * <code>FoXmlSerialHandler</code> implements <code>Runnable</code>.
      * 
-     * <p>The <code>foTree</code> reads events from the <code>xmlevents</code>
+     * <p>The <code>foTree</code> reads events from the <code>eventsBuffer</code>
      * buffer, which it interprets to build the FO tree.  <code>FOTree</code>
      * implements <code>Runnable</code>.
      * 
@@ -126,7 +130,7 @@ public class Driver {
      * buffer has emptied.
      * <p>
      * The FO Tree builder thread is passed the runnable <code>foTree</code>,
-     * which blocks on an empty <code>xmlevents</code> buffer, and continues
+     * which blocks on an empty <code>eventsBuffer</code> buffer, and continues
      * when notified that events are available in the buffer.
      * 
      * @throws FOPException
@@ -134,13 +138,15 @@ public class Driver {
     public void run () throws FOPException {
         setInputHandler(Options.getInputHandler());
         parser = inputHandler.getParser();
-        source = inputHandler.getInputSource();
+        saxSource = inputHandler.getInputSource();
         // Setting of namespace-prefixes feature no longer required
         //setParserFeatures(parser);
 
-        xmlevents = new SyncedXmlEventsBuffer();
-        xmlhandler = new FoXmlSerialHandler(xmlevents, parser, source);
-        foTree = new FOTree(xmlevents);
+        namespaces = new Namespaces();
+        eventsBuffer = new SyncedXmlEventsBuffer(namespaces);
+        eventReader = new XmlEventReader(eventsBuffer, namespaces);
+        xmlhandler = new FoXmlSerialHandler(eventsBuffer, parser, saxSource);
+        foTree = new FOTree(eventReader);
 
         driverThread = Thread.currentThread();
         foThread = new Thread(foTree, "FOTreeBuilder");
index 97c87280acfb12eb30f8c4f14b8524574a97fa19..5099efac6a883fc889efb1b89db5efd7c121f570 100644 (file)
@@ -53,7 +53,6 @@
 package org.apache.fop.datastructs;
 
 import java.util.NoSuchElementException;
-import java.lang.IndexOutOfBoundsException;
 
 /**
  * A general synchronized circular buffer class.
@@ -124,8 +123,7 @@ public class SyncedCircularBuffer {
      * <p>This implementation supports a single entry pushback buffer.</p>
      * @param obj and <tt>Object</tt>
      */
-    synchronized public void pushBack (Object obj)
-        throws IndexOutOfBoundsException {
+    synchronized public void pushBack (Object obj) {
         if (pushBackBuf != null)
             throw new IndexOutOfBoundsException("pushBack buffer is full");
         pushBackBuf = obj;
index 320295ffa75d7ebe54cf5280725498c0eb38821f..5f3a232b1a57a467d240756eab2e5e275ab42d15 100644 (file)
@@ -76,8 +76,8 @@ import org.apache.fop.fo.properties.Property;
 import org.apache.fop.messaging.MessageHandler;
 import org.apache.fop.xml.FoXmlEvent;
 import org.apache.fop.xml.XmlEvent;
-import org.apache.fop.xml.SyncedXmlEventsBuffer;
 import org.apache.fop.xml.Namespaces;
+import org.apache.fop.xml.XmlEventReader;
 
 /**
  * Class for nodes in the FO tree.
@@ -142,10 +142,10 @@ public class FONode extends Node{
         PAGESEQ | FLOW | STATIC | TITLE | MC_MARKER;
 
     /** The buffer from which parser events are drawn. */
-    protected final SyncedXmlEventsBuffer xmlevents;
+    protected final XmlEventReader xmlevents;
 
     /** The namespaces object associated with <i>xmlevents</i>. */
-    protected Namespaces namespaces;
+    protected final Namespaces namespaces;
 
     /** The FO type. */
     public final int type;
@@ -616,8 +616,8 @@ public class FONode extends Node{
                 new FoMarker(getFOTree(), this, (FoXmlEvent)ev, stateFlags);
                 numMarkers++;
                 ev = xmlevents.getEndElement(
-                        SyncedXmlEventsBuffer.DISCARD_EV, ev);
-                namespaces.surrenderEvent(ev);
+                        XmlEventReader.DISCARD_EV, ev);
+                namespaces.relinquishEvent(ev);
             }
         } catch (TreeException e) {
             throw new FOPException(e);
index 14787cfe74924dc5814d41635ffa765ac0b4bd43..8e61578981ebe1f579a94604bb6f577fd4a6a5c1 100644 (file)
@@ -63,8 +63,8 @@ import org.apache.fop.datatypes.Numeric;
 import org.apache.fop.datatypes.PropertyValue;
 import org.apache.fop.fo.expr.PropertyException;
 import org.apache.fop.fo.expr.PropertyParser;
-import org.apache.fop.xml.SyncedXmlEventsBuffer;
 import org.apache.fop.xml.XmlEvent;
+import org.apache.fop.xml.XmlEventReader;
 
 /**
  * <tt>FOTree</tt> is the class that generates and maintains the FO Tree.
@@ -80,7 +80,7 @@ public class FOTree extends Tree implements Runnable {
      * The buffer from which the <tt>XmlEvent</tt>s from the parser will
      * be read.  <tt>protected</tt> so that FONode can access it.
      */
-    protected SyncedXmlEventsBuffer xmlevents;
+    protected XmlEventReader xmlevents;
     private Thread parserThread;
     private boolean errorDump;
 
@@ -94,7 +94,7 @@ public class FOTree extends Tree implements Runnable {
      * @param xmlevents the buffer from which <tt>XmlEvent</tt>s from the
      * parser are read.
      */
-    public FOTree(SyncedXmlEventsBuffer xmlevents)
+    public FOTree(XmlEventReader xmlevents)
         throws PropertyException
     {
         super();
@@ -139,7 +139,7 @@ public class FOTree extends Tree implements Runnable {
      * parser events.
      * @return <i>xmlevents</i>.
      */
-    public SyncedXmlEventsBuffer getXmlevents() {
+    public XmlEventReader getXmlEventReader() {
         return xmlevents;
     }
 
@@ -158,7 +158,7 @@ public class FOTree extends Tree implements Runnable {
             foRoot.buildFoTree();
             System.out.println("Back from buildFoTree");
             // Clean up the fo:root event
-            event = xmlevents.getEndElement(SyncedXmlEventsBuffer.DISCARD_EV, event);
+            event = xmlevents.getEndElement(XmlEventReader.DISCARD_EV, event);
             // Get the end of document
             xmlevents.getEndDocument();
         } catch (Exception e) {
index 323c8c79d987d7d6ed1cd55fb0de27650d7b23cb..b781364dc691551f7cf3cce1f90e9bd52075bbe1 100644 (file)
@@ -66,9 +66,9 @@ import org.apache.fop.fo.expr.PropertyException;
 import org.apache.fop.fo.flow.FoPageSequence;
 import org.apache.fop.fo.pagination.FoLayoutMasterSet;
 import org.apache.fop.xml.FoXmlEvent;
-import org.apache.fop.xml.SyncedXmlEventsBuffer;
 import org.apache.fop.xml.XmlEvent;
 import org.apache.fop.xml.Namespaces;
+import org.apache.fop.xml.XmlEventReader;
 
 /**
  * <tt>FoRoot</tt> is the class which processes the fo:root start element
@@ -175,8 +175,8 @@ public class FoRoot extends FONode {
                                 new FoLayoutMasterSet(getFOTree(), this, ev);
             // Clean up the fo:layout-master-set event
             pageSequenceMasters = layoutMasters.getPageSequenceMasters();
-            ev = xmlevents.getEndElement(SyncedXmlEventsBuffer.DISCARD_EV, ev);
-            namespaces.surrenderEvent(ev);
+            ev = xmlevents.getEndElement(XmlEventReader.DISCARD_EV, ev);
+            namespaces.relinquishEvent(ev);
             layoutMasters.deleteSubTree();
 
             // Look for optional declarations
@@ -187,8 +187,8 @@ public class FoRoot extends FONode {
                 // process the declarations
                 declarations = numChildren();
                 new FoDeclarations(getFOTree(), this, ev);
-                ev = xmlevents.getEndElement(SyncedXmlEventsBuffer.DISCARD_EV, ev);
-                namespaces.surrenderEvent(ev);
+                ev = xmlevents.getEndElement(XmlEventReader.DISCARD_EV, ev);
+                namespaces.relinquishEvent(ev);
             }
 
             // Process page-sequences here
@@ -200,15 +200,15 @@ public class FoRoot extends FONode {
                 throw new FOPException("No page-sequence found.");
             firstPageSeq = numChildren();
             new FoPageSequence(getFOTree(), this, (FoXmlEvent)ev);
-            ev = xmlevents.getEndElement(SyncedXmlEventsBuffer.DISCARD_EV, ev);
-            namespaces.surrenderEvent(ev);
+            ev = xmlevents.getEndElement(XmlEventReader.DISCARD_EV, ev);
+            namespaces.relinquishEvent(ev);
             while ((ev = xmlevents.expectStartElement
                     (FObjectNames.PAGE_SEQUENCE, XmlEvent.DISCARD_W_SPACE))
                    != null) {
                 // Loop over remaining fo:page-sequences
                 new FoPageSequence(getFOTree(), this, (FoXmlEvent)ev);
-                ev = xmlevents.getEndElement(SyncedXmlEventsBuffer.DISCARD_EV, ev);
-                namespaces.surrenderEvent(ev);
+                ev = xmlevents.getEndElement(XmlEventReader.DISCARD_EV, ev);
+                namespaces.relinquishEvent(ev);
             }
         } catch (NoSuchElementException e) {
             throw new FOPException
index 772fd06040961c4cce2e801b6edf67f45132118f..1390bc1164f79a9ce4f432c1583480ec6f691e8c 100644 (file)
@@ -64,7 +64,7 @@ import org.apache.fop.fo.FOTree;
 import org.apache.fop.fo.FObjectNames;
 import org.apache.fop.fo.PropNames;
 import org.apache.fop.fo.expr.PropertyException;
-import org.apache.fop.xml.SyncedXmlEventsBuffer;
+import org.apache.fop.xml.XmlEventReader;
 import org.apache.fop.xml.XmlEvent;
 
 /**
@@ -123,16 +123,16 @@ public class FoDeclarations extends FONode {
                 throw new FOPException
                         ("No fo:color-profile in fo:declarations.");
             new FoColorProfile(foTree, this, ev);
-            ev = xmlevents.getEndElement(SyncedXmlEventsBuffer.DISCARD_EV, ev);
-            namespaces.surrenderEvent(ev);
+            ev = xmlevents.getEndElement(XmlEventReader.DISCARD_EV, ev);
+            namespaces.relinquishEvent(ev);
             do {
                 ev = xmlevents.expectStartElement
                     (FObjectNames.COLOR_PROFILE, XmlEvent.DISCARD_W_SPACE);
                 if (ev == null) break; // No instance of these elements found
                 new FoColorProfile(foTree, this, ev);
                 // Flush the master event
-                ev = xmlevents.getEndElement(SyncedXmlEventsBuffer.DISCARD_EV, ev);
-                namespaces.surrenderEvent(ev);
+                ev = xmlevents.getEndElement(XmlEventReader.DISCARD_EV, ev);
+                namespaces.relinquishEvent(ev);
             } while (true);
         } catch (NoSuchElementException e) {
             // Unexpected end of file
index 02e8d9cf73478f7541cb18a402d499f3236c0908..e9db16904cd718e09000068237678abd67ae057e 100644 (file)
@@ -67,7 +67,7 @@ import org.apache.fop.fo.FOTree;
 import org.apache.fop.fo.FObjectNames;
 import org.apache.fop.fo.PropNames;
 import org.apache.fop.fo.expr.PropertyException;
-import org.apache.fop.xml.SyncedXmlEventsBuffer;
+import org.apache.fop.xml.XmlEventReader;
 import org.apache.fop.xml.XmlEvent;
 
 /**
@@ -214,8 +214,8 @@ public class FoLayoutMasterSet extends FONode {
                     throw new FOPException
                             ("Error seeking page-masters");
                 // Flush the master event
-                ev = xmlevents.getEndElement(SyncedXmlEventsBuffer.DISCARD_EV, ev);
-                namespaces.surrenderEvent(ev);
+                ev = xmlevents.getEndElement(XmlEventReader.DISCARD_EV, ev);
+                namespaces.relinquishEvent(ev);
             } while (true);
         } catch (NoSuchElementException e) {
             // Unexpected end of file
index 97c23a93d1f55efda85d798dca53506d022988b3..35dd4d554b852d18b47cf4c1e5bd06ba7964528a 100644 (file)
@@ -67,7 +67,7 @@ import org.apache.fop.fo.FOTree;
 import org.apache.fop.fo.FObjectNames;
 import org.apache.fop.fo.PropNames;
 import org.apache.fop.fo.expr.PropertyException;
-import org.apache.fop.xml.SyncedXmlEventsBuffer;
+import org.apache.fop.xml.XmlEventReader;
 import org.apache.fop.xml.XmlEvent;
 
 /**
@@ -252,8 +252,8 @@ public class FoPageSequenceMaster extends FONode {
                     throw new FOPException
                             ("Aargh! expectStartElement(events, list)");
                 ev = xmlevents.getEndElement
-                                    (SyncedXmlEventsBuffer.DISCARD_EV, ev);
-                namespaces.surrenderEvent(ev);
+                                    (XmlEventReader.DISCARD_EV, ev);
+                namespaces.relinquishEvent(ev);
             } while (true);
         } catch (NoSuchElementException e) {
             throw new FOPException("Unexpected EOF in page-sequence-master.");
@@ -343,8 +343,8 @@ public class FoPageSequenceMaster extends FONode {
                     //    ("Found conditional-page-master-reference");
                     new FoConditionalPageMasterReference(foTree, this, ev);
                     ev = this.xmlevents.getEndElement
-                                    (SyncedXmlEventsBuffer.DISCARD_EV, ev);
-                    this.namespaces.surrenderEvent(ev);
+                                    (XmlEventReader.DISCARD_EV, ev);
+                    this.namespaces.relinquishEvent(ev);
                 } while (true);
             } catch (NoSuchElementException e) {
                 // End of file reached
index cf2335435e0c3bae52b9195ad4c8b3c0cc803a5b..e200b6fb3ab4cb9e52802c9f91d39988f7120922 100644 (file)
@@ -67,7 +67,7 @@ import org.apache.fop.fo.FObjectNames;
 import org.apache.fop.fo.PropNames;
 import org.apache.fop.fo.PropertySets;
 import org.apache.fop.fo.expr.PropertyException;
-import org.apache.fop.xml.SyncedXmlEventsBuffer;
+import org.apache.fop.xml.XmlEventReader;
 import org.apache.fop.xml.XmlEvent;
 
 /**
@@ -146,8 +146,8 @@ public class FoSimplePageMaster extends FONode {
         // Process region-body
         regionBody = new FoRegionBody(foTree, this, regionEv);
         regionEv = xmlevents.getEndElement
-                                (SyncedXmlEventsBuffer.DISCARD_EV, regionEv);
-        namespaces.surrenderEvent(regionEv);
+                                (XmlEventReader.DISCARD_EV, regionEv);
+        namespaces.relinquishEvent(regionEv);
 
         // Remaining regions are optional
         if ((regionEv = xmlevents.expectStartElement
@@ -156,8 +156,8 @@ public class FoSimplePageMaster extends FONode {
         {
             regionBefore = new FoRegionBefore(foTree, this, regionEv);
             regionEv = xmlevents.getEndElement
-                                (SyncedXmlEventsBuffer.DISCARD_EV, regionEv);
-            namespaces.surrenderEvent(regionEv);
+                                (XmlEventReader.DISCARD_EV, regionEv);
+            namespaces.relinquishEvent(regionEv);
         }
 
         if ((regionEv = xmlevents.expectStartElement
@@ -166,8 +166,8 @@ public class FoSimplePageMaster extends FONode {
         {
             regionAfter = new FoRegionAfter(foTree, this, regionEv);
             regionEv = xmlevents.getEndElement
-                            (SyncedXmlEventsBuffer.DISCARD_EV, regionEv);
-            namespaces.surrenderEvent(regionEv);
+                            (XmlEventReader.DISCARD_EV, regionEv);
+            namespaces.relinquishEvent(regionEv);
         }
 
         if ((regionEv = xmlevents.expectStartElement
@@ -176,8 +176,8 @@ public class FoSimplePageMaster extends FONode {
         {
             regionStart = new FoRegionStart(foTree, this, regionEv);
             regionEv = xmlevents.getEndElement
-                            (SyncedXmlEventsBuffer.DISCARD_EV, regionEv);
-            namespaces.surrenderEvent(regionEv);
+                            (XmlEventReader.DISCARD_EV, regionEv);
+            namespaces.relinquishEvent(regionEv);
         }
 
         if ((regionEv = xmlevents.expectStartElement
@@ -186,8 +186,8 @@ public class FoSimplePageMaster extends FONode {
         {
             regionEnd = new FoRegionEnd(foTree, this, regionEv);
             regionEv = xmlevents.getEndElement
-                            (SyncedXmlEventsBuffer.DISCARD_EV, regionEv);
-            namespaces.surrenderEvent(regionEv);
+                            (XmlEventReader.DISCARD_EV, regionEv);
+            namespaces.relinquishEvent(regionEv);
         }
 
         // Clean up the build environment
index 239672920ac245d57a62227f077c1a8523cd2331..a5091e7387c818764c133d349ba7ada14c1ff530 100644 (file)
@@ -79,7 +79,7 @@ public abstract class FopPool {
      * the range of values that the <tt>Poolable</tt> <i>id</i> field can
      * assume.
      * If there is a significant disparity between the frequency of
-     * pool acquire and surrender invocations, an id clash may arise in
+     * pool acquire and relinquish invocations, an id clash may arise in
      * the current set.
      */
     protected final BitSet eventSet;
@@ -119,12 +119,9 @@ public abstract class FopPool {
      * Return an <tt>Poolable</tt> to the pool.
      * @param ev - the event being returned.
      */
-    public synchronized void surrenderPoolable(Poolable ev) {
-        //System.out.println("surrenderEvent " + ev.id
-                                           //+ "  poolSize " + poolSize);
+    public synchronized void relinquishPoolable(Poolable ev) {
         if (ev == null) return;
         if (eventSet.get(ev.id)) {
-            //System.out.println("Event clash: " + ev);
             MessageHandler.logln
                     ("Event clash in Poolable pool. Id " + ev.id);
             return;
index 6c69a4a391293aaae73eff1ac29773b91790343c..47f206a514effa4ba9129022ce3369e8691f8e5d 100644 (file)
@@ -153,6 +153,9 @@ implements XmlEventSource {
         // TODO Should check for legality of this operation - this will involve
         // a change to the SyncedXmlEventsBuffer implementation and the
         // XmlEventSource interface.
+        if (nextEvent <= 0) {
+            throw new IndexOutOfBoundsException("No events read from buffer");
+        }
         nextEvent--;
     }
     
index 167d9467b5c57f032996aea1493e5819fd7ea8a7..328fac5d23315db806747cd3ececfa77d5180094 100644 (file)
@@ -341,13 +341,13 @@ public class Namespaces {
     }
     
     /**
-     * Surrender an event.  This method selects the appropriate pool
+     * Relinquish an event.  This method selects the appropriate pool
      * according to the event namespace index, and passes the request to
      * the pool.
-     * @param event to surrender
+     * @param event to relinquish
      */
-    public void surrenderEvent(XmlEvent event) {
-        pools[event.uriIndex].surrenderPoolable(event);
+    public void relinquishEvent(XmlEvent event) {
+        pools[event.uriIndex].relinquishPoolable(event);
     }
 
     /**
@@ -361,12 +361,12 @@ public class Namespaces {
     }
     
     /**
-     * Surrender a <code>UriLocalName</code>.
+     * Relinquish a <code>UriLocalName</code>.
      * The name is returned to the pool.
-     * @param uriName to surrender
+     * @param uriName to relinquish
      */
-    public void surrenderUriLocalName(UriLocalName uriName) {
-        uriLocalNamePool.surrenderPoolable(uriName);
+    public void relinquishUriLocalName(UriLocalName uriName) {
+        uriLocalNamePool.relinquishPoolable(uriName);
     }
     
     /**
index eda323e7f6a55d768c9c870bb211199d1c1450f2..2b1567c150f9b5da45058290f37df8db0775849d 100644 (file)
  */
 package org.apache.fop.xml;
 
-import java.util.BitSet;
-import java.util.Iterator;
-import java.util.LinkedList;
-import java.util.NoSuchElementException;
-
 import org.apache.fop.apps.FOPException;
 import org.apache.fop.datastructs.SyncedCircularBuffer;
-import org.apache.fop.fo.FObjectNames;
-import org.apache.fop.fo.FObjectSets;
 
 /**
  * A synchronized circular buffer for XMLEvents.
@@ -74,13 +67,6 @@ public class SyncedXmlEventsBuffer
 extends SyncedCircularBuffer
 implements XmlEventSource {
 
-    /**
-     * Constant for <i>discardEvent</i> field of
-     * <i>getEndElement(boolean discardEvent, XmlEvent(, boolean)).
-     */
-    public static final boolean DISCARD_EV = true,
-                                 RETAIN_EV = false;
-
     /**
      * Maintains an index of namespace URIs.  These can then be referred to
      * by an <tt>int</tt> index.
@@ -88,27 +74,30 @@ implements XmlEventSource {
     private Namespaces namespaces;
 
     /**
-     * No-argument constructor sets up a buffer with the default number of
-     * elements.
+     * One-argument constructor sets up a buffer with the default number of
+     * elements and the "global" <code>Namespaces</code> object.
      * The producer and consumer <tt>Thread</tt>s default to the current
      * thread at the time of instantiation.
+     * @param namespaces object for this <code>Driver</code> instance
+     * @throws IllegalArgumentException
      */
-    public SyncedXmlEventsBuffer()
+    public SyncedXmlEventsBuffer(Namespaces namespaces)
         throws IllegalArgumentException
     {
-        super();
-        namespaces = new Namespaces();
+        this.namespaces = namespaces;
     }
 
     /**
-     * Constructor taking one argument; the size of the buffer.
+     * Constructs a buffer with <code>size</code> elements and the "global"
+     * <code>Namespaces</code> object.
+     * @param namespaces object for this <code>Driver</code> instance
      * @param size the size of the buffer.  Must be > 1.
      */
-    public SyncedXmlEventsBuffer(int size)
+    public SyncedXmlEventsBuffer(Namespaces namespaces, int size)
         throws IllegalArgumentException
     {
         super(size);
-        namespaces = new Namespaces();
+        this.namespaces = namespaces;
     }
 
     /**
@@ -143,1143 +132,5 @@ implements XmlEventSource {
     public void pushBack (XmlEvent event) {
         super.pushBack(event);
     }
-    
-    /**
-     * Get the next event of the given type from the buffer.  Discard
-     * intervening events.
-     * @param eventType - the <tt>int</tt> event type.
-     * @return an event of the given type.
-     * @exception FOPException if buffer errors or interrupts occur.
-     * @exception NoSuchElementException if the event is not found.
-     */
-    public XmlEvent getSaxEvent(int eventType) throws FOPException {
-        XmlEvent ev = getEvent();
-        while (ev != null && ev.type != eventType) {
-            ev = getEvent();
-        }
-        if (ev == null) {
-            throw new NoSuchElementException
-                        (XmlEvent.eventTypeName(eventType) + " not found.");
-        }
-        return ev;
-    }
-
-    /**
-     * Get the next event of the given type and with the given <tt>QName</tt>
-     * from the buffer.  Discard intervening events.
-     * @param eventType - the <tt>int</tt> event type.
-     * @param qName a <tt>String</tt> with the <tt>QName</tt> of the
-     * required element.
-     * @return an event of the given type.
-     * @exception FOPException if buffer errors or interrupts occur.
-     * @exception NoSuchElementException if the event is not found.
-     */
-    public XmlEvent getSaxQNameEvent(int eventType, String qName)
-                throws FOPException
-    {
-        XmlEvent ev = getEvent();
-        while (ev != null &&
-               ! (ev.type == eventType && ev.qName.equals(qName))) {
-            ev = getEvent();
-        }
-        if (ev == null) {
-            throw new NoSuchElementException
-            (XmlEvent.eventTypeName(eventType) + " " + qName + " not found.");
-        }
-        return ev;
-    }
-
-    /**
-     * Get the next event of the given SAX type, from the given namespace
-     * (<code>uriIndex</code>) with the given local name, from the buffer.
-     * Discard intervening events.
-     * @param eventType the SAX event type.
-     * @param uriIndex the URI index maintained in the
-     * <tt>Namespaces</tt> object.
-     * @param localName of the required element.
-     * @return an event of the given type.
-     * @exception FOPException if buffer errors or interrupts occur.
-     * @exception NoSuchElementException if the event is not found.
-     */
-    public XmlEvent getSaxUriLocalEvent
-                            (int eventType, int uriIndex, String localName)
-                throws FOPException
-    {
-        XmlEvent ev = getEvent();
-        while (ev != null &&
-               ! (ev.type == eventType
-                  && ev.uriIndex == uriIndex
-                  && ev.localName.equals(localName))) {
-            namespaces.surrenderEvent(ev);
-            ev = getEvent();
-        }
-        if (ev == null)
-            throw new NoSuchElementException
-                    (XmlEvent.eventTypeName(eventType)
-                             + namespaces.getIndexURI(uriIndex)
-                                       + ":" + localName + " not found.");
-        return ev;
-    }
-    
-    /**
-     * Get the next event with of the given SAX type, whose URI is matched
-     * by the namespaces URI indexed by <code>uriIndex</code>, and whose
-     * namespace-specific type matches <code>nsType</code>.
-     * Discard any intervening events.
-     * @param eventType the SAX event type
-     * @param uriIndex of the URI in namespaces
-     * @param nsType the namespace-specific type
-     * @return the matching event
-     * @throws FOPException
-     */
-    public XmlEvent getSaxUriTypedEvent(
-            int eventType, int uriIndex, int nsType) throws FOPException {
-        XmlEvent ev = getEvent();
-        while (ev != null) {
-            if (ev.type == eventType && ev.uriIndex == uriIndex) {
-                switch (uriIndex) {
-                case Namespaces.DefAttrNSIndex:
-                    throw new NoSuchElementException
-                    ("No special types for default attribute namespace");
-                case Namespaces.XSLNSpaceIndex:
-                    // The FO namespace
-                    if (ev.getFoType() == nsType) {
-                        return ev;
-                    }
-                    break;
-                case Namespaces.FOXNSpaceIndex:
-                    // The FOX namespace
-                    if (ev.getFoxType() == nsType) {
-                        return ev;
-                    }
-                    break;
-                case Namespaces.SVGNSpaceIndex:
-                    // The SVG namespace
-                    if (ev.getSvgType() == nsType) {
-                        return ev;
-                    }
-                    break;
-                }
-            }
-            namespaces.surrenderEvent(ev);
-            ev = getEvent();
-        }
-        throw new NoSuchElementException
-            (XmlEvent.eventTypeName(eventType) + " "
-                    + namespaces.getIndexURI(uriIndex)
-                    + " type " + nsType + " not found.");
-    }
-
-    /**
-     * Get the next event of the given type, from the fo: namespace, with
-     * the given FO type.  Discard intervening events.
-     * @param eventType - the <tt>int</tt> event type.
-     * @param foType - the <tt>int</tt> FO type.
-     * @return an event of the given type.
-     * @exception FOPException if buffer errors or interrupts occur.
-     * @exception NoSuchElementException if the event is not found.
-     */
-    public XmlEvent getSaxFoEvent(int eventType, int foType)
-                throws FOPException
-    {
-        return getSaxUriTypedEvent(
-                eventType, Namespaces.XSLNSpaceIndex, foType);
-    }
-
-    /**
-     * Return the next element if it is of the required type.  If the next
-     * element is not of the required type, push it back onto the buffer.
-     * @param eventType - the <tt>int</tt> event type.
-     * @param discardWhiteSpace - if true, discard any <tt>characters</tt>
-     * events which contain only whitespace.
-     * @return an event of the required type.  If the next
-     * event detected is not of the required type, <tt>null</tt> is returned.
-     * The erroneous event is pushed back.
-     * @exception FOPException if buffer errors or interrupts occur.
-     * @exception NoSuchElementException if the buffer is empty.
-     */
-    public XmlEvent expectSaxEvent
-                                    (int eventType, boolean discardWhiteSpace)
-                throws FOPException
-    {
-        XmlEvent ev = getEvent();
-        if (discardWhiteSpace) {
-            while (ev != null && ev.type == XmlEvent.CHARACTERS
-                   && ev.chars.trim().equals("")) {
-                namespaces.surrenderEvent(ev);
-                ev = getEvent();
-            }
-        }
-        if (ev != null && ev.type == eventType) {
-            return ev;
-        }
-        if (ev == null)
-            throw new NoSuchElementException
-                        (XmlEvent.eventTypeName(eventType)
-                                           + " not found: end of buffer.");
-        pushBack(ev);
-        return null;
-    }
-
-    /**
-     * Return the next element if it is of the required type and has the
-     * required URI index and local name.  If the next
-     * element is not of the required type, push it back onto the buffer.
-     * @param eventType - the <tt>int</tt> event type.
-     * @param uriIndex - the <tt>int</tt> URI index.
-     * @param localName a <tt>String</tt> with the local name of the
-     * required element.
-     * @param discardWhiteSpace - if true, discard any <tt>characters</tt>
-     * events which contain only whitespace.
-     * @return an event of the required type.  If the next
-     * event detected is not of the required type, <tt>null</tt> is returned.
-     * The erroneous event is pushed back.
-     * @exception FOPException if buffer errors or interrupts occur.
-     * @exception NoSuchElementException if end of buffer detected.
-     */
-    public XmlEvent expectSaxUriLocalEvent
-                            (int eventType, int uriIndex,
-                                 String localName, boolean discardWhiteSpace)
-                throws FOPException
-    {
-        XmlEvent ev = getEvent();
-        if (discardWhiteSpace) {
-            while (ev != null && ev.type == XmlEvent.CHARACTERS
-                   && ev.chars.trim().equals("")) {
-                namespaces.surrenderEvent(ev);
-                ev = getEvent();
-            }
-        }
-        if (ev != null
-                && ev.type == eventType
-                   && ev.uriIndex == uriIndex
-                       && ev.localName.equals(localName)) {
-            return ev;
-        }
-        if (ev == null)
-            throw new NoSuchElementException
-                        (XmlEvent.eventTypeName(eventType)
-                                           + " not found: end of buffer.");
-        pushBack(ev);
-        return null;
-    }
-    
-    /**
-     * Return the next event if it is of the given SAX type, whose URI is
-     * matched by the namespaces URI indexed by <code>uriIndex</code>, and
-     * whose namespace-specific type matches <code>nsType</code>.
-     * If the next element is not of the required type,
-     * push it back onto the buffer.
-     * @param eventType the SAX event type
-     * @param uriIndex of the URI in namespaces
-     * @param nsType the namespace-specific type
-     * @param discardWhiteSpace - if true, discard any intervening
-     * <tt>characters</tt> events which contain only whitespace.
-     * @return an event of the required type.  If the next
-     * event detected is not of the required type, <tt>null</tt> is returned.
-     * The erroneous event is pushed back.
-     * @throws FOPException
-     */
-    public XmlEvent expectSaxUriTypedEvent(
-            int eventType, int uriIndex, int nsType,
-            boolean discardWhiteSpace)
-    throws FOPException {
-        XmlEvent ev = getEvent();
-        if (discardWhiteSpace) {
-            while (ev != null && ev.type == XmlEvent.CHARACTERS
-                    && ev.chars.trim().equals("")) {
-                namespaces.surrenderEvent(ev);
-                ev = getEvent();
-            }
-        }
-        if (ev != null && ev.type == eventType) {
-            switch (uriIndex) {
-            case Namespaces.DefAttrNSIndex:
-                throw new NoSuchElementException
-                ("No special types for default attribute namespace");
-            case Namespaces.XSLNSpaceIndex:
-                // The FO namespace
-                if (ev.getFoType() == nsType) {
-                    return ev;
-                }
-                break;
-            case Namespaces.FOXNSpaceIndex:
-                // The FOX namespace
-                if (ev.getFoxType() == nsType) {
-                    return ev;
-                }
-                break;
-            case Namespaces.SVGNSpaceIndex:
-                // The SVG namespace
-                if (ev.getSvgType() == nsType) {
-                    return ev;
-                }
-                break;
-            }
-        }
-        if (ev == null)
-            throw new NoSuchElementException
-            (XmlEvent.eventTypeName(eventType) + " "
-                    + namespaces.getIndexURI(uriIndex)
-                    + " type " + nsType + " not found.");
-        pushBack(ev);
-        return null;
-    }
-    
-    /**
-     * Return the next element if it is of the required type and has the
-     * required FO type.  If the next
-     * element is not of the required type, push it back onto the buffer.
-     * @param eventType - the <tt>int</tt> event type.
-     * @param foType - the <tt>int</tt> FO type.
-     * @param discardWhiteSpace - if true, discard any <tt>characters</tt>
-     * events which contain only whitespace.
-     * @return an event of the required type.  If the next
-     * event detected is not of the required type, <tt>null</tt> is returned.
-     * The erroneous event is pushed back.
-     * @exception FOPException if buffer errors or interrupts occur.
-     * @exception NoSuchElementException if end of buffer detected.
-     */
-    public XmlEvent expectSaxFoEvent
-                    (int eventType, int foType, boolean discardWhiteSpace)
-                throws FOPException
-    {
-        return expectSaxUriTypedEvent(
-                eventType, Namespaces.XSLNSpaceIndex,
-                foType, discardWhiteSpace);
-    }
-
-    /**
-     * Get the next ENDDOCUMENT event from the buffer.  Discard any other
-     * events preceding the ENDDOCUMENT event.
-     * @return an ENDDOCUMENT event
-     * @exception FOPException if buffer errors or interrupts occur
-     * @exception NoSuchElementException if the event is not found
-     */
-    public XmlEvent getEndDocument() throws FOPException {
-        return getSaxEvent(XmlEvent.ENDDOCUMENT);
-    }
-
-    /**
-     * Return the next element if it is an ENDDOCUMENT.  If the next
-     * element is not of the required type, push it back onto the buffer.
-     * @param discardWhiteSpace - if true, discard any <tt>characters</tt>
-     * events which contain only whitespace.
-     * @return an ENDDOCUMENT event. If the next
-     * event detected is not of the required type, <tt>null</tt> is returned.
-     * The erroneous event is pushed back.
-     * @exception FOPException if buffer errors or interrupts occur
-     * @exception NoSuchElementException if end of buffer detected.
-     */
-    public XmlEvent expectEndDocument(boolean discardWhiteSpace)
-                throws FOPException
-    {
-        return expectSaxEvent(XmlEvent.ENDDOCUMENT, discardWhiteSpace);
-    }
-
-    /**
-     * Get the next STARTELEMENT event from the buffer.  Discard any other
-     * events preceding the STARTELEMENT event.
-     * @return a STARTELEMENT event
-     * @exception FOPException if buffer errors or interrupts occur
-     * @exception NoSuchElementException if the event is not found
-     */
-    public XmlEvent getStartElement() throws FOPException {
-        return getSaxEvent(XmlEvent.STARTELEMENT);
-    }
-
-    /**
-     * Return the next element if it is a STARTELEMENT.  If the next
-     * element is not of the required type, push it back onto the buffer.
-     * @param discardWhiteSpace - if true, discard any <tt>characters</tt>
-     * events which contain only whitespace.
-     * @return a STARTELEMENT event.  If the next
-     * event detected is not of the required type, <tt>null</tt> is returned.
-     * The erroneous event is pushed back.
-     * @exception FOPException if buffer errors or interrupts occur
-     * @exception NoSuchElementException if end of buffer detected.
-     */
-    public XmlEvent expectStartElement(boolean discardWhiteSpace)
-                throws FOPException
-    {
-        return expectSaxEvent(XmlEvent.STARTELEMENT, discardWhiteSpace);
-    }
-
-    /**
-     * Get the next STARTELEMENT event with the given URI index and local name
-     * from the buffer.  Discard any other events preceding the
-     * STARTELEMENT event.
-     * @param uriIndex an <tt>int</tt> with the index of the URI of the
-     * required URI
-     * @param localName a <tt>String</tt> 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 XmlEvent getStartElement(int uriIndex, String localName)
-        throws FOPException
-    {
-        return getSaxUriLocalEvent(XmlEvent.STARTELEMENT, uriIndex, localName);
-    }
-
-    /**
-     * Return the next element if it is a STARTELEMENT with the given
-     * URI index and local name.  If the next
-     * element is not of the required type, push it back onto the buffer.
-     * @param uriIndex an <tt>int</tt> URI index.
-     * @param localName a <tt>String</tt> with the local name of the
-     * required STARTELEMENT
-     * @param discardWhiteSpace - if true, discard any <tt>characters</tt>
-     * events which contain only whitespace.
-     * @return a STARTELEMENT event.  If the next
-     * event detected is not of the required type, <tt>null</tt> is returned.
-     * The erroneous event is pushed back.
-     * @exception FOPException if buffer errors or interrupts occur
-     * @exception NoSuchElementException if end of buffer detected.
-     */
-    public XmlEvent expectStartElement
-                (int uriIndex, String localName, boolean discardWhiteSpace)
-        throws FOPException
-    {
-        return expectSaxUriLocalEvent
-            (XmlEvent.STARTELEMENT, uriIndex, localName, discardWhiteSpace);
-    }
-
-    /**
-     * Get the next STARTELEMENT event with the given URI index and local name
-     * from the buffer.  Discard any other events preceding the
-     * STARTELEMENT event.
-     * @param uriIndex an <tt>int</tt> with the index of the URI of the
-     * required URI
-     * @param nsType the namespace-dependent event type
-     * @return a STARTELEMENT event
-     * @exception FOPException if buffer errors or interrupts occur
-     * @exception NoSuchElementException if the event is not found
-     */
-    public XmlEvent getStartElement(int uriIndex, int nsType)
-    throws FOPException
-    {
-        return getSaxUriTypedEvent(XmlEvent.STARTELEMENT, uriIndex, nsType);
-    }
-
-    /**
-     * Return the next element if it is a STARTELEMENT with the given
-     * URI index and local name.  If the next
-     * element is not of the required type, push it back onto the buffer.
-     * @param uriIndex an <tt>int</tt> URI index.
-     * @param nsType the namespace-dependent event type
-     * @param discardWhiteSpace - if true, discard any <tt>characters</tt>
-     * events which contain only whitespace.
-     * @return a STARTELEMENT event.  If the next
-     * event detected is not of the required type, <tt>null</tt> is returned.
-     * The erroneous event is pushed back.
-     * @exception FOPException if buffer errors or interrupts occur
-     * @exception NoSuchElementException if end of buffer detected.
-     */
-    public XmlEvent expectStartElement(
-            int uriIndex, int nsType, boolean discardWhiteSpace)
-    throws FOPException
-    {
-        return expectSaxUriTypedEvent(
-                XmlEvent.STARTELEMENT, uriIndex, nsType, discardWhiteSpace);
-    }
-    
-    /**
-     * From the buffer get the next STARTELEMENT event from the fo: namespace
-     * with the given FO object type.
-     *  Discard any other events preceding the
-     * STARTELEMENT event.
-     * @param foType - the <tt>int</tt> FO object type, as defined in
-     * <tt>FObjectNames</tt>.
-     * @return a matching STARTELEMENT event.
-     * @exception FOPException if buffer errors or interrupts occur
-     * @exception NoSuchElementException if the event is not found
-     */
-    public XmlEvent getStartElement(int foType)
-    throws FOPException
-    {
-        return getSaxFoEvent(XmlEvent.STARTELEMENT, foType);
-    }
-
-    /**
-     * From the buffer return the next STARTELEMENT event from the fo:
-     * namespace with the given FO object type.  If the next
-     * element is not of the required type, push it back onto the buffer.
-     * @param foType - the <tt>int</tt> FO object type, as defined in
-     * <tt>FObjectNames</tt>.
-     * @param discardWhiteSpace - if true, discard any <tt>characters</tt>
-     * events which contain only whitespace.
-     * @return a matching STARTELEMENT event.  If the next
-     * event detected is not of the required type, <tt>null</tt> is returned.
-     * The erroneous event is pushed back.
-     * @exception FOPException if buffer errors or interrupts occur
-     * @exception NoSuchElementException if end of buffer detected.
-     */
-    public XmlEvent expectStartElement
-    (int foType, boolean discardWhiteSpace)
-    throws FOPException
-    {
-        return expectSaxFoEvent(
-                XmlEvent.STARTELEMENT, foType, discardWhiteSpace);
-    }
-    
-    /**
-     * Get one of a list of possible STARTELEMENT events.
-     * @param list a <tt>LinkedList</tt> containing either <tt>String</tt>s
-     * with the <tt>QName</tt>, or <tt>UriLocalName</tt>
-     * objects with the URI index and local name of one of the required
-     * STARTELEMENT events.
-     * @param discardWhiteSpace - if true, discard any <tt>characters</tt>
-     * events which contain only whitespace.
-     * @return a STARTELEMENT event
-     * @exception FOPException if buffer errors or interrupts occur
-     * @exception NoSuchElementException if the event is not found
-     */
-    public XmlEvent getStartElement
-                                (LinkedList list, boolean discardWhiteSpace)
-        throws FOPException
-    {
-        XmlEvent ev;
-        do {
-            ev = expectStartElement(list, discardWhiteSpace);
-            if (ev != null) return ev;
-            // 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
-            // return null.
-            ev = getEvent();
-            namespaces.surrenderEvent(ev);
-        } 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 list a <tt>LinkedList</tt> containing either
-     * <tt>UriLocalName</tt> objects with the URI index and local name,
-     * <tt>NameSpaceType</tt> objects with the URI index and local name and
-     * a namespace-dependent <tt>int</tt> type, or <tt>Integer</tt>s with
-     * the FO type of one of the required STARTELEMENT events.
-     * @param discardWhiteSpace - if true, discard any <tt>characters</tt>
-     * events which contain only whitespace.
-     * @return a STARTELEMENT event.  If the next
-     * event detected is not of the required type, <tt>null</tt> is returned.
-     * The erroneous event is pushed back.
-     * @exception FOPException if buffer errors or interrupts occur
-     * @exception NoSuchElementException if end of buffer detected.
-     */
-    public XmlEvent expectStartElement
-                                (LinkedList list, boolean discardWhiteSpace)
-        throws FOPException
-    {
-        XmlEvent ev;
-        Iterator elements = list.iterator();
-        while (elements.hasNext()) {
-            Object o = elements.next();
-            if (o instanceof UriLocalName) {
-                if (o instanceof NameSpaceType) {
-                    NameSpaceType nameSpType = (NameSpaceType)o;
-                    ev = expectStartElement(
-                            nameSpType.uriIndex,
-                            nameSpType.nsType,
-                            discardWhiteSpace);
-                    // Found it!
-                    if (ev != null) return ev;
-                } else {
-                    UriLocalName uriLocalName = (UriLocalName)o;
-                    ev = expectStartElement
-                    (uriLocalName.uriIndex,
-                            uriLocalName.localName,
-                            discardWhiteSpace);
-                    // Found it!
-                    if (ev != null) return ev;
-                }
-            } else if (o instanceof Integer) {
-                ev = expectStartElement(((Integer)o).intValue(),
-                                        discardWhiteSpace);
-                if (ev != null) return ev;
-            } else
-                throw new FOPException
-                        ("Invalid list elements for getStartElement");
-        }
-        return null;
-    }
-
-    /**
-     * Get one of a array of possible STARTELEMENT events.  Scan and discard
-     * events until a STARTELEMENT event is found whose URI index and
-     * local name matches one of those in the argument
-     * <tt>UriLocalName[]</tt> array.
-     * @param list an array containing <tt>UriLocalName</tt>
-     * objects with the URI index and local name of
-     * @param discardWhiteSpace - if true, discard any <tt>characters</tt>
-     * events which contain only whitespace.
-     * STARTELEMENT events, one of which is required.
-     * @return the next matching STARTELEMENT event from the buffer.
-     * @exception FOPException if buffer errors or interrupts occur
-     * @exception NoSuchElementException if the event is not found
-     */
-    public XmlEvent getStartElement
-                    (UriLocalName[] list, boolean discardWhiteSpace)
-        throws FOPException
-    {
-        XmlEvent ev;
-        do {
-            ev = expectStartElement(list, discardWhiteSpace);
-            if (ev != null) return ev;
-            // 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();
-            namespaces.surrenderEvent(ev);
-        } while (ev != null);
-        // Exit from this while loop is only by discovery of null event
-        throw new NoSuchElementException
-                    ("StartElement from list not found.");
-    }
-
-    /**
-     * Expect one of an array of possible STARTELEMENT events.  The next
-     * STARTELEMENT must have a URI index and local name which match
-     * an element of the argument <tt>UriLocalName[]</tt> list.
-     * @param list an <tt>UriLocalName[]</tt> array containing the
-     * namespace Uri index and LocalName
-     * of possible events, one of which must be the next returned.
-     * @param discardWhiteSpace - if true, discard any <tt>characters</tt>
-     * events which contain only whitespace.
-     * @return the matching STARTELEMENT event. If the next
-     * event detected is not of the required type, <tt>null</tt> is returned.
-     * The erroneous event is pushed back.
-     * @exception FOPException if buffer errors or interrupts occur
-     * @exception NoSuchElementException if end of buffer detected.
-     */
-    public XmlEvent expectStartElement
-                    (UriLocalName[] list, boolean discardWhiteSpace)
-        throws FOPException
-    {
-        XmlEvent ev;
-        for (int i = 0; i < list.length; i++) {
-            ev = expectStartElement(list[i].uriIndex,
-                                    list[i].localName,
-                                    discardWhiteSpace);
-            // Found it!
-            if (ev != null) return ev;
-        }
-        return null;
-    }
-
-    /**
-     * Get one of a array of possible STARTELEMENT events.  Scan and discard
-     * events until a STARTELEMENT event is found which is in the fo:
-     * namespace and whose FO type matches one of those in the argument
-     * <tt>int</tt> array.
-     * @param list an <tt>int[]</tt> array containing FO types
-     * one of which is required.
-     * @param discardWhiteSpace - if true, discard any <tt>characters</tt>
-     * events which contain only whitespace.
-     * @return the next matching STARTELEMENT event from the buffer.
-     * @exception FOPException if buffer errors or interrupts occur
-     * @exception NoSuchElementException if the event is not found
-     */
-    public XmlEvent getStartElement(int[] list, boolean discardWhiteSpace)
-        throws FOPException
-    {
-        XmlEvent ev;
-        do {
-            ev = expectStartElement(list, discardWhiteSpace);
-            if (ev != null) return ev;
-            // 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();
-            namespaces.surrenderEvent(ev);
-        } while (ev != null);
-        // Exit from this while loop is only by discovery of null event
-        throw new NoSuchElementException
-                    ("StartElement from array not found.");
-    }
-
-    /**
-     * Expect one of an array of possible STARTELEMENT events.  The next
-     * STARTELEMENT must be in the fo: namespace, and must have an FO type
-     * which matches one of those in the argument <tt>int[]</tt> list.
-     * @param list a <tt>int[]</tt> array containing the FO types
-     * of possible events, one of which must be the next returned.
-     * @param discardWhiteSpace - if true, discard any <tt>characters</tt>
-     * events which contain only whitespace.
-     * @return the matching STARTELEMENT event.If the next
-     * event detected is not of the required type, <tt>null</tt> is returned.
-     * The erroneous event is pushed back.
-     * @exception FOPException if buffer errors or interrupts occur
-     * @exception NoSuchElementException if end of buffer detected.
-     */
-    public XmlEvent expectStartElement
-                                    (int[] list, boolean discardWhiteSpace)
-        throws FOPException
-    {
-        XmlEvent ev;
-        for (int i = 0; i < list.length; i++) {
-            ev = expectStartElement(list[i], discardWhiteSpace);
-            // Found it!
-            if (ev != null) return ev;
-        }
-        return null;
-    }
-
-    /**
-     * Get one of a <tt>BitSet</tt> of possible STARTELEMENT events.  Scan
-     * and discard events until a STARTELEMENT event is found which is in
-     * the fo: namespace and whose FO type matches one of those in the
-     * argument <tt>BitSet</tt>.
-     * @param set a <tt>BitSet</tt> containing FO types one of which is
-     * required.
-     * @param discardWhiteSpace - if true, discard any <tt>characters</tt>
-     * events which contain only whitespace.
-     * @return the next matching STARTELEMENT event from the buffer.
-     * @exception FOPException if buffer errors or interrupts occur
-     * @exception NoSuchElementException if the event is not found
-     */
-    public XmlEvent getStartElement(BitSet set, boolean discardWhiteSpace)
-        throws FOPException
-    {
-        XmlEvent ev;
-        do {
-            try {
-                ev = expectStartElement(set, discardWhiteSpace);
-                if (ev != null) return ev;
-                // 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();
-                namespaces.surrenderEvent(ev);
-            } catch(UnexpectedStartElementException e) {
-                ev = getEvent();
-                namespaces.surrenderEvent(ev);
-            }
-        } while (ev != null);
-        // Exit from this while loop is only by discovery of null event
-        throw new NoSuchElementException
-                    ("StartElement from BitSet not found.");
-    }
-
-    /**
-     * Expect one of an <tt>BitSet</tt> of possible STARTELEMENT events.
-     * The next STARTELEMENT must be in the fo: namespace, and must have an
-     * FO type which matches one of those in the argument <tt>BitSet</tt>.
-     * <p>TODO:<br>
-     * This method should be retro-fitted to list and array versions.
-     *
-     * @param set a <tt>BitSet</tt> containing the FO types
-     * of possible events, one of which must be the next returned.
-     * @param discardWhiteSpace - if true, discard any <tt>characters</tt>
-     * events which contain only whitespace.
-     * @return the matching STARTELEMENT event.If the next
-     * event detected is not of the required type, <tt>null</tt> is returned.
-     * The erroneous event is pushed back.
-     * @exception FOPException if buffer errors or interrupts occur
-     * @exception NoSuchElementException if end of buffer detected.
-     */
-    public XmlEvent expectStartElement
-                                    (BitSet set, boolean discardWhiteSpace)
-        throws FOPException, UnexpectedStartElementException
-    {
-        XmlEvent ev;
-        ev = expectSaxEvent(XmlEvent.STARTELEMENT, discardWhiteSpace);
-        if (ev == null) return ev;
-
-        for (int i = set.nextSetBit(0); i >= 0; i = set.nextSetBit(++i)) {
-            if (ev.getFoType() == i)
-                return ev; // Found it!
-        }
-        // Not found - push the STARTELEMENT event back and throw an
-        // UnexpectedStartElementException
-        pushBack(ev);
-        throw new UnexpectedStartElementException
-                ("Unexpected START element: " + ev.getQName());
-    }
-
-    /**
-     * Expect that the next element will be a STARTELEMENT for one of the
-     * flow objects which are members of %block; from
-     * <b>6.2 Formatting Object Content</b>, including out-of-line flow
-     * objects which may occur except as descendents of out-of-line formatting
-     * objects.  White space is discarded.
-     * @return the <tt>XmlEvent found. If any other events are encountered
-     * return <tt>null</tt>.
-     */
-    public XmlEvent expectBlock()
-        throws FOPException, UnexpectedStartElementException
-    {
-        return expectStartElement
-                (FObjectSets.blockEntity, XmlEvent.DISCARD_W_SPACE);
-    }
-
-    /**
-     * Expect that the next element will be a STARTELEMENT for one of the
-     * flow objects which are members of %block; from
-     * <b>6.2 Formatting Object Content</b>, excluding out-of-line flow
-     * objects which may not occur as descendents of out-of-line formatting
-     * objects.  White space is discarded.
-     * @return the <tt>XmlEvent found. If any other events are encountered
-     * return <tt>null</tt>.
-     */
-    public XmlEvent expectOutOfLineBlock()
-        throws FOPException, UnexpectedStartElementException
-    {
-        return expectStartElement
-                (FObjectSets.outOfLineBlockSet, XmlEvent.DISCARD_W_SPACE);
-    }
-
-    /**
-     * Expect that the next element will be a STARTELEMENT for one of the
-     * flow objects which are members of (#PCDATA|%inline;) from
-     * <b>6.2 Formatting Object Content</b>, including out-of-line flow
-     * objects which may occur except as descendents of out-of-line
-     * formatting objects.  White space is retained, and
-     * will appear as #PCDATA, i.e, as an instance of FoCharacters.
-     * @return the <tt>XmlEvent found. If any other events are encountered
-     * return <tt>null</tt>.
-     */
-    public XmlEvent expectPcdataOrInline()
-        throws FOPException, UnexpectedStartElementException
-    {
-        XmlEvent ev = expectStartElement
-                (FObjectSets.normalPcdataInlineSet, XmlEvent.RETAIN_W_SPACE);
-        if (ev == null)
-            ev = expectCharacters();
-        return ev;
-    }
-
-    /**
-     * Expect that the next element will be a STARTELEMENT for one of the
-     * flow objects which are members of (#PCDATA|%inline;) from
-     * <b>6.2 Formatting Object Content</b>, excluding out-of-line flow
-     * objects which may not occur as descendents of out-of-line formatting
-     * objects.  White space is retained, and
-     * will appear as #PCDATA, i.e, as an instance of FoCharacters.
-     * @return the <tt>XmlEvent found. If any other events are encountered
-     * return <tt>null</tt>.
-     */
-    public XmlEvent expectOutOfLinePcdataOrInline()
-        throws FOPException, UnexpectedStartElementException
-    {
-        XmlEvent ev = expectStartElement
-                    (FObjectSets.inlineEntity, XmlEvent.RETAIN_W_SPACE);
-        if (ev == null)
-            ev = expectCharacters();
-        return ev;
-    }
-
-    /**
-     * Expect that the next element will be a STARTELEMENT for one of the
-     * flow objects which are members of (#PCDATA|%inline;|%block;) from
-     * <b>6.2 Formatting Object Content</b>, including out-of-line flow
-     * objects which may occur except as descendents of out-of-line
-     * formatting objects.  White space is retained, and
-     * will appear as #PCDATA, i.e, as an instance of FoCharacters.
-     * @return the <tt>XmlEvent</tt> found. If any other events are
-     * encountered return <tt>null</tt>.
-     */
-    public XmlEvent expectPcdataOrInlineOrBlock()
-        throws FOPException, UnexpectedStartElementException
-    {
-        XmlEvent ev = expectStartElement
-            (FObjectSets.normalPcdataBlockInlineSet, XmlEvent.RETAIN_W_SPACE);
-        if (ev == null)
-            ev = expectCharacters();
-        return ev;
-    }
-
-    /**
-     * Expect that the next element will be a STARTELEMENT for one of the
-     * flow objects which are members of (#PCDATA|%inline;|%block;) from
-     * <b>6.2 Formatting Object Content</b>, excluding out-of-line flow
-     * objects which may not occur as descendents of out-of-line formatting
-     * objects.  White space is retained, and
-     * will appear as #PCDATA, i.e, as an instance of FoCharacters.
-     * @return the <tt>XmlEvent</tt> found. If any other events are
-     * encountered return <tt>null</tt>.
-     */
-    public XmlEvent expectOutOfLinePcdataOrInlineOrBlock()
-        throws FOPException, UnexpectedStartElementException
-    {
-        XmlEvent ev = expectStartElement
-            (FObjectSets.outOfLinePcdataBlockInlineSet,
-                                                     XmlEvent.RETAIN_W_SPACE);
-        if (ev == null)
-            ev = expectCharacters();
-        return ev;
-    }
-
-    /**
-     * Get the next ENDELEMENT event from the buffer.  Discard any other
-     * events preceding the ENDELEMENT event.
-     * @return an ENDELEMENT event
-     * @exception FOPException if buffer errors or interrupts occur
-     * @exception NoSuchElementException if the event is not found
-     */
-    public XmlEvent getEndElement() throws FOPException {
-        return getSaxEvent(XmlEvent.ENDELEMENT);
-    }
-
-    /**
-     * Return the next element if it is an ENDELEMENT.  If the next
-     * element is not of the required type, push it back onto the buffer.
-     * @param discardWhiteSpace - if true, discard any <tt>characters</tt>
-     * events which contain only whitespace.
-     * @return a matching ENDELEMENT event.  If the next
-     * event detected is not of the required type, <tt>null</tt> is returned.
-     * The erroneous event is pushed back.
-     * @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 XmlEvent expectEndElement(boolean discardWhiteSpace)
-                throws FOPException
-    {
-        return expectSaxEvent(XmlEvent.ENDELEMENT, discardWhiteSpace);
-    }
-
-    /**
-     * Get the next ENDELEMENT event with the given <tt>QName</tt>
-     * from the buffer.  Discard any other events preceding the
-     * ENDELEMENT event.
-     * @param qName a <tt>String</tt> with the <tt>QName</tt> 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 XmlEvent getEndElement(String qName) throws FOPException
-    {
-        return getSaxQNameEvent(XmlEvent.ENDELEMENT, qName);
-    }
-
-    /**
-     * Get the next ENDELEMENT event with the given URI index and local name
-     * from the buffer.  Discard any other events preceding the
-     * ENDELEMENT event.
-     * @param uriIndex an <tt>int</tt> with the index of the URI of the
-     * required URI
-     * @param localName a <tt>String</tt> with the local name of the
-     * required ENDELEMENT
-     * @return an ENDELEMENT event
-     * @exception FOPException if buffer errors or interrupts occur
-     * @exception NoSuchElementException if the event is not found
-     */
-    public XmlEvent getEndElement(int uriIndex, String localName)
-        throws FOPException
-    {
-        return getSaxUriLocalEvent(XmlEvent.ENDELEMENT, uriIndex, localName);
-    }
-
-    /**
-     * Return the next element if it is an ENDELEMENT with the given
-     * URI index and local name.  If the next
-     * element is not of the required type, push it back onto the buffer.
-     * @param uriIndex an <tt>int</tt> with the index of the URI of the
-     * required URI
-     * @param localName a <tt>String</tt> with the local name of the
-     * required ENDELEMENT
-     * @param discardWhiteSpace - if true, discard any <tt>characters</tt>
-     * events which contain only whitespace.
-     * @return a matching ENDELEMENT event.
-     * If the next
-     * event detected is not an ENDELEMENT, <tt>null</tt> is returned.
-     * The erroneous event is pushed back.
-     * @exception FOPException if buffer errors or interrupts occur
-     * @exception NoSuchElementException if end of buffer detected.
-     */
-    public XmlEvent expectEndElement
-                (int uriIndex, String localName, boolean discardWhiteSpace)
-        throws FOPException
-    {
-        return expectSaxUriLocalEvent
-                (XmlEvent.ENDELEMENT, uriIndex, localName, discardWhiteSpace);
-    }
-
-    /**
-     * Get the next ENDELEMENT event with the given Fo type
-     * from the buffer.  Discard any other events preceding the
-     * ENDELEMENT event.
-     * @param foType - the FO type of the required ENDELEMENT
-     * @return a matching ENDELEMENT event.
-     * @exception FOPException if buffer errors or interrupts occur
-     * @exception NoSuchElementException if the event is not found
-     */
-    public XmlEvent getEndElement(int foType) throws FOPException
-    {
-        return getSaxFoEvent(XmlEvent.ENDELEMENT, foType);
-    }
-
-    /**
-     * Return the next element if it is an ENDELEMENT with the given
-     * FO type.  If the next
-     * element is not of the required type, push it back onto the buffer.
-     * @param foType - the FO type of the required ENDELEMENT
-     * @param discardWhiteSpace - if true, discard any <tt>characters</tt>
-     * events which contain only whitespace.
-     * @return a matching ENDELEMENT.  If the next
-     * event detected is not an ENDELEMENT, <tt>null</tt> is returned.
-     * The erroneous event is pushed back.
-     * @exception FOPException if buffer errors or interrupts occur
-     * @exception NoSuchElementException if end of buffer detected.
-     */
-    public XmlEvent expectEndElement(int foType, boolean discardWhiteSpace)
-        throws FOPException
-    {
-        return expectSaxFoEvent
-                            (XmlEvent.ENDELEMENT, foType, discardWhiteSpace);
-    }
-
-    /**
-     * Get the next ENDELEMENT event, with the same URI index and local name
-     * as the <tt>XmlEvent</tt> argument, from the buffer.
-     * Discard any other events preceding the ENDELEMENT event.
-     * @param event an <tt>XmlEvent</tt>.  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 XmlEvent getEndElement(XmlEvent event) throws FOPException
-    {
-        int foType;
-        if ((foType = event.getFoType()) != FObjectNames.NO_FO)
-            return getSaxFoEvent(XmlEvent.ENDELEMENT, foType);
-        return getSaxUriLocalEvent
-                    (XmlEvent.ENDELEMENT, event.uriIndex, event.localName);
-    }
-
-    /**
-     * Return the next element if it is an ENDELEMENT with the same
-     * URI index and local name as the <tt>XmlEvent argument</tt>.  If the
-     * next element is not of the required type, push it back onto the buffer.
-     * @param event an <tt>XmlEvent</tt>.  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.
-     * @param discardWhiteSpace - if true, discard any <tt>characters</tt>
-     * events which contain only whitespace.
-     * @return a matching ENDELEMENT event.  If the next
-     * event detected is not an ENDELEMENT, <tt>null</tt> is returned.
-     * The erroneous event is pushed back.
-     * @exception FOPException if buffer errors or interrupts occur
-     * @exception NoSuchElementException if end of buffer detected.
-     */
-    public XmlEvent expectEndElement
-                                (XmlEvent event, boolean discardWhiteSpace)
-        throws FOPException
-    {
-        int foType;
-        if ((foType = event.getFoType()) != FObjectNames.NO_FO)
-            return expectSaxFoEvent
-                    (XmlEvent.ENDELEMENT, foType, discardWhiteSpace);
-        return expectSaxUriLocalEvent
-                (XmlEvent.ENDELEMENT, event.uriIndex, event.localName,
-                                                         discardWhiteSpace);
-    }
-
-    /**
-     * Get the next ENDELEMENT event, with the same URI index and local name
-     * as the <tt>XmlEvent</tt> argument, from the buffer.
-     * Discard any other events preceding the ENDELEMENT event.
-     * @param discardEvent the argument event may be discarded.
-     * @param event an <tt>XmlEvent</tt>.  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 XmlEvent getEndElement(boolean discardEvent, XmlEvent event)
-        throws FOPException
-    {
-        XmlEvent ev;
-        int foType;
-        if ((foType = event.getFoType()) != FObjectNames.NO_FO)
-            ev = getSaxFoEvent(XmlEvent.ENDELEMENT, foType);
-        else
-            ev = getSaxUriLocalEvent
-                    (XmlEvent.ENDELEMENT, event.uriIndex, event.localName);
-        if (discardEvent) {
-            //System.out.println("discardEvent");
-            namespaces.surrenderEvent(event);
-        }
-        return ev;
-    }
-
-    /**
-     * Return the next element if it is an ENDELEMENT with the same
-     * URI index and local name as the <tt>XmlEvent argument</tt>.  If the
-     * next element is not of the required type, push it back onto the buffer.
-     * @param discardEvent the argument event may be discarded.
-     * @param event an <tt>XmlEvent</tt>.  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.
-     * @param discardWhiteSpace - if true, discard any <tt>characters</tt>
-     * events which contain only whitespace.
-     * @return a matching ENDELEMENT event.  If the next
-     * event detected is not an ENDELEMENT, <tt>null</tt> is returned.
-     * The erroneous event is pushed back.
-     * @exception FOPException if buffer errors or interrupts occur
-     * @exception NoSuchElementException if end of buffer detected.
-     */
-    public XmlEvent expectEndElement
-        (boolean discardEvent, XmlEvent event, boolean discardWhiteSpace)
-        throws FOPException
-    {
-        XmlEvent ev;
-        int foType;
-        if ((foType = event.getFoType()) != FObjectNames.NO_FO)
-            ev = expectSaxFoEvent
-                    (XmlEvent.ENDELEMENT, foType, discardWhiteSpace);
-        else
-            ev = expectSaxUriLocalEvent
-                (XmlEvent.ENDELEMENT, event.uriIndex, event.localName,
-                                                         discardWhiteSpace);
-        if (discardEvent)
-            namespaces.surrenderEvent(event);
-        return ev;
-    }
-
-    /**
-     * @return a CHARACTERS event
-     * @exception FOPException if buffer errors or interrupts occur
-     * @exception NoSuchElementException if the event is not found
-     */
-    public XmlEvent getCharacters() throws FOPException {
-        XmlEvent ev = getEvent();
-        while (ev != null && ev.type != XmlEvent.CHARACTERS) {
-            namespaces.surrenderEvent(ev);
-            ev = getEvent();
-        }
-        if (ev == null) {
-            throw new NoSuchElementException("Characters not found.");
-        }
-        return ev;
-    }
-
-    /**
-     * @return a CHARACTERS event.  If the next event detected is not
-     * a CHARACTERS event, <tt>null</tt> is returned.
-     * The erroneous event is pushed back.
-     * @exception FOPException if buffer errors or interrupts occur
-     * @exception NoSuchElementException if end of buffer detected.
-     */
-    public XmlEvent expectCharacters() throws FOPException {
-        XmlEvent ev = getEvent();
-        if (ev != null && ev.type == XmlEvent.CHARACTERS) {
-            return ev;
-        }
-        pushBack(ev);
-        return null;
-    }
 
 }
diff --git a/src/java/org/apache/fop/xml/XmlEventReader.java b/src/java/org/apache/fop/xml/XmlEventReader.java
new file mode 100644 (file)
index 0000000..2582a9f
--- /dev/null
@@ -0,0 +1,1246 @@
+/*
+ * $Id$
+ * 
+ * 
+ * ============================================================================
+ *                   The Apache Software License, Version 1.1
+ * ============================================================================
+ * 
+ * Copyright (C) 1999-2004 The Apache Software Foundation. All rights reserved.
+ * 
+ * Redistribution and use in source and binary forms, with or without modifica-
+ * tion, are permitted provided that the following conditions are met:
+ * 
+ * 1. Redistributions of  source code must  retain the above copyright  notice,
+ *    this list of conditions and the following disclaimer.
+ * 
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ *    this list of conditions and the following disclaimer in the documentation
+ *    and/or other materials provided with the distribution.
+ * 
+ * 3. The end-user documentation included with the redistribution, if any, must
+ *    include  the following  acknowledgment:  "This product includes  software
+ *    developed  by the  Apache Software Foundation  (http://www.apache.org/)."
+ *    Alternately, this  acknowledgment may  appear in the software itself,  if
+ *    and wherever such third-party acknowledgments normally appear.
+ * 
+ * 4. The names "FOP" and  "Apache Software Foundation"  must not be used to
+ *    endorse  or promote  products derived  from this  software without  prior
+ *    written permission. For written permission, please contact
+ *    apache@apache.org.
+ * 
+ * 5. Products  derived from this software may not  be called "Apache", nor may
+ *    "Apache" appear  in their name,  without prior written permission  of the
+ *    Apache Software Foundation.
+ * 
+ * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
+ * FITNESS  FOR A PARTICULAR  PURPOSE ARE  DISCLAIMED.  IN NO  EVENT SHALL  THE
+ * APACHE SOFTWARE  FOUNDATION  OR ITS CONTRIBUTORS  BE LIABLE FOR  ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL,  EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLU-
+ * DING, BUT NOT LIMITED TO, PROCUREMENT  OF SUBSTITUTE GOODS OR SERVICES; LOSS
+ * OF USE, DATA, OR  PROFITS; OR BUSINESS  INTERRUPTION)  HOWEVER CAUSED AND ON
+ * ANY  THEORY OF LIABILITY,  WHETHER  IN CONTRACT,  STRICT LIABILITY,  OR TORT
+ * (INCLUDING  NEGLIGENCE OR  OTHERWISE) ARISING IN  ANY WAY OUT OF THE  USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ * 
+ * This software  consists of voluntary contributions made  by many individuals
+ * on  behalf of the Apache Software  Foundation and was  originally created by
+ * James Tauber <jtauber@jtauber.com>. For more  information on the Apache 
+ * Software Foundation, please see <http://www.apache.org/>.
+ */
+package org.apache.fop.xml;
+
+import java.util.BitSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.NoSuchElementException;
+
+import org.apache.fop.apps.FOPException;
+import org.apache.fop.fo.FObjectNames;
+import org.apache.fop.fo.FObjectSets;
+
+/**
+ * A synchronized circular buffer for XMLEvents.
+ * Extends SyncedCircularBuffer and implements XmlEventSource.
+ * 
+ * @see org.apache.fop.datastructs.SyncedCircularBuffer
+ * @see XmlEventSource
+ * @author <a href="mailto:pbwest@powerup.com.au">Peter B. West</a>
+ * @version $Revision$ $Name$
+ */
+public class XmlEventReader {
+
+    /**
+     * Constant for <i>discardEvent</i> field of
+     * <i>getEndElement(boolean discardEvent, XmlEvent(, boolean)).
+     */
+    public static final boolean DISCARD_EV = true,
+                                 RETAIN_EV = false;
+    
+    /**
+     * The event source for this reader
+     */
+    private XmlEventSource source;
+
+
+    /**
+     * Maintains an index of namespace URIs.  These can then be referred to
+     * by an <tt>int</tt> index.
+     */
+    private Namespaces namespaces;
+
+    /**
+     * @param namespaces
+     * @throws IllegalArgumentException
+     */
+    public XmlEventReader(XmlEventSource source, Namespaces namespaces) {
+        this.source = source;
+        this.namespaces = namespaces;
+    }
+
+    /**
+     * Get the <tt>Namespaces</tt> from this buffer.
+     * @return - the namespaces object.
+     */
+    public Namespaces getNamespaces() { return namespaces; }
+    
+    /**
+     * Get the next event of the given type from the buffer.  Discard
+     * intervening events.
+     * @param eventType - the <tt>int</tt> event type.
+     * @return an event of the given type.
+     * @exception FOPException if buffer errors or interrupts occur.
+     * @exception NoSuchElementException if the event is not found.
+     */
+    public XmlEvent getSaxEvent(int eventType) throws FOPException {
+        XmlEvent ev = source.getEvent();
+        while (ev != null && ev.type != eventType) {
+            ev = source.getEvent();
+        }
+        if (ev == null) {
+            throw new NoSuchElementException
+                        (XmlEvent.eventTypeName(eventType) + " not found.");
+        }
+        return ev;
+    }
+
+    /**
+     * Get the next event of the given type and with the given <tt>QName</tt>
+     * from the buffer.  Discard intervening events.
+     * @param eventType - the <tt>int</tt> event type.
+     * @param qName a <tt>String</tt> with the <tt>QName</tt> of the
+     * required element.
+     * @return an event of the given type.
+     * @exception FOPException if buffer errors or interrupts occur.
+     * @exception NoSuchElementException if the event is not found.
+     */
+    public XmlEvent getSaxQNameEvent(int eventType, String qName)
+                throws FOPException
+    {
+        XmlEvent ev = source.getEvent();
+        while (ev != null &&
+               ! (ev.type == eventType && ev.qName.equals(qName))) {
+            ev = source.getEvent();
+        }
+        if (ev == null) {
+            throw new NoSuchElementException
+            (XmlEvent.eventTypeName(eventType) + " " + qName + " not found.");
+        }
+        return ev;
+    }
+
+    /**
+     * Get the next event of the given SAX type, from the given namespace
+     * (<code>uriIndex</code>) with the given local name, from the buffer.
+     * Discard intervening events.
+     * @param eventType the SAX event type.
+     * @param uriIndex the URI index maintained in the
+     * <tt>Namespaces</tt> object.
+     * @param localName of the required element.
+     * @return an event of the given type.
+     * @exception FOPException if buffer errors or interrupts occur.
+     * @exception NoSuchElementException if the event is not found.
+     */
+    public XmlEvent getSaxUriLocalEvent
+                            (int eventType, int uriIndex, String localName)
+                throws FOPException
+    {
+        XmlEvent ev = source.getEvent();
+        while (ev != null &&
+               ! (ev.type == eventType
+                  && ev.uriIndex == uriIndex
+                  && ev.localName.equals(localName))) {
+            namespaces.relinquishEvent(ev);
+            ev = source.getEvent();
+        }
+        if (ev == null)
+            throw new NoSuchElementException
+                    (XmlEvent.eventTypeName(eventType)
+                             + namespaces.getIndexURI(uriIndex)
+                                       + ":" + localName + " not found.");
+        return ev;
+    }
+    
+    /**
+     * Get the next event with of the given SAX type, whose URI is matched
+     * by the namespaces URI indexed by <code>uriIndex</code>, and whose
+     * namespace-specific type matches <code>nsType</code>.
+     * Discard any intervening events.
+     * @param eventType the SAX event type
+     * @param uriIndex of the URI in namespaces
+     * @param nsType the namespace-specific type
+     * @return the matching event
+     * @throws FOPException
+     */
+    public XmlEvent getSaxUriTypedEvent(
+            int eventType, int uriIndex, int nsType) throws FOPException {
+        XmlEvent ev = source.getEvent();
+        while (ev != null) {
+            if (ev.type == eventType && ev.uriIndex == uriIndex) {
+                switch (uriIndex) {
+                case Namespaces.DefAttrNSIndex:
+                    throw new NoSuchElementException
+                    ("No special types for default attribute namespace");
+                case Namespaces.XSLNSpaceIndex:
+                    // The FO namespace
+                    if (ev.getFoType() == nsType) {
+                        return ev;
+                    }
+                    break;
+                case Namespaces.FOXNSpaceIndex:
+                    // The FOX namespace
+                    if (ev.getFoxType() == nsType) {
+                        return ev;
+                    }
+                    break;
+                case Namespaces.SVGNSpaceIndex:
+                    // The SVG namespace
+                    if (ev.getSvgType() == nsType) {
+                        return ev;
+                    }
+                    break;
+                }
+            }
+            namespaces.relinquishEvent(ev);
+            ev = source.getEvent();
+        }
+        throw new NoSuchElementException
+            (XmlEvent.eventTypeName(eventType) + " "
+                    + namespaces.getIndexURI(uriIndex)
+                    + " type " + nsType + " not found.");
+    }
+
+    /**
+     * Get the next event of the given type, from the fo: namespace, with
+     * the given FO type.  Discard intervening events.
+     * @param eventType - the <tt>int</tt> event type.
+     * @param foType - the <tt>int</tt> FO type.
+     * @return an event of the given type.
+     * @exception FOPException if buffer errors or interrupts occur.
+     * @exception NoSuchElementException if the event is not found.
+     */
+    public XmlEvent getSaxFoEvent(int eventType, int foType)
+                throws FOPException
+    {
+        return getSaxUriTypedEvent(
+                eventType, Namespaces.XSLNSpaceIndex, foType);
+    }
+
+    /**
+     * Return the next element if it is of the required type.  If the next
+     * element is not of the required type, push it back onto the buffer.
+     * @param eventType - the <tt>int</tt> event type.
+     * @param discardWhiteSpace - if true, discard any <tt>characters</tt>
+     * events which contain only whitespace.
+     * @return an event of the required type.  If the next
+     * event detected is not of the required type, <tt>null</tt> is returned.
+     * The erroneous event is pushed back.
+     * @exception FOPException if buffer errors or interrupts occur.
+     * @exception NoSuchElementException if the buffer is empty.
+     */
+    public XmlEvent expectSaxEvent
+                                    (int eventType, boolean discardWhiteSpace)
+                throws FOPException
+    {
+        XmlEvent ev = source.getEvent();
+        if (discardWhiteSpace) {
+            while (ev != null && ev.type == XmlEvent.CHARACTERS
+                   && ev.chars.trim().equals("")) {
+                namespaces.relinquishEvent(ev);
+                ev = source.getEvent();
+            }
+        }
+        if (ev != null && ev.type == eventType) {
+            return ev;
+        }
+        if (ev == null)
+            throw new NoSuchElementException
+                        (XmlEvent.eventTypeName(eventType)
+                                           + " not found: end of buffer.");
+        source.pushBack(ev);
+        return null;
+    }
+
+    /**
+     * Return the next element if it is of the required type and has the
+     * required URI index and local name.  If the next
+     * element is not of the required type, push it back onto the buffer.
+     * @param eventType - the <tt>int</tt> event type.
+     * @param uriIndex - the <tt>int</tt> URI index.
+     * @param localName a <tt>String</tt> with the local name of the
+     * required element.
+     * @param discardWhiteSpace - if true, discard any <tt>characters</tt>
+     * events which contain only whitespace.
+     * @return an event of the required type.  If the next
+     * event detected is not of the required type, <tt>null</tt> is returned.
+     * The erroneous event is pushed back.
+     * @exception FOPException if buffer errors or interrupts occur.
+     * @exception NoSuchElementException if end of buffer detected.
+     */
+    public XmlEvent expectSaxUriLocalEvent
+                            (int eventType, int uriIndex,
+                                 String localName, boolean discardWhiteSpace)
+                throws FOPException
+    {
+        XmlEvent ev = source.getEvent();
+        if (discardWhiteSpace) {
+            while (ev != null && ev.type == XmlEvent.CHARACTERS
+                   && ev.chars.trim().equals("")) {
+                namespaces.relinquishEvent(ev);
+                ev = source.getEvent();
+            }
+        }
+        if (ev != null
+                && ev.type == eventType
+                   && ev.uriIndex == uriIndex
+                       && ev.localName.equals(localName)) {
+            return ev;
+        }
+        if (ev == null)
+            throw new NoSuchElementException
+                        (XmlEvent.eventTypeName(eventType)
+                                           + " not found: end of buffer.");
+        source.pushBack(ev);
+        return null;
+    }
+    
+    /**
+     * Return the next event if it is of the given SAX type, whose URI is
+     * matched by the namespaces URI indexed by <code>uriIndex</code>, and
+     * whose namespace-specific type matches <code>nsType</code>.
+     * If the next element is not of the required type,
+     * push it back onto the buffer.
+     * @param eventType the SAX event type
+     * @param uriIndex of the URI in namespaces
+     * @param nsType the namespace-specific type
+     * @param discardWhiteSpace - if true, discard any intervening
+     * <tt>characters</tt> events which contain only whitespace.
+     * @return an event of the required type.  If the next
+     * event detected is not of the required type, <tt>null</tt> is returned.
+     * The erroneous event is pushed back.
+     * @throws FOPException
+     */
+    public XmlEvent expectSaxUriTypedEvent(
+            int eventType, int uriIndex, int nsType,
+            boolean discardWhiteSpace)
+    throws FOPException {
+        XmlEvent ev = source.getEvent();
+        if (discardWhiteSpace) {
+            while (ev != null && ev.type == XmlEvent.CHARACTERS
+                    && ev.chars.trim().equals("")) {
+                namespaces.relinquishEvent(ev);
+                ev = source.getEvent();
+            }
+        }
+        if (ev != null && ev.type == eventType) {
+            switch (uriIndex) {
+            case Namespaces.DefAttrNSIndex:
+                throw new NoSuchElementException
+                ("No special types for default attribute namespace");
+            case Namespaces.XSLNSpaceIndex:
+                // The FO namespace
+                if (ev.getFoType() == nsType) {
+                    return ev;
+                }
+                break;
+            case Namespaces.FOXNSpaceIndex:
+                // The FOX namespace
+                if (ev.getFoxType() == nsType) {
+                    return ev;
+                }
+                break;
+            case Namespaces.SVGNSpaceIndex:
+                // The SVG namespace
+                if (ev.getSvgType() == nsType) {
+                    return ev;
+                }
+                break;
+            }
+        }
+        if (ev == null)
+            throw new NoSuchElementException
+            (XmlEvent.eventTypeName(eventType) + " "
+                    + namespaces.getIndexURI(uriIndex)
+                    + " type " + nsType + " not found.");
+        source.pushBack(ev);
+        return null;
+    }
+    
+    /**
+     * Return the next element if it is of the required type and has the
+     * required FO type.  If the next
+     * element is not of the required type, push it back onto the buffer.
+     * @param eventType - the <tt>int</tt> event type.
+     * @param foType - the <tt>int</tt> FO type.
+     * @param discardWhiteSpace - if true, discard any <tt>characters</tt>
+     * events which contain only whitespace.
+     * @return an event of the required type.  If the next
+     * event detected is not of the required type, <tt>null</tt> is returned.
+     * The erroneous event is pushed back.
+     * @exception FOPException if buffer errors or interrupts occur.
+     * @exception NoSuchElementException if end of buffer detected.
+     */
+    public XmlEvent expectSaxFoEvent
+                    (int eventType, int foType, boolean discardWhiteSpace)
+                throws FOPException
+    {
+        return expectSaxUriTypedEvent(
+                eventType, Namespaces.XSLNSpaceIndex,
+                foType, discardWhiteSpace);
+    }
+
+    /**
+     * Get the next ENDDOCUMENT event from the buffer.  Discard any other
+     * events preceding the ENDDOCUMENT event.
+     * @return an ENDDOCUMENT event
+     * @exception FOPException if buffer errors or interrupts occur
+     * @exception NoSuchElementException if the event is not found
+     */
+    public XmlEvent getEndDocument() throws FOPException {
+        return getSaxEvent(XmlEvent.ENDDOCUMENT);
+    }
+
+    /**
+     * Return the next element if it is an ENDDOCUMENT.  If the next
+     * element is not of the required type, push it back onto the buffer.
+     * @param discardWhiteSpace - if true, discard any <tt>characters</tt>
+     * events which contain only whitespace.
+     * @return an ENDDOCUMENT event. If the next
+     * event detected is not of the required type, <tt>null</tt> is returned.
+     * The erroneous event is pushed back.
+     * @exception FOPException if buffer errors or interrupts occur
+     * @exception NoSuchElementException if end of buffer detected.
+     */
+    public XmlEvent expectEndDocument(boolean discardWhiteSpace)
+                throws FOPException
+    {
+        return expectSaxEvent(XmlEvent.ENDDOCUMENT, discardWhiteSpace);
+    }
+
+    /**
+     * Get the next STARTELEMENT event from the buffer.  Discard any other
+     * events preceding the STARTELEMENT event.
+     * @return a STARTELEMENT event
+     * @exception FOPException if buffer errors or interrupts occur
+     * @exception NoSuchElementException if the event is not found
+     */
+    public XmlEvent getStartElement() throws FOPException {
+        return getSaxEvent(XmlEvent.STARTELEMENT);
+    }
+
+    /**
+     * Return the next element if it is a STARTELEMENT.  If the next
+     * element is not of the required type, push it back onto the buffer.
+     * @param discardWhiteSpace - if true, discard any <tt>characters</tt>
+     * events which contain only whitespace.
+     * @return a STARTELEMENT event.  If the next
+     * event detected is not of the required type, <tt>null</tt> is returned.
+     * The erroneous event is pushed back.
+     * @exception FOPException if buffer errors or interrupts occur
+     * @exception NoSuchElementException if end of buffer detected.
+     */
+    public XmlEvent expectStartElement(boolean discardWhiteSpace)
+                throws FOPException
+    {
+        return expectSaxEvent(XmlEvent.STARTELEMENT, discardWhiteSpace);
+    }
+
+    /**
+     * Get the next STARTELEMENT event with the given URI index and local name
+     * from the buffer.  Discard any other events preceding the
+     * STARTELEMENT event.
+     * @param uriIndex an <tt>int</tt> with the index of the URI of the
+     * required URI
+     * @param localName a <tt>String</tt> 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 XmlEvent getStartElement(int uriIndex, String localName)
+        throws FOPException
+    {
+        return getSaxUriLocalEvent(XmlEvent.STARTELEMENT, uriIndex, localName);
+    }
+
+    /**
+     * Return the next element if it is a STARTELEMENT with the given
+     * URI index and local name.  If the next
+     * element is not of the required type, push it back onto the buffer.
+     * @param uriIndex an <tt>int</tt> URI index.
+     * @param localName a <tt>String</tt> with the local name of the
+     * required STARTELEMENT
+     * @param discardWhiteSpace - if true, discard any <tt>characters</tt>
+     * events which contain only whitespace.
+     * @return a STARTELEMENT event.  If the next
+     * event detected is not of the required type, <tt>null</tt> is returned.
+     * The erroneous event is pushed back.
+     * @exception FOPException if buffer errors or interrupts occur
+     * @exception NoSuchElementException if end of buffer detected.
+     */
+    public XmlEvent expectStartElement
+                (int uriIndex, String localName, boolean discardWhiteSpace)
+        throws FOPException
+    {
+        return expectSaxUriLocalEvent
+            (XmlEvent.STARTELEMENT, uriIndex, localName, discardWhiteSpace);
+    }
+
+    /**
+     * Get the next STARTELEMENT event with the given URI index and local name
+     * from the buffer.  Discard any other events preceding the
+     * STARTELEMENT event.
+     * @param uriIndex an <tt>int</tt> with the index of the URI of the
+     * required URI
+     * @param nsType the namespace-dependent event type
+     * @return a STARTELEMENT event
+     * @exception FOPException if buffer errors or interrupts occur
+     * @exception NoSuchElementException if the event is not found
+     */
+    public XmlEvent getStartElement(int uriIndex, int nsType)
+    throws FOPException
+    {
+        return getSaxUriTypedEvent(XmlEvent.STARTELEMENT, uriIndex, nsType);
+    }
+
+    /**
+     * Return the next element if it is a STARTELEMENT with the given
+     * URI index and local name.  If the next
+     * element is not of the required type, push it back onto the buffer.
+     * @param uriIndex an <tt>int</tt> URI index.
+     * @param nsType the namespace-dependent event type
+     * @param discardWhiteSpace - if true, discard any <tt>characters</tt>
+     * events which contain only whitespace.
+     * @return a STARTELEMENT event.  If the next
+     * event detected is not of the required type, <tt>null</tt> is returned.
+     * The erroneous event is pushed back.
+     * @exception FOPException if buffer errors or interrupts occur
+     * @exception NoSuchElementException if end of buffer detected.
+     */
+    public XmlEvent expectStartElement(
+            int uriIndex, int nsType, boolean discardWhiteSpace)
+    throws FOPException
+    {
+        return expectSaxUriTypedEvent(
+                XmlEvent.STARTELEMENT, uriIndex, nsType, discardWhiteSpace);
+    }
+    
+    /**
+     * From the buffer get the next STARTELEMENT event from the fo: namespace
+     * with the given FO object type.
+     *  Discard any other events preceding the
+     * STARTELEMENT event.
+     * @param foType - the <tt>int</tt> FO object type, as defined in
+     * <tt>FObjectNames</tt>.
+     * @return a matching STARTELEMENT event.
+     * @exception FOPException if buffer errors or interrupts occur
+     * @exception NoSuchElementException if the event is not found
+     */
+    public XmlEvent getStartElement(int foType)
+    throws FOPException
+    {
+        return getSaxFoEvent(XmlEvent.STARTELEMENT, foType);
+    }
+
+    /**
+     * From the buffer return the next STARTELEMENT event from the fo:
+     * namespace with the given FO object type.  If the next
+     * element is not of the required type, push it back onto the buffer.
+     * @param foType - the <tt>int</tt> FO object type, as defined in
+     * <tt>FObjectNames</tt>.
+     * @param discardWhiteSpace - if true, discard any <tt>characters</tt>
+     * events which contain only whitespace.
+     * @return a matching STARTELEMENT event.  If the next
+     * event detected is not of the required type, <tt>null</tt> is returned.
+     * The erroneous event is pushed back.
+     * @exception FOPException if buffer errors or interrupts occur
+     * @exception NoSuchElementException if end of buffer detected.
+     */
+    public XmlEvent expectStartElement
+    (int foType, boolean discardWhiteSpace)
+    throws FOPException
+    {
+        return expectSaxFoEvent(
+                XmlEvent.STARTELEMENT, foType, discardWhiteSpace);
+    }
+    
+    /**
+     * Get one of a list of possible STARTELEMENT events.
+     * @param list a <tt>LinkedList</tt> containing either <tt>String</tt>s
+     * with the <tt>QName</tt>, or <tt>UriLocalName</tt>
+     * objects with the URI index and local name of one of the required
+     * STARTELEMENT events.
+     * @param discardWhiteSpace - if true, discard any <tt>characters</tt>
+     * events which contain only whitespace.
+     * @return a STARTELEMENT event
+     * @exception FOPException if buffer errors or interrupts occur
+     * @exception NoSuchElementException if the event is not found
+     */
+    public XmlEvent getStartElement
+                                (LinkedList list, boolean discardWhiteSpace)
+        throws FOPException
+    {
+        XmlEvent ev;
+        do {
+            ev = expectStartElement(list, discardWhiteSpace);
+            if (ev != null) return ev;
+            // The non-matching event has been pushed back.
+            // Get it and discard.  Note that if the first attempt to
+            // source.getEvent() returns null, the expectStartElement() calls
+            // return null.
+            ev = source.getEvent();
+            namespaces.relinquishEvent(ev);
+        } 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 list a <tt>LinkedList</tt> containing either
+     * <tt>UriLocalName</tt> objects with the URI index and local name,
+     * <tt>NameSpaceType</tt> objects with the URI index and local name and
+     * a namespace-dependent <tt>int</tt> type, or <tt>Integer</tt>s with
+     * the FO type of one of the required STARTELEMENT events.
+     * @param discardWhiteSpace - if true, discard any <tt>characters</tt>
+     * events which contain only whitespace.
+     * @return a STARTELEMENT event.  If the next
+     * event detected is not of the required type, <tt>null</tt> is returned.
+     * The erroneous event is pushed back.
+     * @exception FOPException if buffer errors or interrupts occur
+     * @exception NoSuchElementException if end of buffer detected.
+     */
+    public XmlEvent expectStartElement
+                                (LinkedList list, boolean discardWhiteSpace)
+        throws FOPException
+    {
+        XmlEvent ev;
+        Iterator elements = list.iterator();
+        while (elements.hasNext()) {
+            Object o = elements.next();
+            if (o instanceof UriLocalName) {
+                if (o instanceof NameSpaceType) {
+                    NameSpaceType nameSpType = (NameSpaceType)o;
+                    ev = expectStartElement(
+                            nameSpType.uriIndex,
+                            nameSpType.nsType,
+                            discardWhiteSpace);
+                    // Found it!
+                    if (ev != null) return ev;
+                } else {
+                    UriLocalName uriLocalName = (UriLocalName)o;
+                    ev = expectStartElement
+                    (uriLocalName.uriIndex,
+                            uriLocalName.localName,
+                            discardWhiteSpace);
+                    // Found it!
+                    if (ev != null) return ev;
+                }
+            } else if (o instanceof Integer) {
+                ev = expectStartElement(((Integer)o).intValue(),
+                                        discardWhiteSpace);
+                if (ev != null) return ev;
+            } else
+                throw new FOPException
+                        ("Invalid list elements for getStartElement");
+        }
+        return null;
+    }
+
+    /**
+     * Get one of a array of possible STARTELEMENT events.  Scan and discard
+     * events until a STARTELEMENT event is found whose URI index and
+     * local name matches one of those in the argument
+     * <tt>UriLocalName[]</tt> array.
+     * @param list an array containing <tt>UriLocalName</tt>
+     * objects with the URI index and local name of
+     * @param discardWhiteSpace - if true, discard any <tt>characters</tt>
+     * events which contain only whitespace.
+     * STARTELEMENT events, one of which is required.
+     * @return the next matching STARTELEMENT event from the buffer.
+     * @exception FOPException if buffer errors or interrupts occur
+     * @exception NoSuchElementException if the event is not found
+     */
+    public XmlEvent getStartElement
+                    (UriLocalName[] list, boolean discardWhiteSpace)
+        throws FOPException
+    {
+        XmlEvent ev;
+        do {
+            ev = expectStartElement(list, discardWhiteSpace);
+            if (ev != null) return ev;
+            // The non-matching event has been pushed back.
+            // Get it and discard.  Note that if the first attempt to
+            // source.getEvent() returns null, the expectStartElement() calls
+            // will throw a NoSuchElementException
+            ev = source.getEvent();
+            namespaces.relinquishEvent(ev);
+        } while (ev != null);
+        // Exit from this while loop is only by discovery of null event
+        throw new NoSuchElementException
+                    ("StartElement from list not found.");
+    }
+
+    /**
+     * Expect one of an array of possible STARTELEMENT events.  The next
+     * STARTELEMENT must have a URI index and local name which match
+     * an element of the argument <tt>UriLocalName[]</tt> list.
+     * @param list an <tt>UriLocalName[]</tt> array containing the
+     * namespace Uri index and LocalName
+     * of possible events, one of which must be the next returned.
+     * @param discardWhiteSpace - if true, discard any <tt>characters</tt>
+     * events which contain only whitespace.
+     * @return the matching STARTELEMENT event. If the next
+     * event detected is not of the required type, <tt>null</tt> is returned.
+     * The erroneous event is pushed back.
+     * @exception FOPException if buffer errors or interrupts occur
+     * @exception NoSuchElementException if end of buffer detected.
+     */
+    public XmlEvent expectStartElement
+                    (UriLocalName[] list, boolean discardWhiteSpace)
+        throws FOPException
+    {
+        XmlEvent ev;
+        for (int i = 0; i < list.length; i++) {
+            ev = expectStartElement(list[i].uriIndex,
+                                    list[i].localName,
+                                    discardWhiteSpace);
+            // Found it!
+            if (ev != null) return ev;
+        }
+        return null;
+    }
+
+    /**
+     * Get one of a array of possible STARTELEMENT events.  Scan and discard
+     * events until a STARTELEMENT event is found which is in the fo:
+     * namespace and whose FO type matches one of those in the argument
+     * <tt>int</tt> array.
+     * @param list an <tt>int[]</tt> array containing FO types
+     * one of which is required.
+     * @param discardWhiteSpace - if true, discard any <tt>characters</tt>
+     * events which contain only whitespace.
+     * @return the next matching STARTELEMENT event from the buffer.
+     * @exception FOPException if buffer errors or interrupts occur
+     * @exception NoSuchElementException if the event is not found
+     */
+    public XmlEvent getStartElement(int[] list, boolean discardWhiteSpace)
+        throws FOPException
+    {
+        XmlEvent ev;
+        do {
+            ev = expectStartElement(list, discardWhiteSpace);
+            if (ev != null) return ev;
+            // The non-matching event has been pushed back.
+            // Get it and discard.  Note that if the first attempt to
+            // source.getEvent() returns null, the expectStartElement() calls
+            // will throw a NoSuchElementException
+            ev = source.getEvent();
+            namespaces.relinquishEvent(ev);
+        } while (ev != null);
+        // Exit from this while loop is only by discovery of null event
+        throw new NoSuchElementException
+                    ("StartElement from array not found.");
+    }
+
+    /**
+     * Expect one of an array of possible STARTELEMENT events.  The next
+     * STARTELEMENT must be in the fo: namespace, and must have an FO type
+     * which matches one of those in the argument <tt>int[]</tt> list.
+     * @param list a <tt>int[]</tt> array containing the FO types
+     * of possible events, one of which must be the next returned.
+     * @param discardWhiteSpace - if true, discard any <tt>characters</tt>
+     * events which contain only whitespace.
+     * @return the matching STARTELEMENT event.If the next
+     * event detected is not of the required type, <tt>null</tt> is returned.
+     * The erroneous event is pushed back.
+     * @exception FOPException if buffer errors or interrupts occur
+     * @exception NoSuchElementException if end of buffer detected.
+     */
+    public XmlEvent expectStartElement
+                                    (int[] list, boolean discardWhiteSpace)
+        throws FOPException
+    {
+        XmlEvent ev;
+        for (int i = 0; i < list.length; i++) {
+            ev = expectStartElement(list[i], discardWhiteSpace);
+            // Found it!
+            if (ev != null) return ev;
+        }
+        return null;
+    }
+
+    /**
+     * Get one of a <tt>BitSet</tt> of possible STARTELEMENT events.  Scan
+     * and discard events until a STARTELEMENT event is found which is in
+     * the fo: namespace and whose FO type matches one of those in the
+     * argument <tt>BitSet</tt>.
+     * @param set a <tt>BitSet</tt> containing FO types one of which is
+     * required.
+     * @param discardWhiteSpace - if true, discard any <tt>characters</tt>
+     * events which contain only whitespace.
+     * @return the next matching STARTELEMENT event from the buffer.
+     * @exception FOPException if buffer errors or interrupts occur
+     * @exception NoSuchElementException if the event is not found
+     */
+    public XmlEvent getStartElement(BitSet set, boolean discardWhiteSpace)
+        throws FOPException
+    {
+        XmlEvent ev;
+        do {
+            try {
+                ev = expectStartElement(set, discardWhiteSpace);
+                if (ev != null) return ev;
+                // The non-matching event has been pushed back.
+                // Get it and discard.  Note that if the first attempt to
+                // source.getEvent() returns null, the expectStartElement() calls
+                // will throw a NoSuchElementException
+                ev = source.getEvent();
+                namespaces.relinquishEvent(ev);
+            } catch(UnexpectedStartElementException e) {
+                ev = source.getEvent();
+                namespaces.relinquishEvent(ev);
+            }
+        } while (ev != null);
+        // Exit from this while loop is only by discovery of null event
+        throw new NoSuchElementException
+                    ("StartElement from BitSet not found.");
+    }
+
+    /**
+     * Expect one of an <tt>BitSet</tt> of possible STARTELEMENT events.
+     * The next STARTELEMENT must be in the fo: namespace, and must have an
+     * FO type which matches one of those in the argument <tt>BitSet</tt>.
+     * <p>TODO:<br>
+     * This method should be retro-fitted to list and array versions.
+     *
+     * @param set a <tt>BitSet</tt> containing the FO types
+     * of possible events, one of which must be the next returned.
+     * @param discardWhiteSpace - if true, discard any <tt>characters</tt>
+     * events which contain only whitespace.
+     * @return the matching STARTELEMENT event.If the next
+     * event detected is not of the required type, <tt>null</tt> is returned.
+     * The erroneous event is pushed back.
+     * @exception FOPException if buffer errors or interrupts occur
+     * @exception NoSuchElementException if end of buffer detected.
+     */
+    public XmlEvent expectStartElement
+                                    (BitSet set, boolean discardWhiteSpace)
+        throws FOPException, UnexpectedStartElementException
+    {
+        XmlEvent ev;
+        ev = expectSaxEvent(XmlEvent.STARTELEMENT, discardWhiteSpace);
+        if (ev == null) return ev;
+
+        for (int i = set.nextSetBit(0); i >= 0; i = set.nextSetBit(++i)) {
+            if (ev.getFoType() == i)
+                return ev; // Found it!
+        }
+        // Not found - push the STARTELEMENT event back and throw an
+        // UnexpectedStartElementException
+        source.pushBack(ev);
+        throw new UnexpectedStartElementException
+                ("Unexpected START element: " + ev.getQName());
+    }
+
+    /**
+     * Expect that the next element will be a STARTELEMENT for one of the
+     * flow objects which are members of %block; from
+     * <b>6.2 Formatting Object Content</b>, including out-of-line flow
+     * objects which may occur except as descendents of out-of-line formatting
+     * objects.  White space is discarded.
+     * @return the <tt>XmlEvent found. If any other events are encountered
+     * return <tt>null</tt>.
+     */
+    public XmlEvent expectBlock()
+        throws FOPException, UnexpectedStartElementException
+    {
+        return expectStartElement
+                (FObjectSets.blockEntity, XmlEvent.DISCARD_W_SPACE);
+    }
+
+    /**
+     * Expect that the next element will be a STARTELEMENT for one of the
+     * flow objects which are members of %block; from
+     * <b>6.2 Formatting Object Content</b>, excluding out-of-line flow
+     * objects which may not occur as descendents of out-of-line formatting
+     * objects.  White space is discarded.
+     * @return the <tt>XmlEvent found. If any other events are encountered
+     * return <tt>null</tt>.
+     */
+    public XmlEvent expectOutOfLineBlock()
+        throws FOPException, UnexpectedStartElementException
+    {
+        return expectStartElement
+                (FObjectSets.outOfLineBlockSet, XmlEvent.DISCARD_W_SPACE);
+    }
+
+    /**
+     * Expect that the next element will be a STARTELEMENT for one of the
+     * flow objects which are members of (#PCDATA|%inline;) from
+     * <b>6.2 Formatting Object Content</b>, including out-of-line flow
+     * objects which may occur except as descendents of out-of-line
+     * formatting objects.  White space is retained, and
+     * will appear as #PCDATA, i.e, as an instance of FoCharacters.
+     * @return the <tt>XmlEvent found. If any other events are encountered
+     * return <tt>null</tt>.
+     */
+    public XmlEvent expectPcdataOrInline()
+        throws FOPException, UnexpectedStartElementException
+    {
+        XmlEvent ev = expectStartElement
+                (FObjectSets.normalPcdataInlineSet, XmlEvent.RETAIN_W_SPACE);
+        if (ev == null)
+            ev = expectCharacters();
+        return ev;
+    }
+
+    /**
+     * Expect that the next element will be a STARTELEMENT for one of the
+     * flow objects which are members of (#PCDATA|%inline;) from
+     * <b>6.2 Formatting Object Content</b>, excluding out-of-line flow
+     * objects which may not occur as descendents of out-of-line formatting
+     * objects.  White space is retained, and
+     * will appear as #PCDATA, i.e, as an instance of FoCharacters.
+     * @return the <tt>XmlEvent found. If any other events are encountered
+     * return <tt>null</tt>.
+     */
+    public XmlEvent expectOutOfLinePcdataOrInline()
+        throws FOPException, UnexpectedStartElementException
+    {
+        XmlEvent ev = expectStartElement
+                    (FObjectSets.inlineEntity, XmlEvent.RETAIN_W_SPACE);
+        if (ev == null)
+            ev = expectCharacters();
+        return ev;
+    }
+
+    /**
+     * Expect that the next element will be a STARTELEMENT for one of the
+     * flow objects which are members of (#PCDATA|%inline;|%block;) from
+     * <b>6.2 Formatting Object Content</b>, including out-of-line flow
+     * objects which may occur except as descendents of out-of-line
+     * formatting objects.  White space is retained, and
+     * will appear as #PCDATA, i.e, as an instance of FoCharacters.
+     * @return the <tt>XmlEvent</tt> found. If any other events are
+     * encountered return <tt>null</tt>.
+     */
+    public XmlEvent expectPcdataOrInlineOrBlock()
+        throws FOPException, UnexpectedStartElementException
+    {
+        XmlEvent ev = expectStartElement
+            (FObjectSets.normalPcdataBlockInlineSet, XmlEvent.RETAIN_W_SPACE);
+        if (ev == null)
+            ev = expectCharacters();
+        return ev;
+    }
+
+    /**
+     * Expect that the next element will be a STARTELEMENT for one of the
+     * flow objects which are members of (#PCDATA|%inline;|%block;) from
+     * <b>6.2 Formatting Object Content</b>, excluding out-of-line flow
+     * objects which may not occur as descendents of out-of-line formatting
+     * objects.  White space is retained, and
+     * will appear as #PCDATA, i.e, as an instance of FoCharacters.
+     * @return the <tt>XmlEvent</tt> found. If any other events are
+     * encountered return <tt>null</tt>.
+     */
+    public XmlEvent expectOutOfLinePcdataOrInlineOrBlock()
+        throws FOPException, UnexpectedStartElementException
+    {
+        XmlEvent ev = expectStartElement
+            (FObjectSets.outOfLinePcdataBlockInlineSet,
+                                                     XmlEvent.RETAIN_W_SPACE);
+        if (ev == null)
+            ev = expectCharacters();
+        return ev;
+    }
+
+    /**
+     * Get the next ENDELEMENT event from the buffer.  Discard any other
+     * events preceding the ENDELEMENT event.
+     * @return an ENDELEMENT event
+     * @exception FOPException if buffer errors or interrupts occur
+     * @exception NoSuchElementException if the event is not found
+     */
+    public XmlEvent getEndElement() throws FOPException {
+        return getSaxEvent(XmlEvent.ENDELEMENT);
+    }
+
+    /**
+     * Return the next element if it is an ENDELEMENT.  If the next
+     * element is not of the required type, push it back onto the buffer.
+     * @param discardWhiteSpace - if true, discard any <tt>characters</tt>
+     * events which contain only whitespace.
+     * @return a matching ENDELEMENT event.  If the next
+     * event detected is not of the required type, <tt>null</tt> is returned.
+     * The erroneous event is pushed back.
+     * @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 XmlEvent expectEndElement(boolean discardWhiteSpace)
+                throws FOPException
+    {
+        return expectSaxEvent(XmlEvent.ENDELEMENT, discardWhiteSpace);
+    }
+
+    /**
+     * Get the next ENDELEMENT event with the given <tt>QName</tt>
+     * from the buffer.  Discard any other events preceding the
+     * ENDELEMENT event.
+     * @param qName a <tt>String</tt> with the <tt>QName</tt> 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 XmlEvent getEndElement(String qName) throws FOPException
+    {
+        return getSaxQNameEvent(XmlEvent.ENDELEMENT, qName);
+    }
+
+    /**
+     * Get the next ENDELEMENT event with the given URI index and local name
+     * from the buffer.  Discard any other events preceding the
+     * ENDELEMENT event.
+     * @param uriIndex an <tt>int</tt> with the index of the URI of the
+     * required URI
+     * @param localName a <tt>String</tt> with the local name of the
+     * required ENDELEMENT
+     * @return an ENDELEMENT event
+     * @exception FOPException if buffer errors or interrupts occur
+     * @exception NoSuchElementException if the event is not found
+     */
+    public XmlEvent getEndElement(int uriIndex, String localName)
+        throws FOPException
+    {
+        return getSaxUriLocalEvent(XmlEvent.ENDELEMENT, uriIndex, localName);
+    }
+
+    /**
+     * Return the next element if it is an ENDELEMENT with the given
+     * URI index and local name.  If the next
+     * element is not of the required type, push it back onto the buffer.
+     * @param uriIndex an <tt>int</tt> with the index of the URI of the
+     * required URI
+     * @param localName a <tt>String</tt> with the local name of the
+     * required ENDELEMENT
+     * @param discardWhiteSpace - if true, discard any <tt>characters</tt>
+     * events which contain only whitespace.
+     * @return a matching ENDELEMENT event.
+     * If the next
+     * event detected is not an ENDELEMENT, <tt>null</tt> is returned.
+     * The erroneous event is pushed back.
+     * @exception FOPException if buffer errors or interrupts occur
+     * @exception NoSuchElementException if end of buffer detected.
+     */
+    public XmlEvent expectEndElement
+                (int uriIndex, String localName, boolean discardWhiteSpace)
+        throws FOPException
+    {
+        return expectSaxUriLocalEvent
+                (XmlEvent.ENDELEMENT, uriIndex, localName, discardWhiteSpace);
+    }
+
+    /**
+     * Get the next ENDELEMENT event with the given Fo type
+     * from the buffer.  Discard any other events preceding the
+     * ENDELEMENT event.
+     * @param foType - the FO type of the required ENDELEMENT
+     * @return a matching ENDELEMENT event.
+     * @exception FOPException if buffer errors or interrupts occur
+     * @exception NoSuchElementException if the event is not found
+     */
+    public XmlEvent getEndElement(int foType) throws FOPException
+    {
+        return getSaxFoEvent(XmlEvent.ENDELEMENT, foType);
+    }
+
+    /**
+     * Return the next element if it is an ENDELEMENT with the given
+     * FO type.  If the next
+     * element is not of the required type, push it back onto the buffer.
+     * @param foType - the FO type of the required ENDELEMENT
+     * @param discardWhiteSpace - if true, discard any <tt>characters</tt>
+     * events which contain only whitespace.
+     * @return a matching ENDELEMENT.  If the next
+     * event detected is not an ENDELEMENT, <tt>null</tt> is returned.
+     * The erroneous event is pushed back.
+     * @exception FOPException if buffer errors or interrupts occur
+     * @exception NoSuchElementException if end of buffer detected.
+     */
+    public XmlEvent expectEndElement(int foType, boolean discardWhiteSpace)
+        throws FOPException
+    {
+        return expectSaxFoEvent
+                            (XmlEvent.ENDELEMENT, foType, discardWhiteSpace);
+    }
+
+    /**
+     * Get the next ENDELEMENT event, with the same URI index and local name
+     * as the <tt>XmlEvent</tt> argument, from the buffer.
+     * Discard any other events preceding the ENDELEMENT event.
+     * @param event an <tt>XmlEvent</tt>.  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 XmlEvent getEndElement(XmlEvent event) throws FOPException
+    {
+        int foType;
+        if ((foType = event.getFoType()) != FObjectNames.NO_FO)
+            return getSaxFoEvent(XmlEvent.ENDELEMENT, foType);
+        return getSaxUriLocalEvent
+                    (XmlEvent.ENDELEMENT, event.uriIndex, event.localName);
+    }
+
+    /**
+     * Return the next element if it is an ENDELEMENT with the same
+     * URI index and local name as the <tt>XmlEvent argument</tt>.  If the
+     * next element is not of the required type, push it back onto the buffer.
+     * @param event an <tt>XmlEvent</tt>.  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.
+     * @param discardWhiteSpace - if true, discard any <tt>characters</tt>
+     * events which contain only whitespace.
+     * @return a matching ENDELEMENT event.  If the next
+     * event detected is not an ENDELEMENT, <tt>null</tt> is returned.
+     * The erroneous event is pushed back.
+     * @exception FOPException if buffer errors or interrupts occur
+     * @exception NoSuchElementException if end of buffer detected.
+     */
+    public XmlEvent expectEndElement
+                                (XmlEvent event, boolean discardWhiteSpace)
+        throws FOPException
+    {
+        int foType;
+        if ((foType = event.getFoType()) != FObjectNames.NO_FO)
+            return expectSaxFoEvent
+                    (XmlEvent.ENDELEMENT, foType, discardWhiteSpace);
+        return expectSaxUriLocalEvent
+                (XmlEvent.ENDELEMENT, event.uriIndex, event.localName,
+                                                         discardWhiteSpace);
+    }
+
+    /**
+     * Get the next ENDELEMENT event, with the same URI index and local name
+     * as the <tt>XmlEvent</tt> argument, from the buffer.
+     * Discard any other events preceding the ENDELEMENT event.
+     * @param discardEvent the argument event may be discarded.
+     * @param event an <tt>XmlEvent</tt>.  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 XmlEvent getEndElement(boolean discardEvent, XmlEvent event)
+        throws FOPException
+    {
+        XmlEvent ev;
+        int foType;
+        if ((foType = event.getFoType()) != FObjectNames.NO_FO)
+            ev = getSaxFoEvent(XmlEvent.ENDELEMENT, foType);
+        else
+            ev = getSaxUriLocalEvent
+                    (XmlEvent.ENDELEMENT, event.uriIndex, event.localName);
+        if (discardEvent) {
+            //System.out.println("discardEvent");
+            namespaces.relinquishEvent(event);
+        }
+        return ev;
+    }
+
+    /**
+     * Return the next element if it is an ENDELEMENT with the same
+     * URI index and local name as the <tt>XmlEvent argument</tt>.  If the
+     * next element is not of the required type, push it back onto the buffer.
+     * @param discardEvent the argument event may be discarded.
+     * @param event an <tt>XmlEvent</tt>.  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.
+     * @param discardWhiteSpace - if true, discard any <tt>characters</tt>
+     * events which contain only whitespace.
+     * @return a matching ENDELEMENT event.  If the next
+     * event detected is not an ENDELEMENT, <tt>null</tt> is returned.
+     * The erroneous event is pushed back.
+     * @exception FOPException if buffer errors or interrupts occur
+     * @exception NoSuchElementException if end of buffer detected.
+     */
+    public XmlEvent expectEndElement
+        (boolean discardEvent, XmlEvent event, boolean discardWhiteSpace)
+        throws FOPException
+    {
+        XmlEvent ev;
+        int foType;
+        if ((foType = event.getFoType()) != FObjectNames.NO_FO)
+            ev = expectSaxFoEvent
+                    (XmlEvent.ENDELEMENT, foType, discardWhiteSpace);
+        else
+            ev = expectSaxUriLocalEvent
+                (XmlEvent.ENDELEMENT, event.uriIndex, event.localName,
+                                                         discardWhiteSpace);
+        if (discardEvent)
+            namespaces.relinquishEvent(event);
+        return ev;
+    }
+
+    /**
+     * @return a CHARACTERS event
+     * @exception FOPException if buffer errors or interrupts occur
+     * @exception NoSuchElementException if the event is not found
+     */
+    public XmlEvent getCharacters() throws FOPException {
+        XmlEvent ev = source.getEvent();
+        while (ev != null && ev.type != XmlEvent.CHARACTERS) {
+            namespaces.relinquishEvent(ev);
+            ev = source.getEvent();
+        }
+        if (ev == null) {
+            throw new NoSuchElementException("Characters not found.");
+        }
+        return ev;
+    }
+
+    /**
+     * @return a CHARACTERS event.  If the next event detected is not
+     * a CHARACTERS event, <tt>null</tt> is returned.
+     * The erroneous event is pushed back.
+     * @exception FOPException if buffer errors or interrupts occur
+     * @exception NoSuchElementException if end of buffer detected.
+     */
+    public XmlEvent expectCharacters() throws FOPException {
+        XmlEvent ev = source.getEvent();
+        if (ev != null && ev.type == XmlEvent.CHARACTERS) {
+            return ev;
+        }
+        source.pushBack(ev);
+        return null;
+    }
+
+}