/** * The BxmlStreamReader interface defines forward, read-only API to parse XML data structures * encoded as per the OGC Binary XML specification, in a "pull" fashion. *

* BxmlStreamReader is designed to iterate over BXML using next() and * hasNext(). This interface defines a cursor like API to iterate over XML * structured documents encoded as per the OGC Binary XML implementation specification. The API is * inspired by the StAX XML pull API and provides for querying element and attribute * contents stored as primitive or arrays of primitive data types. *

*

*

Query methods

* Some document metadata derived from the BXML header token and the XML declaration token, as well * as some state control may be safely queried at any time. For instance, the following methods * return such information: * *

*

*

Data access

* The data being parsed can be accessed using methods such as next(), * nextTag(), getElementName(), getValueCount() and * the various getValue() methods. *

*

* The {@link #next()} method causes the reader to read the next parse event. *

*

* The next() method returns an integer which identifies the type of event just read. The event type * can be determined using getEventType() *

*

* How to get the content of an element: The process of getting at the value of elements is * two-fold. First, the last call to {@code next()} and thus the current * {@link #getEventType() event type} shall returned one of {@link EventType#VALUE_BOOL VALUE_BOOL}, * {@link EventType#VALUE_BYTE VALUE_BYTE}, {@link EventType#VALUE_INT VALUE_INT}, * {@link EventType#VALUE_LONG VALUE_LONG}, {@link EventType#VALUE_FLOAT VALUE_FLOAT}, * {@link EventType#VALUE_DOUBLE VALUE_DOUBLE}, {@link EventType#VALUE_STRING VALUE_STRING}. Or, * what is the same, {@code getEventType().isValue == true}. *

*

* Then, the count of elements of that kind needs to be requested through {@link #getValueCount()}. * With that information at hand, the client code may use the appropriate * {@code getValue(type[], int, int)}, or a String representation of the value may be asked * directly through {@link #getStringValue()}. By using the {@code getValue()} methods client code * can be under control of memory resources. It is allowed to make multiple calls to a * {@code getValue()} method as long as the total requested length between the multiple calls does * not exceed the value count returned by {@code getValueCount()}. Also, it is allowed to call * {@code next()} before having consumed all the values in a value array. The reader shall just skip * to the next token. The same applies to the {@link #nextTag()} method, which can be called at any * time as long as the end of document has not been reached, to advance to the next start element or * end element event, whatever is found first. *

*

* Note the BXML specification only supports arrays of primitive types. *

* * @author Gabriel Roldan (TOPP) * @version $Id: BxmlStreamReader.java 465 2008-04-01 19:54:45Z groldan $ * @since 1.0 */ public interface BxmlStreamReader { /** * Derived property from the BXML file header, indicates whether the BXML document is marked as * standalone, as per the XML standalone definition. * * @return {@code true} if the document is standalone, {@code false} otherwise */ public boolean isStandalone(); /** * Derived property from the BXML file header, indicates whether the BXML document standalone * mark is set at all. * * @return {@code true} if the document standalone mark is explicitly set, {@code false} * otherwise */ public boolean standAloneIsSet(); /** * Returns whether the multi-byte primitive values (doubles, longs, etc) in the document are * encoded in little endian or big endian byte order. * * @return {@code true} if the document is little endian, {@code false} if its big endian. */ public boolean isLittleEndian(); /** * Returns whether this reader is namespace aware or not. * * @return {@code true} if this reader handles namespaces, {@code false otherwise} */ public boolean isNamespaceAware(); /** * Returns a flag set in the bxml document header that indicates if the document structure and * contents is already validated, with the aim of easying the task of parsers. * * @return {@code true} is the document is marked to be validated, {@code false} otherwise */ public boolean isValidated(); /** * Get the xml version declared on the xml declaration token, or {@code null} if none was * declared. * * @return the xml version or {@code null} if not declared. */ public String getXmlVersion(); /** * Derived property from the BXML file header, identifies the character-set encoding that is * used for all of the Strings in the file. * * @post {$return != null} * @return the charset used by the document */ public Charset getCharset(); /** * Frees any resource associated with this reader, including closing the underlying input stream * this reader fetches data from. *

* The first call to this method closes and releases resources. Subsequent calls shall take no * effect and return quitely. After the first call to this method any non query method (defined * as metadata retrieval methods in the class' javadoc) shall fail with an io exception. *

* * @throws IOException if an I/O error occurs closing this reader or the underlying input stream */ public void close() throws IOException; /** * Returns whether this stream reader and its underlying input source are open and able to * receive more parsing calls. *

* A {@code BxmlStreamReader} should be open since its creation until {@link #close()} was * explicitly called by client code, regardless of whether there are or not more parsing events * to process. *

* * @return {@code true} if this stream is still open, {@code false} otherwise */ public boolean isOpen(); /** * Returns whether there are more parsing events to be processed. * * @pre {isOpen() == true} * @post {$return == (getEventType() == END_DOCUMENT? false : true)} * @return {@code true} if there are more parsing events and {@code false} if there are no more * events (i.e. the trailer token has been reached, which is the same than the current * event being END_DOCUMENT). * @throws IOException if an I/O error occurs checking whether there are more parsing events to * process */ public boolean hasNext() throws IOException; /** * Advances the cursor to the next BXML token that has an {@link EventType} mapping and returns * the corresponding event type. *

* The first call to {@code next()} shall always return {@link EventType#START_DOCUMENT}. *

* * @pre {hasNext() == true} * @post {$return != null} * @post {$return == getEventType()} * @return the event corresponding to the parsing event the cursor advanced to * @throws IOException if an I/O error occurs checking whether there are more parsing events to * process * @see #getEventType() */ public EventType next() throws IOException; /** * Advances the cursor skipping any content until the first start or end element token is found. * * @pre {hasNext() == true} * @post {$return != null} * @post {$return == getEventType()} * @post {getEventType().isTag() == true} * @return the event type corresponding to the first START_ELEMENT or END_ELEMENT parse event * found * @throws IOException if an I/O exception is found while reading through the contents looking * for a tag token */ public EventType nextTag() throws IOException; /** * Returns the event type for the current position of the BXML reader cursor. *

* When a {@code BxmlStreamReader} is first created, the current event type is * {@link EventType#NONE NONE}. It is after the first call to {@code next()} when * {@code getEventType()} will return {@link EventType#START_DOCUMENT START_DOCUMENT}. *

* * @return the {@link EventType} returned by the last {@link #next()} call, or * {@link EventType#NONE} if the document did not started being parssed yet. */ public EventType getEventType(); /** * Returns the qualified name of the current element, being at a START_ELEMENT or END_ELEMENT * event *

* If this bxml reader is {@link #isNamespaceAware() namespace aware}, the returned name * contains both the attribute namespace uri, as well as the local name. The prefix shall be * included only if its present in the element name as it is in the file being parsed, to better * reflect the actual file format. *

*

* If this bxml reader is not namespace aware, the namespace and prefix in the returned * name are the {@link XMLConstants#NULL_NS_URI null namespace URI} and * {@link XMLConstants#DEFAULT_NS_PREFIX default namespace prefix}, as defined in the XML 1.0 * spec, and the {@code localName} field contains the element name as it is in the file being * parsed. *

* * @pre {getEventType().isTag() == true} * @post {$return != null} * @return the name of the current element */ public QName getElementName(); /** * Returns the count of attributes on this {@code START_ELEMENT} *

* This count excludes namespace definitions if this parser is * {@link #isNamespaceAware() namespace aware}. If the parser does not handle namespaces, * namespace definitions are returned as normal attributes. *

*

* Attribute indices are zero-based. *

* * @pre {getEventType() == START_ELEMENT} * @post {$return >= 0} * @return the number of attributes for the current start element tag or zero if there are no * declared attributes. */ public int getAttributeCount(); /** * Returns the qualified name of the attribute at the provided {@code index}, for the current * {@code START_ELEMENT} event *

* If this bxml reader is {@link #isNamespaceAware() namespace aware}, the returned name * contains both the attribute namespace uri, as well as the local name. The prefix shall be * included only if its present in the attribute name as it is in the file being parsed, to * better reflect the actual file format. *

*

* If this bxml reader is not namespace aware, the namespace and prefix in the returned * name are the {@link XMLConstants#NULL_NS_URI null namespace URI} and * {@link XMLConstants#DEFAULT_NS_PREFIX default namespace prefix}, as defined in the XML 1.0 * spec, and the {@code localName} field contains the element name as it is in the file being * parsed. *

*

* The attribute order reported by the {@code BxmlStreamReader} implementation shall be self * consistent between {@code getAttributeName} and {@code getAttributeValue}, though it might * not match the order in the bxml file being parsed. *

* * @pre {getEventType() == START_ELEMENT} * @pre {index >= 0} * @pre {index < getAttributeCount()} * @post {$return != null} * @param index zero based index for which to return the qualified name * @return the name of the attribute at index {@code index} * @see #getAttributeCount() */ public QName getAttributeName(int index); /** * Returns the coalesced value for the attribute at index {@code index} *

* NOTE in the binary xml file being parsed, the {@code AttributeStart} token from which an * attribute is parsed, may be followed by one or more value tokens. In case it is not followed * by any value token, the returned value for the attribute will be the empty string, not * {@code null}. In case it is followed by more than one value token, the returned attribute * value will be the concatenated string value from all the value tokens composing the attribute * value. The rules to transform a non string value to String are the same than for the * {@link #getStringValue()} method. *

* * @pre {getEventType() == START_ELEMENT} * @pre {index >= 0} * @pre {index < getAttributeCount()} * @post {$return != null} * @param index * @return the coalesced String representation of the attribute value, or the empty string if * the attribute has no value. */ public String getAttributeValue(int index); /** * Returns the normalized attribute value of the attribute with the namespace and localName If * the namespaceURI is null the namespace is not checked for equality * * @pre {getEventType() == START_ELEMENT} * @pre {localName != null} * @param namespaceURI the namespace of the attribute * @param localName the local name of the attribute, cannot be null * @return returns the value of the attribute , or {@code null} if not found */ public String getAttributeValue(String namespaceURI, String localName); /** * Returns the number of elements of the given value type that are directly available when a * value token was found. *

* If the current value type refers to a StringValue, {@code getValueCount} will return always * {@code 1}, since the spec does not defines the array of strings as a value element. * Otherwise, if the current value type is of a single primitive element, returns {@code 1}, * and if it is of an array of some primitive value type, returns the array length, which might * be any integer including zero. *

* * @pre {getEventType().isValue() == true} * @post {$return >= 0} * @return {@code 1} in case {@code getEventType() == VALUE_STRING}, as there are no arrays of * Strings, otherwise the number of elements of the primitive data type corresponding to * the current {@code VALUE_*} event type that are stored in the document for that value * token. * @see #getValueReadCount() */ public int getValueCount(); /** * Returns the number of elements of the current value event type that was already read. *

* This is useful to control the required value read count does not exceed the actual value * element count. *

* * @pre {getEventType().isValue() == true} * @post {$return <= getValueCount()} * @return the number of elements already read for the current value event * @see #getValueCount() */ public int getValueReadCount(); /** * Returns the String representation of the current value or comment token. *

* When the current value token represents an array of some primitive value, the content is * translated to String using the standard xml list type encoding. For example, the * double[]{1.0, 1.1, 2.2} array will be converted to the {@code "1.0 1.1 2.2"} * String before returning it. *

*

* NOTE calling this method implies parsing all the remaining elements for the current value * event, so it is not allowed to call other {@code getValue} or {@code getXXXValue} method * after this method returns, since the whole value event was consumed. *

* * @pre {getEventType().isValue() == true || getEventType() == {@link EventType#COMMENT}} * @post {$return != null} * @return the current value object, whether it is a single element or an array of some * primitive types, as a String. * @throws IOException if an I/O error occurs while reading the data */ public String getStringValue() throws IOException; /** * Being at a {@link EventType#VALUE_BOOL boolean value} event, reads {@code length} booleans * out of the underlying input stream and stores them in {@code dst}, starting at array index * {@code offset}. *

* This operation is semantically equivalent to calling {@link #getBooleanValue()} * {@code length} times, though its recommended for bulk reads as the implementation may perform * better. *

* * @pre {getEventType() == VALUE_BOOL} * @pre {dst != null} * @pre {offset >= 0} * @pre {length <= (dst.length - offset)} * @pre {getValueCount() - getValueReadCount() >= length} * @param dst the client supplied buffer where to store the read content * @param offset the zero based index at which to start storing the read content in {@code dst} * @param length the amount of elements to store in {@code dst} * @throws IOException if an I/O error occurs while reading the data * @see #getValueCount() */ public void getValue(boolean[] dst, int offset, int length) throws IOException; /** * Reads a single boolean value out of the underlying input stream. *

* Calls to this method may be interleaved with calls to {@link #getValue(boolean[], int, int)} * for the same VALUE_BOOL event, as long as the accumulated number of elements read does not * exceed the current {@link #getValueCount() value count}. *

* * @pre {getEventType() == VALUE_BOOL} * @pre {getValueReadCount() < getValueCount()} * @return the value read * @throws IOException if an I/O error occurs while reading the data * @see #getValueCount() * @see #getValueReadCount() * @see #getValue(boolean[], int, int) */ public boolean getBooleanValue() throws IOException; /** * Being at a {@link EventType#VALUE_BYTE byte value} event, reads {@code length} bytes out of * the underlying input stream and stores them in {@code dst}, starting at array index * {@code offset}. *

* This operation is semantically equivalent to calling {@link #getByteValue()} {@code length} * times, though its recommended for bulk reads as the implementation may perform better. *

* * @pre {getEventType() == VALUE_BYTE} * @pre {dst != null} * @pre {offset >= 0} * @pre {length <= (dst.length - offset)} * @pre {getValueCount() - getValueReadCount() >= length} * @param dst the client supplied buffer where to store the read content * @param offset the zero based index at which to start storing the read content in {@code dst} * @param length the amount of elements to store in {@code dst} * @throws IOException if an I/O error occurs while reading the data * @throws IllegalArgumentException if the accumulated read length for the current value event * exceeds the actual value length * @see #getValueCount() * @see #getValueReadCount() * @see #getBooleanValue() */ public void getValue(byte[] dst, int offset, int length) throws IOException; /** * Reads a single byte value out of the underlying input stream. *

* Calls to this method may be interleaved with calls to {@link #getValue(byte[], int, int)} for * the same VALUE_BYTE event, as long as the accumulated number of elements read does not exceed * the current {@link #getValueCount() value count}. *

* * @pre {getEventType() == VALUE_BYTE} * @pre {getValueReadCount() < getValueCount()} * @return the value read * @throws IOException if an I/O error occurs while reading the data * @see #getValueCount() * @see #getValueReadCount() * @see #getValue(byte[], int, int) */ public int getByteValue() throws IOException; /** * Being at a {@link EventType#VALUE_INT int value} event, reads {@code length} integers out of * the underlying input stream and stores them in {@code dst}, starting at array index * {@code offset}. *

* This operation is semantically equivalent to calling {@link #getIntValue()} {@code length} * times, though its recommended for bulk reads as the implementation may perform better. *

* * @pre {getEventType() == VALUE_INT} * @pre {dst != null} * @pre {offset >= 0} * @pre {length <= (dst.length - offset)} * @pre {getValueCount() - getValueReadCount() >= length} * @param dst the client supplied buffer where to store the read content * @param offset the zero based index at which to start storing the read content in {@code dst} * @param length the amount of elements to store in {@code dst} * @throws IOException if an I/O error occurs while reading the data * @throws IllegalArgumentException if the accumulated read length for the current value event * exceeds the actual value length * @see #getValueCount() * @see #getValueReadCount() * @see #getIntValue() */ public void getValue(int[] dst, int offset, int length) throws IOException; /** * Reads a single integer value out of the underlying input stream. *

* Calls to this method may be interleaved with calls to {@link #getValue(int[], int, int)} for * the same VALUE_INT event, as long as the accumulated number of elements read does not exceed * the current {@link #getValueCount() value count}. *

* * @pre {getEventType() == VALUE_INT} * @pre {getValueReadCount() < getValueCount()} * @return the value read * @throws IOException if an I/O error occurs while reading the data * @see #getValueCount() * @see #getValueReadCount() * @see #getValue(int[], int, int) */ public int getIntValue() throws IOException; /** * Being at a {@link EventType#VALUE_LONG long value} event, reads {@code length} longs out of * the underlying input stream and stores them in {@code dst}, starting at array index * {@code offset}. *

* This operation is semantically equivalent to calling {@link #getLongValue()} {@code length} * times, though its recommended for bulk reads as the implementation may perform better. *

* * @pre {getEventType() == VALUE_LONG} * @pre {dst != null} * @pre {offset >= 0} * @pre {length <= (dst.length - offset)} * @pre {getValueCount() - getValueReadCount() >= length} * @param dst the client supplied buffer where to store the read content * @param offset the zero based index at which to start storing the read content in {@code dst} * @param length the amount of elements to store in {@code dst} * @throws IOException if an I/O error occurs while reading the data * @throws IllegalArgumentException if the accumulated read length for the current value event * exceeds the actual value length * @see #getValueCount() * @see #getValueReadCount() * @see #getLongValue() */ public void getValue(long[] dst, int offset, int length) throws IOException; /** * Reads a single long value out of the underlying input stream. *

* Calls to this method may be interleaved with calls to {@link #getValue(long[], int, int)} for * the same VALUE_LONG event, as long as the accumulated number of elements read does not exceed * the current {@link #getValueCount() value count}. *

* * @pre {getEventType() == VALUE_LONG} * @pre {getValueReadCount() < getValueCount()} * @return the value read * @throws IOException if an I/O error occurs while reading the data * @see #getValueCount() * @see #getValueReadCount() * @see #getValue(long[], int, int) */ public long getLongValue() throws IOException; /** * Being at a {@link EventType#VALUE_FLOAT float value} event, reads {@code length} floats out * of the underlying input stream and stores them in {@code dst}, starting at array index * {@code offset}. *

* This operation is semantically equivalent to calling {@link #getFloatValue()} {@code length} * times, though its recommended for bulk reads as the implementation may perform better. *

* * @pre {getEventType() == VALUE_FLOAT} * @pre {dst != null} * @pre {offset >= 0} * @pre {length <= (dst.length - offset)} * @pre {getValueCount() - getValueReadCount() >= length} * @param dst the client supplied buffer where to store the read content * @param offset the zero based index at which to start storing the read content in {@code dst} * @param length the amount of elements to store in {@code dst} * @throws IOException if an I/O error occurs while reading the data * @throws IllegalArgumentException if the accumulated read length for the current value event * exceeds the actual value length * @see #getValueCount() * @see #getValueReadCount() * @see #getFloatValue() */ public void getValue(float[] dst, int offset, int length) throws IOException; /** * Reads a single float value out of the underlying input stream. *

* Calls to this method may be interleaved with calls to {@link #getValue(float[], int, int)} * for the same VALUE_FLOAT event, as long as the accumulated number of elements read does not * exceed the current {@link #getValueCount() value count}. *

* * @pre {getEventType() == VALUE_FLOAT} * @pre {getValueReadCount() < getValueCount()} * @return the value read * @throws IOException if an I/O error occurs while reading the data * @see #getValueCount() * @see #getValueReadCount() * @see #getValue(float[], int, int) */ public float getFloatValue() throws IOException; /** * Being at a {@link EventType#VALUE_DOUBLE double value} event, reads {@code length} doubles * out of the underlying input stream and stores them in {@code dst}, starting at array index * {@code offset}. *

* This operation is semantically equivalent to calling {@link #getDoubleValue()} {@code length} * times, though its recommended for bulk reads as the implementation may perform better. *

* * @pre {getEventType() == VALUE_DOUBLE} * @pre {dst != null} * @pre {offset >= 0} * @pre {length <= (dst.length - offset)} * @pre {getValueCount() - getValueReadCount() >= length} * @param dst the client supplied buffer where to store the read content * @param offset the zero based index at which to start storing the read content in {@code dst} * @param length the amount of elements to store in {@code dst} * @throws IOException if an I/O error occurs while reading the data * @throws IllegalArgumentException if the accumulated read length for the current value event * exceeds the actual value length * @see #getValueCount() * @see #getValueReadCount() * @see #getDoubleValue() */ public void getValue(double[] dst, int offset, int length) throws IOException; /** * Reads a single double value out of the underlying input stream. *

* Calls to this method may be interleaved with calls to {@link #getValue(double[], int, int)} * for the same VALUE_DOUBLE event, as long as the accumulated number of elements read does not * exceed the current {@link #getValueCount() value count}. *

* * @pre {getEventType() == VALUE_DOUBLE} * @pre {getValueReadCount() < getValueCount()} * @return the value read * @throws IOException if an I/O error occurs while reading the data * @see #getValueCount() * @see #getValueReadCount() * @see #getValue(double[], int, int) */ public double getDoubleValue() throws IOException; }