package org.ibex.util;
import java.io.Reader;
+import java.io.Writer;
import java.io.IOException;
import java.io.EOFException;
* @see <a href="http://w3.org/TR/REC-xml">XML Specification</a>
* @see <a href="http://w3.org/TR/REC-xml-names">XML Namespaces</a>
*/
-public abstract class XML
-{
+public abstract class XML {
+
/////////////////////////////////////////////////////////////////////////////////////////////
// XML Parser
/////////////////////////////////////////////////////////////////////////////////////////////
private static final char[] single_lt = new char[] { '<' };
private static final char[] single_quot = new char[] { '"' };
- private int line;
- private int col;
+ int line;
+ int col;
- private Reader in;
- private char[] buf;
- private int off;
- private int base; // base+off == distance into the stream
- private int len;
+ Reader in;
+ char[] buf;
+ int off;
+ int base; // base+off == distance into the stream
+ int len;
- private Element current;
+ Element current = null;
// used in readEntity() to process a single character without creating a new array
private char[] singlechar = new char[1];
public XML(int bSize) {
buf = new char[bSize];
-
- current = (Element)elements.remove(false);
- if (current == null) current = new Element();
+ //current = (Element)elements.remove(false);
+ if (current == null) current = newElement();
}
/** Returns the line number at the beginning of the last process call. */
/** Returns the global file offset at the beginning of the last process call. */
public int getGlobalOffset() { return base + off; }
+ Element newElement() { return new Element(); }
+
/**
* Parse given input and call the abstract event functions.
*
} finally { clear(); } // clean up elements
}
+ // Stuff below here is Adam's hack //////////////////////////////////////////////////////////////////////////////
+
+ boolean done = false;
+ public static class Pull extends XML {
+ public Pull(Reader in) { this.in = in; off = len = 0; line = col = 1; clear(); }
+ StringBuffer sb = new StringBuffer();
+ Element pending = null;
+ boolean emptytag = true;
+ public int level = 0;
+ public final void startElement(Element e) throws Exn { emptytag = false; level++; pending = e; }
+ public final void endElement(Element e) throws Exn, IOException { emptytag=pending!=null; level--; }
+ public final void whitespace(char[] ch, int start, int length) throws Exn, IOException { }
+ public final void characters(char[] ch, int start, int length) throws Exn, IOException {
+ emptytag=false; sb.append(ch,start,length);}
+ public Object read() throws Exn, IOException {
+ while(!done) {
+ if (pending != null) { Element ret = pending; pending = null; ret.level = level-(emptytag?0:1); return ret; }
+ if (sb.length() > 0) { String ret = sb.toString(); sb.setLength(0); return ret; }
+ if (!buffer(1)) {
+ if (done) return null;
+ throw new Exn("reached eof without closing <"+current.qName+"> element", Exn.WFC, getLine(), getCol());
+ }
+ if (buf[off] == '<') readTag(); else readChars(!done);
+ }
+ return null;
+ }
+ }
+
+
+ // Stuff above here is Adam's hack //////////////////////////////////////////////////////////////////////////////
+
/** remove any leftover elements from the linked list and queue them */
- private final void clear() {
+ final void clear() {
for (Element last = current; current.parent != null; ) {
current = current.parent;
last.clear();
}
/** reads in a tag. expects <tt>buf[off] == '<'</tt> */
- private final void readTag() throws IOException, Exn {
+ final void readTag() throws IOException, Exn {
// Start Tag '<' Name (S Attribute)* S? '>'
boolean starttag = true;
// create the in-memory element representation of this beast
// if current.qName == null then this is the root element we're dealing with
if (current.qName != null) {
- Element next = (Element)elements.remove(false);
- if (next == null) next = new Element();
+ Element next = newElement();
//next.clear(); // TODO: remove as elements now checked as they're added to the queue
next.parent = current;
current = next;
// we just closed an element, so remove it from the element 'stack'
if (current.getParent() == null) {
// we just finished the root element
- current.clear();
+ done = true;
} else {
Element last = current;
current = current.parent;
- last.clear();
+ //last.clear(); FIXME
elements.append(last);
}
}
}
}
+
/** reads in an attribute of an element. expects Name(buf[off]) */
private final void readAttribute() throws IOException, Exn {
int ref = 0;
}
/** reads until the passed string is encountered. */
- private final void readChars(boolean p, String match, boolean entities) throws IOException, Exn {
+ final void readChars(boolean p, String match, boolean entities) throws IOException, Exn {
int ref;
char[] end = match.toCharArray();
* reads until a <tt><</tt> symbol is encountered
* @param p If true call the characters(char[],int,int) funciton for the processed characters
*/
- private final void readChars(boolean p) throws IOException, Exn {
+ final void readChars(boolean p) throws IOException, Exn {
int ref;
for (boolean more = true; more;) {
* @param min Minimum number of characters to read (even if we have to block to do it).
* @return return false if min can't be reached.
*/
- private final boolean buffer(int min) throws IOException {
+ final boolean buffer(int min) throws IOException {
if (len > min) return true;
if (buf.length - (off+len) >= min) {
/** Represents the end of an Element. */
public abstract void endElement(Element e) throws Exn, IOException;
-
/////////////////////////////////////////////////////////////////////////////////////////////
// Inner Classes for Parser Support
/////////////////////////////////////////////////////////////////////////////////////////////
protected String localName = null;
protected String qName = null;
protected String prefix = null;
+ public int level = 0;
protected Hash urimap = new Hash(3,3);