/* * Copyright 2001-2004 The Apache Software Foundation. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.fop.xml; import org.apache.fop.datastructs.SyncedCircularBuffer; import org.apache.fop.apps.FOPException; import org.apache.fop.fo.FObjectNames; import org.apache.fop.fo.FObjectSets; import org.apache.fop.xml.FoXMLEventPool; import java.util.NoSuchElementException; import java.util.LinkedList; import java.util.Iterator; import java.util.BitSet; /** * A synchronized circular buffer for FoXMLEvents. * @see org.apache.fop.datastructs.SyncedCircularBuffer * @author <a href="mailto:pbwest@powerup.com.au">Peter B. West</a> */ public class SyncedFoXmlEventsBuffer extends SyncedCircularBuffer { /** * Constant for <i>discardEvent</i> field of * <i>getEndElement(boolean discardEvent, FoXMLEvent(, 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. */ private XMLNamespaces namespaces; /** * The FoXMLEventPool for this buffer. */ private FoXMLEventPool pool; /** * No-argument constructor sets up a buffer with the default number of * elements. * The producer and consumer <tt>Thread</tt>s default to the current * thread at the time of instantiation. */ public SyncedFoXmlEventsBuffer() throws IllegalArgumentException { super(); namespaces = new XMLNamespaces(); pool = new FoXMLEventPool(namespaces, DEFAULTBUFSIZE); } /** * Constructor taking one argument; the size of the buffer. * @param size the size of the buffer. Must be > 1. */ public SyncedFoXmlEventsBuffer(int size) throws IllegalArgumentException { super(size); namespaces = new XMLNamespaces(); pool = new FoXMLEventPool(namespaces); } /** * Get the <tt>XMLNamespaces</tt> from this buffer. * @return - the namespaces object. */ public XMLNamespaces getNamespaces() { return namespaces; } /** * Get the <tt>FoXMLEventPool</tt> from this buffer. * @return - the pool object. */ public FoXMLEventPool getPool() { return pool; } /** * @return next event from the SyncedCircularBuffer * @exception FOPException. The purpose of this method is to catch * and transform any InterruptedException exceptions thrown by the * <tt>SyncedCircularBuffer</tt>. */ public FoXMLEvent getEvent() throws FOPException { FoXMLEvent ev; try { ev = (FoXMLEvent)get(); //System.out.println("getEvent: " + ev); return ev; } catch (InterruptedException e) { throw new FOPException(e); } } /** * 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 FoXMLEvent getTypedEvent(int eventType) throws FOPException { FoXMLEvent 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 FoXMLEvent getTypedEvent(int eventType, String qName) throws FOPException { FoXMLEvent 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 type, and with the given URI index and * local name, from the buffer. Discard intervening events. * @param eventType - the <tt>int</tt> event type. * @param uriIndex - the <tt>int</tt> URI index maintained in the * <tt>XMLNamespaces</tt> object. * @param localName a <tt>String</tt> with the local name 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 FoXMLEvent getTypedEvent (int eventType, int uriIndex, String localName) throws FOPException { FoXMLEvent ev = getEvent(); while (ev != null && ! (ev.type == eventType && ev.uriIndex == uriIndex && ev.localName.equals(localName))) { pool.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 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 FoXMLEvent getTypedEvent(int eventType, int foType) throws FOPException { FoXMLEvent ev = getEvent(); while (ev != null && ! (ev.type == eventType && ev.foType == foType)) { pool.surrenderEvent(ev); ev = getEvent(); } if (ev == null) throw new NoSuchElementException (XMLEvent.eventTypeName(eventType) + " FO type " + foType + " not found."); return ev; } /** * 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 FoXMLEvent expectTypedEvent (int eventType, boolean discardWhiteSpace) throws FOPException { FoXMLEvent ev = getEvent(); if (discardWhiteSpace) { while (ev != null && ev.type == XMLEvent.CHARACTERS && ev.chars.trim().equals("")) { pool.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 <tt>QName</tt>. 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 qName a <tt>String</tt> with the <tt>QName</tt> 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 the event is not found. */ public FoXMLEvent expectTypedEvent (int eventType, String qName, boolean discardWhiteSpace) throws FOPException { FoXMLEvent ev = getEvent(); if (discardWhiteSpace) { while (ev != null && ev.type == XMLEvent.CHARACTERS && ev.chars.trim().equals("")) { pool.surrenderEvent(ev); ev = getEvent(); } } if (ev != null && ev.type == eventType && ev.qName.equals(qName)) { 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 FoXMLEvent expectTypedEvent (int eventType, int uriIndex, String localName, boolean discardWhiteSpace) throws FOPException { FoXMLEvent ev = getEvent(); if (discardWhiteSpace) { while (ev != null && ev.type == XMLEvent.CHARACTERS && ev.chars.trim().equals("")) { pool.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 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 FoXMLEvent expectTypedEvent (int eventType, int foType, boolean discardWhiteSpace) throws FOPException { FoXMLEvent ev = getEvent(); if (discardWhiteSpace) { while (ev != null && ev.type == XMLEvent.CHARACTERS && ev.chars.trim().equals("")) { pool.surrenderEvent(ev); ev = getEvent(); } } if (ev != null && ev.type == eventType && ev.foType == foType) { return ev; } if (ev == null) throw new NoSuchElementException (XMLEvent.eventTypeName(eventType) + " not found: end of buffer."); pushBack(ev); return null; } /** * 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 FoXMLEvent getEndDocument() throws FOPException { return getTypedEvent(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 FoXMLEvent expectEndDocument(boolean discardWhiteSpace) throws FOPException { return expectTypedEvent(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 FoXMLEvent getStartElement() throws FOPException { return getTypedEvent(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 FoXMLEvent expectStartElement(boolean discardWhiteSpace) throws FOPException { return expectTypedEvent(XMLEvent.STARTELEMENT, discardWhiteSpace); } /** * Get the next STARTELEMENT event with the given <tt>QName</tt> * from the buffer. Discard any other events preceding the * STARTELEMENT event. * @param qName a <tt>String</tt> with the <tt>QName</tt> 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 FoXMLEvent getStartElement(String qName) throws FOPException { return getTypedEvent(XMLEvent.STARTELEMENT, qName); } /** * Return the next element if it is a STARTELEMENT with the given * <tt>QName</tt>. If the next * element is not of the required type, push it back onto the buffer. * @param qName a <tt>String</tt> with the <tt>QName</tt> 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 FoXMLEvent expectStartElement (String qName, boolean discardWhiteSpace) throws FOPException { return expectTypedEvent (XMLEvent.STARTELEMENT, qName, 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 FoXMLEvent getStartElement(int uriIndex, String localName) throws FOPException { return getTypedEvent(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 FoXMLEvent expectStartElement (int uriIndex, String localName, boolean discardWhiteSpace) throws FOPException { return expectTypedEvent (XMLEvent.STARTELEMENT, uriIndex, localName, 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 FoXMLEvent getStartElement(int foType) throws FOPException { return getTypedEvent(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 FoXMLEvent expectStartElement (int foType, boolean discardWhiteSpace) throws FOPException { return expectTypedEvent (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 FoXMLEvent getStartElement (LinkedList list, boolean discardWhiteSpace) throws FOPException { FoXMLEvent 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(); pool.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>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. 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 FoXMLEvent expectStartElement (LinkedList list, boolean discardWhiteSpace) throws FOPException { FoXMLEvent ev; Iterator elements = list.iterator(); while (elements.hasNext()) { Object o = elements.next(); if (o instanceof String) { ev = expectStartElement((String) o, discardWhiteSpace); // Found it! if (ev != null) return ev; } else if (o instanceof UriLocalName) { ev = expectStartElement (((UriLocalName) o).uriIndex, ((UriLocalName) o).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 FoXMLEvent getStartElement (UriLocalName[] list, boolean discardWhiteSpace) throws FOPException { FoXMLEvent 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(); pool.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 FoXMLEvent expectStartElement (UriLocalName[] list, boolean discardWhiteSpace) throws FOPException { FoXMLEvent 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 whose <tt>QName</tt> * matches one of those in the argument <tt>String[]</tt> array. * @param list a <tt>String[]</tt> array containing <tt>QName</tt>s, * 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 FoXMLEvent getStartElement(String[] list, boolean discardWhiteSpace) throws FOPException { FoXMLEvent 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(); pool.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 have a <tt>QName</tt> which matches an element * of the argument <tt>String[]</tt> list. * @param list a <tt>String[]</tt> array containing <tt>QName</tt>s * 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 FoXMLEvent expectStartElement (String[] list, boolean discardWhiteSpace) throws FOPException { FoXMLEvent 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 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 FoXMLEvent getStartElement(int[] list, boolean discardWhiteSpace) throws FOPException { FoXMLEvent 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(); pool.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 FoXMLEvent expectStartElement (int[] list, boolean discardWhiteSpace) throws FOPException { FoXMLEvent 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 FoXMLEvent getStartElement(BitSet set, boolean discardWhiteSpace) throws FOPException { FoXMLEvent 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(); pool.surrenderEvent(ev); } catch(UnexpectedStartElementException e) { ev = getEvent(); pool.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 FoXMLEvent expectStartElement (BitSet set, boolean discardWhiteSpace) throws FOPException, UnexpectedStartElementException { FoXMLEvent ev; ev = expectTypedEvent(XMLEvent.STARTELEMENT, discardWhiteSpace); if (ev == null) return ev; for (int i = set.nextSetBit(0); i >= 0; i = set.nextSetBit(++i)) { if (ev.foType == 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>FoXMLEvent found. If any other events are encountered * return <tt>null</tt>. */ public FoXMLEvent 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>FoXMLEvent found. If any other events are encountered * return <tt>null</tt>. */ public FoXMLEvent 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>FoXMLEvent found. If any other events are encountered * return <tt>null</tt>. */ public FoXMLEvent expectPcdataOrInline() throws FOPException, UnexpectedStartElementException { FoXMLEvent 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>FoXMLEvent found. If any other events are encountered * return <tt>null</tt>. */ public FoXMLEvent expectOutOfLinePcdataOrInline() throws FOPException, UnexpectedStartElementException { FoXMLEvent 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>FoXMLEvent</tt> found. If any other events are * encountered return <tt>null</tt>. */ public FoXMLEvent expectPcdataOrInlineOrBlock() throws FOPException, UnexpectedStartElementException { FoXMLEvent 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>FoXMLEvent</tt> found. If any other events are * encountered return <tt>null</tt>. */ public FoXMLEvent expectOutOfLinePcdataOrInlineOrBlock() throws FOPException, UnexpectedStartElementException { FoXMLEvent 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 FoXMLEvent getEndElement() throws FOPException { return getTypedEvent(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. * @exception NoSuchElementException if end of buffer detected. */ public FoXMLEvent expectEndElement(boolean discardWhiteSpace) throws FOPException { return expectTypedEvent(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 FoXMLEvent getEndElement(String qName) throws FOPException { return getTypedEvent(XMLEvent.ENDELEMENT, qName); } /** * Return the next element if it is an ENDELEMENT with the given * <tt>QName</tt>. If the next * element is not of the required type, push it back onto the buffer. * @param qName a <tt>String</tt> with the <tt>QName</tt> of the * required ENDELEMENT * @param discardWhiteSpace - if true, discard any <tt>characters</tt> * events which contain only whitespace. * @return an ENDELEMENT with the given qname. 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 FoXMLEvent expectEndElement(String qName, boolean discardWhiteSpace) throws FOPException { return expectTypedEvent(XMLEvent.ENDELEMENT, qName, discardWhiteSpace); } /** * 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 FoXMLEvent getEndElement(int uriIndex, String localName) throws FOPException { return getTypedEvent(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 FoXMLEvent expectEndElement (int uriIndex, String localName, boolean discardWhiteSpace) throws FOPException { return expectTypedEvent (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 FoXMLEvent getEndElement(int foType) throws FOPException { return getTypedEvent(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 FoXMLEvent expectEndElement(int foType, boolean discardWhiteSpace) throws FOPException { return expectTypedEvent (XMLEvent.ENDELEMENT, foType, discardWhiteSpace); } /** * Get the next ENDELEMENT event, with the same URI index and local name * as the <tt>FoXMLEvent</tt> argument, from the buffer. * Discard any other events preceding the ENDELEMENT event. * @param event an <tt>FoXMLEvent</tt>. Only the uriIndex and the * localName from the event are used. It is intended that the FoXMLEvent * 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 FoXMLEvent getEndElement(FoXMLEvent event) throws FOPException { if (event.foType != FObjectNames.NO_FO) return getTypedEvent(XMLEvent.ENDELEMENT, event.foType); return getTypedEvent (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>FoXMLEvent argument</tt>. If the * next element is not of the required type, push it back onto the buffer. * @param event an <tt>FoXMLEvent</tt>. Only the uriIndex and the * localName from the event are used. It is intended that the FoXMLEvent * 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 FoXMLEvent expectEndElement (FoXMLEvent event, boolean discardWhiteSpace) throws FOPException { if (event.foType != FObjectNames.NO_FO) return expectTypedEvent (XMLEvent.ENDELEMENT, event.foType, discardWhiteSpace); return expectTypedEvent (XMLEvent.ENDELEMENT, event.uriIndex, event.localName, discardWhiteSpace); } /** * Get the next ENDELEMENT event, with the same URI index and local name * as the <tt>FoXMLEvent</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>FoXMLEvent</tt>. Only the uriIndex and the * localName from the event are used. It is intended that the FoXMLEvent * 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 FoXMLEvent getEndElement(boolean discardEvent, FoXMLEvent event) throws FOPException { FoXMLEvent ev; if (event.foType != FObjectNames.NO_FO) ev = getTypedEvent(XMLEvent.ENDELEMENT, event.foType); else ev = getTypedEvent (XMLEvent.ENDELEMENT, event.uriIndex, event.localName); if (discardEvent) { //System.out.println("discardEvent"); pool.surrenderEvent(event); } return ev; } /** * Return the next element if it is an ENDELEMENT with the same * URI index and local name as the <tt>FoXMLEvent 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>FoXMLEvent</tt>. Only the uriIndex and the * localName from the event are used. It is intended that the FoXMLEvent * 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 FoXMLEvent expectEndElement (boolean discardEvent, FoXMLEvent event, boolean discardWhiteSpace) throws FOPException { FoXMLEvent ev; if (event.foType != FObjectNames.NO_FO) ev = expectTypedEvent (XMLEvent.ENDELEMENT, event.foType, discardWhiteSpace); else ev = expectTypedEvent (XMLEvent.ENDELEMENT, event.uriIndex, event.localName, discardWhiteSpace); if (discardEvent) pool.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 FoXMLEvent getCharacters() throws FOPException { FoXMLEvent ev = getEvent(); while (ev != null && ev.type != XMLEvent.CHARACTERS) { pool.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 FoXMLEvent expectCharacters() throws FOPException { FoXMLEvent ev = getEvent(); if (ev != null && ev.type == XMLEvent.CHARACTERS) { return ev; } pushBack(ev); return null; } }