7 /** an event-driven XML parser, derived from MinML (http://www.wilson.co.uk/xml/minml.htm) */
8 public abstract class XML {
10 /////////////////////////////////////////////////////////////////////////////////////////////
11 // The following code was copied from the w3c's org.xml.sax.* classes
12 /////////////////////////////////////////////////////////////////////////////////////////////
14 protected static interface AttributeList {
15 public abstract int getLength ();
16 public abstract String getName (int i);
17 public abstract String getType (int i);
18 public abstract String getValue (int i);
19 public abstract String getType (String name);
20 public abstract String getValue (String name);
23 protected static interface DTDHandler {
24 public abstract void notationDecl (String name, String publicId, String systemId) throws SAXException;
25 public abstract void unparsedEntityDecl (String name, String publicId, String systemId, String notationName) throws SAXException;
28 protected static interface EntityResolver {
29 public abstract InputSource resolveEntity (String publicId, String systemId) throws SAXException, IOException;
32 protected static interface ErrorHandler {
33 public abstract void warning (SAXParseException exception) throws SAXException;
34 public abstract void error (SAXParseException exception) throws SAXException;
35 public abstract void fatalError (SAXParseException exception) throws SAXException;
38 private static class InputSource {
39 public InputSource () { }
40 public InputSource (String systemId) { setSystemId(systemId); }
41 public InputSource (InputStream byteStream) { setByteStream(byteStream); }
42 public InputSource (Reader characterStream) { setCharacterStream(characterStream); }
43 public void setPublicId (String publicId) { this.publicId = publicId; }
44 public String getPublicId () { return publicId; }
45 public void setSystemId (String systemId) { this.systemId = systemId; }
46 public String getSystemId() { return systemId; }
47 public void setByteStream (InputStream byteStream) { this.byteStream = byteStream; }
48 public InputStream getByteStream() { return byteStream; }
49 public void setEncoding (String encoding) { this.encoding = encoding; }
50 public String getEncoding() { return encoding; }
51 public void setCharacterStream (Reader characterStream) { this.characterStream = characterStream; }
52 public Reader getCharacterStream () { return characterStream; }
53 private String publicId;
54 private String systemId;
55 private InputStream byteStream;
56 private String encoding;
57 private Reader characterStream;
60 protected static interface Locator {
61 public abstract String getPublicId ();
62 public abstract String getSystemId ();
63 public abstract int getLineNumber ();
64 public abstract int getColumnNumber ();
67 protected static interface Parser {
68 public abstract void setLocale (Locale locale) throws SAXException;
69 public abstract void setEntityResolver (EntityResolver resolver);
70 public abstract void setDTDHandler (DTDHandler handler);
71 public abstract void setDocumentHandler (DocumentHandler handler);
72 public abstract void setErrorHandler (ErrorHandler handler);
73 public abstract void parse (InputSource source) throws SAXException, IOException;
74 public abstract void parse (String systemId) throws SAXException, IOException;
77 public static class SAXException extends Exception {
78 public SAXException (String message) {
80 this.message = message;
81 this.exception = null;
84 public SAXException (Exception e) {
90 public SAXException (String message, Exception e) {
92 this.message = message;
96 public String getMessage () {
97 if (message == null && exception != null) {
98 return exception.getMessage();
104 public Exception getException () { return exception; }
105 public String toString () { return getMessage(); }
106 private String message;
107 private Exception exception;
110 static class SAXParseException extends SAXException {
111 public SAXParseException (String message, Locator locator) {
113 this.publicId = locator.getPublicId();
114 this.systemId = locator.getSystemId();
115 this.lineNumber = locator.getLineNumber();
116 this.columnNumber = locator.getColumnNumber();
118 public SAXParseException (String message, Locator locator, Exception e) {
120 this.publicId = locator.getPublicId();
121 this.systemId = locator.getSystemId();
122 this.lineNumber = locator.getLineNumber();
123 this.columnNumber = locator.getColumnNumber();
125 public SAXParseException (String message, String publicId, String systemId, int lineNumber, int columnNumber) {
127 this.publicId = publicId;
128 this.systemId = systemId;
129 this.lineNumber = lineNumber;
130 this.columnNumber = columnNumber;
132 public SAXParseException (String message, String publicId, String systemId, int lineNumber, int columnNumber, Exception e) {
134 this.publicId = publicId;
135 this.systemId = systemId;
136 this.lineNumber = lineNumber;
137 this.columnNumber = columnNumber;
139 public String getPublicId() { return this.publicId; }
140 public String getSystemId() { return this.systemId; }
141 public int getLineNumber () { return this.lineNumber; }
142 public int getColumnNumber () { return this.columnNumber; }
143 private String publicId;
144 private String systemId;
145 private int lineNumber;
146 private int columnNumber;
149 protected static interface DocumentHandler {
150 public abstract void setDocumentLocator (Locator locator);
151 public abstract void startDocument() throws SAXException;
152 public abstract void endDocument() throws SAXException;
153 public abstract void startElement(String name, AttributeList atts) throws SAXException;
154 public abstract void endElement(String name) throws SAXException;
155 public abstract void characters(char ch[], int start, int length) throws SAXException;
156 public abstract void ignorableWhitespace(char ch[], int start, int length) throws SAXException;
157 public abstract void processingInstruction (String target, String data) throws SAXException;
158 Writer startDocument(final Writer writer) throws SAXException;
159 Writer startElement(final String name, final AttributeList attributes, final Writer writer) throws SAXException;
164 /////////////////////////////////////////////////////////////////////////////////////////////
165 // Everything from here down is copied verbatim from the MinML 1.7
166 // distribution, except for these modifications:
167 // - some classes have been changed from 'public' to 'private static'
168 // - extraneous import and package declarations have been removed
169 // - the advertising clause of the copyright notice has been removed
170 // as approved by John Wilson in an email to Adam Megacz.
171 /////////////////////////////////////////////////////////////////////////////////////////////
173 // Copyright (c) 2000, 2001, 2002 The Wilson Partnership.
174 // All Rights Reserved.
175 // @(#)MinML.java, 1.8(provisional), 2nd March 2002
176 // Author: John Wilson - tug@wilson.co.uk
179 Copyright (c) 2000, 2001 John Wilson (tug@wilson.co.uk).
181 Redistribution and use in source and binary forms,
182 with or without modification, are permitted provided
183 that the following conditions are met:
185 Redistributions of source code must retain the above
186 copyright notice, this list of conditions and the
187 following disclaimer.
189 Redistributions in binary form must reproduce the
190 above copyright notice, this list of conditions and
191 the following disclaimer in the documentation and/or
192 other materials provided with the distribution.
194 THIS SOFTWARE IS PROVIDED BY JOHN WILSON ``AS IS'' AND ANY
195 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
196 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
197 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JOHN WILSON
198 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
199 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
200 TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
201 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
202 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
203 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
204 IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
205 OF THE POSSIBILITY OF SUCH DAMAGE
208 private static class MinML implements Parser, Locator, DocumentHandler, ErrorHandler {
209 public static final int endStartName = 0;
210 public static final int emitStartElement = 1;
211 public static final int emitEndElement = 2;
212 public static final int possiblyEmitCharacters = 3;
213 public static final int emitCharacters = 4;
214 public static final int emitCharactersSave = 5;
215 public static final int saveAttributeName = 6;
216 public static final int saveAttributeValue = 7;
217 public static final int startComment = 8;
218 public static final int endComment = 9;
219 public static final int incLevel = 10;
220 public static final int decLevel = 11;
221 public static final int startCDATA = 12;
222 public static final int endCDATA = 13;
223 public static final int processCharRef = 14;
224 public static final int writeCdata = 15;
225 public static final int exitParser = 16;
226 public static final int parseError = 17;
227 public static final int discardAndChange = 18;
228 public static final int discardSaveAndChange = 19;
229 public static final int saveAndChange = 20;
230 public static final int change = 21;
232 public static final int inSkipping = 0;
233 public static final int inSTag = 1;
234 public static final int inPossiblyAttribute = 2;
235 public static final int inNextAttribute = 3;
236 public static final int inAttribute = 4;
237 public static final int inAttribute1 = 5;
238 public static final int inAttributeValue = 6;
239 public static final int inAttributeQuoteValue = 7;
240 public static final int inAttributeQuotesValue = 8;
241 public static final int inETag = 9;
242 public static final int inETag1 = 10;
243 public static final int inMTTag = 11;
244 public static final int inTag = 12;
245 public static final int inTag1 = 13;
246 public static final int inPI = 14;
247 public static final int inPI1 = 15;
248 public static final int inPossiblySkipping = 16;
249 public static final int inCharData = 17;
250 public static final int inCDATA = 18;
251 public static final int inCDATA1 = 19;
252 public static final int inComment =20;
253 public static final int inDTD = 21;
255 public MinML(final int initialBufferSize, final int bufferIncrement) {
256 this.initialBufferSize = initialBufferSize;
257 this.bufferIncrement = bufferIncrement;
264 public void parse(final Reader in) throws SAXException, IOException {
265 final Vector attributeNames = new Vector();
266 final Vector attributeValues = new Vector();
268 final AttributeList attrs = new AttributeList() {
269 public int getLength() {
270 return attributeNames.size();
273 public String getName(final int i) {
274 return (String)attributeNames.elementAt(i);
277 public String getType(final int i) {
281 public String getValue(final int i) {
282 return (String)attributeValues.elementAt(i);
285 public String getType(final String name) {
289 public String getValue(final String name) {
290 final int index = attributeNames.indexOf(name);
292 return (index == -1) ? null : (String)attributeValues.elementAt(index);
296 final MinMLBuffer buffer = new MinMLBuffer(in);
297 int currentChar = 0, charCount = 0;
299 int mixedContentLevel = -1;
300 String elementName = null;
301 String state = operands[inSkipping];
304 this.columnNumber = 0;
311 // this is to try and make the loop a bit faster
312 // currentChar = buffer.read(); is simpler but is a bit slower.
314 currentChar = (buffer.nextIn == buffer.lastIn) ? buffer.read() : buffer.chars[buffer.nextIn++];
316 final int transition;
318 if (currentChar > ']') {
319 transition = state.charAt(14);
321 final int charClass = charClasses[currentChar + 1];
323 if (charClass == -1) fatalError("Document contains illegal control character with value " + currentChar, this.lineNumber, this.columnNumber);
325 if (charClass == 12) {
326 if (currentChar == '\r') {
331 if (currentChar == '\n') {
332 if (charCount == 0) continue; // preceeded by '\r' so ignore
334 if (charCount != -1) charCount = 0;
337 this.columnNumber = 0;
341 transition = state.charAt(charClass);
346 final String operand = operands[transition >>> 8];
348 switch (transition & 0XFF) {
350 // end of start element name
351 elementName = buffer.getString();
352 if (currentChar != '>' && currentChar != '/') break; // change state to operand
353 // drop through to emit start element (we have no attributes)
355 case emitStartElement:
356 // emit start element
358 final Writer newWriter = this.extDocumentHandler.startElement(elementName, attrs,
359 (this.tags.empty()) ?
360 this.extDocumentHandler.startDocument(buffer)
364 buffer.pushWriter(newWriter);
365 this.tags.push(elementName);
367 attributeValues.removeAllElements();
368 attributeNames.removeAllElements();
370 if (mixedContentLevel != -1) mixedContentLevel++;
372 if (currentChar != '/') break; // change state to operand
374 // <element/> drop through
380 final String begin = (String)this.tags.pop();
383 elementName = buffer.getString();
385 if (currentChar != '/' && !elementName.equals(begin)) {
386 fatalError("end tag </" + elementName + "> does not match begin tag <" + begin + ">",
387 this.lineNumber, this.columnNumber);
389 this.documentHandler.endElement(begin);
391 if (this.tags.empty()) {
392 this.documentHandler.endDocument();
397 catch (final EmptyStackException e) {
398 fatalError("end tag at begining of document", this.lineNumber, this.columnNumber);
401 if (mixedContentLevel != -1) --mixedContentLevel;
403 break; // change state to operand
409 break; // change state to operand
411 case emitCharactersSave:
412 // emit characters and save current character
414 if (mixedContentLevel == -1) mixedContentLevel = 0;
418 buffer.saveChar((char)currentChar);
420 break; // change state to operand
422 case possiblyEmitCharacters:
423 // write any skipped whitespace if in mixed content
425 if (mixedContentLevel != -1) buffer.flush();
426 break; // change state to operand
428 case saveAttributeName:
429 // save attribute name
431 attributeNames.addElement(buffer.getString());
432 break; // change state to operand
434 case saveAttributeValue:
435 // save attribute value
437 attributeValues.addElement(buffer.getString());
438 break; // change state to operand
441 // change state if we have found "<!--"
443 if (buffer.read() != '-') continue; // not "<!--"
445 char[] lastthree = new char[3];
448 currentChar = buffer.read();
449 lastthree[pos] = (char)currentChar;
450 if (lastthree[pos] == '>' && lastthree[(pos + 2) % 3] == '-' && lastthree[(pos + 1) % 3] == '-') break;
454 state = operands[inCharData];
455 continue; // change state to operand
458 // change state if we find "-->"
460 if ((currentChar = buffer.read()) == '-') {
461 // deal with the case where we might have "------->"
462 while ((currentChar = buffer.read()) == '-');
464 if (currentChar == '>') break; // end of comment, change state to operand
467 continue; // not end of comment, don't change state
477 if (level == 0) break; // outer level <> change state
481 continue; // in nested <>, don't change state
484 // change state if we have found "<![CDATA["
486 if (buffer.read() != 'C') continue; // don't change state
487 if (buffer.read() != 'D') continue; // don't change state
488 if (buffer.read() != 'A') continue; // don't change state
489 if (buffer.read() != 'T') continue; // don't change state
490 if (buffer.read() != 'A') continue; // don't change state
491 if (buffer.read() != '[') continue; // don't change state
492 break; // change state to operand
495 // change state if we find "]]>"
497 if ((currentChar = buffer.read()) == ']') {
498 // deal with the case where we might have "]]]]]]]>"
499 while ((currentChar = buffer.read()) == ']') buffer.write(']');
501 if (currentChar == '>') break; // end of CDATA section, change state to operand
507 buffer.write(currentChar);
508 continue; // not end of CDATA section, don't change state
511 // process character entity
515 currentChar = buffer.read();
518 if ("#amp;&pos;'quot;\"gt;>lt;<".charAt(crefState) == currentChar) {
521 if (currentChar == ';') {
522 buffer.write("#amp;&pos;'quot;\"gt;>lt;<".charAt(crefState));
525 } else if (currentChar == '#') {
528 currentChar = buffer.read();
530 if (currentChar == 'x') {
532 currentChar = buffer.read();
537 int charRef = Character.digit((char)currentChar, radix);
540 currentChar = buffer.read();
542 final int digit = Character.digit((char)currentChar, radix);
544 if (digit == -1) break;
546 charRef = (char)((charRef * radix) + digit);
549 if (currentChar == ';' && charRef != -1) {
550 buffer.write(charRef);
554 fatalError("invalid Character Entitiy", this.lineNumber, this.columnNumber);
556 currentChar = buffer.read();
559 crefState = ("\u0001\u000b\u0006\u00ff\u00ff\u00ff\u00ff\u00ff\u00ff\u00ff\u00ff" +
560 // # a m p ; & p o s ; '
561 // 0 1 2 3 4 5 6 7 8 9 a
562 "\u0011\u00ff\u00ff\u00ff\u00ff\u00ff\u0015\u00ff\u00ff\u00ff" +
563 // q u o t ; " g t ; >
564 // b b d e f 10 11 12 13 14
565 "\u00ff\u00ff\u00ff").charAt(crefState);
569 if (crefState == 255) fatalError("invalid Character Entitiy", this.lineNumber, this.columnNumber);
576 // report fatal error
578 fatalError(operand, this.lineNumber, this.columnNumber);
579 // drop through to exit parser
587 // write character data
588 // this will also write any skipped whitespace
590 buffer.write(currentChar);
591 break; // change state to operand
593 case discardAndChange:
594 // throw saved characters away and change state
597 break; // change state to operand
599 case discardSaveAndChange:
600 // throw saved characters away, save character and change state
603 // drop through to save character and change state
606 // save character and change state
608 buffer.saveChar((char)currentChar);
609 break; // change state to operand
612 // change state to operand
614 break; // change state to operand
620 catch (final IOException e) {
621 this.errorHandler.fatalError(new SAXParseException(e.toString(), null, null, this.lineNumber, this.columnNumber, e));
624 this.errorHandler = this;
625 this.documentHandler = this.extDocumentHandler = this;
626 this.tags.removeAllElements();
630 public void parse(final InputSource source) throws SAXException, IOException {
631 if (source.getCharacterStream() != null)
632 parse(source.getCharacterStream());
633 else if (source.getByteStream() != null)
634 parse(new InputStreamReader(source.getByteStream()));
636 parse(new InputStreamReader(new URL(source.getSystemId()).openStream()));
639 public void parse(final String systemId) throws SAXException, IOException {
640 parse(new InputSource(systemId));
643 public void setLocale(final Locale locale) throws SAXException {
644 throw new SAXException("Not supported");
647 public void setEntityResolver(final EntityResolver resolver) {
651 public void setDTDHandler(final DTDHandler handler) {
655 public void setDocumentHandler(final DocumentHandler handler) {
656 this.documentHandler = (handler == null) ? this : handler;
657 if (handler != null) handler.setDocumentLocator(this);
658 this.extDocumentHandler = this;
661 public void setErrorHandler(final ErrorHandler handler) {
662 this.errorHandler = (handler == null) ? this : handler;
665 public void setDocumentLocator(final Locator locator) {
668 public void startDocument() throws SAXException {
671 public Writer startDocument(final Writer writer) throws SAXException {
672 this.documentHandler.startDocument();
676 public void endDocument() throws SAXException {
679 public void startElement(final String name, final AttributeList attributes) throws SAXException {
682 public Writer startElement(final String name, final AttributeList attributes, final Writer writer)
685 this.documentHandler.startElement(name, attributes);
689 public void endElement(final String name) throws SAXException {
692 public void characters(final char ch[], final int start, final int length) throws SAXException {
695 public void ignorableWhitespace(final char ch[], final int start, final int length) throws SAXException {
698 public void processingInstruction(final String target, final String data) throws SAXException {
701 public void warning(final SAXParseException e) throws SAXException {
704 public void error(final SAXParseException e) throws SAXException {
707 public void fatalError(final SAXParseException e) throws SAXException {
711 public String getPublicId() {
716 public String getSystemId() {
720 public int getLineNumber () {
721 return this.lineNumber;
724 public int getColumnNumber () {
725 return this.columnNumber;
728 private void fatalError(final String msg, final int lineNumber, final int columnNumber) throws SAXException {
729 this.errorHandler.fatalError(new SAXParseException(msg, null, null, lineNumber, columnNumber));
732 private class MinMLBuffer extends Writer {
733 public MinMLBuffer(final Reader in) {
737 public void close() throws IOException {
741 public void flush() throws IOException {
744 if (writer != this) writer.flush();
751 public void write(final int c) throws IOException {
753 chars[count++] = (char)c;
756 public void write(final char[] cbuf, final int off, final int len) throws IOException {
758 System.arraycopy(cbuf, off, chars, count, len);
762 public void saveChar(final char c) {
767 public void pushWriter(final Writer writer) {
768 MinML.this.tags.push(this.writer);
770 this.writer = (writer == null) ? this : writer;
772 flushed = written = false;
775 public Writer getWriter() {
779 public void popWriter() throws IOException {
781 if (!flushed && writer != this) writer.flush();
784 writer = (Writer)MinML.this.tags.pop();
785 flushed = written = false;
789 public String getString() {
790 final String result = new String(chars, 0, count);
796 public void reset() {
800 public int read() throws IOException {
801 if (nextIn == lastIn) {
805 } else if (count >= (chars.length - MinML.this.bufferIncrement)) {
806 final char[] newChars = new char[chars.length + MinML.this.bufferIncrement];
808 System.arraycopy(chars, 0, newChars, 0, count);
813 final int numRead = in.read(chars, count, chars.length - count);
815 if (numRead == -1) return -1;
818 lastIn = count + numRead;
821 return chars[nextIn++];
824 private void _flush() throws IOException {
827 if (writer == this) {
829 MinML.this.documentHandler.characters(chars, 0, count);
831 catch (final SAXException e) {
832 throw new IOException(e.toString());
835 writer.write(chars, 0, count);
844 private int nextIn = 0, lastIn = 0;
845 private char[] chars = new char[MinML.this.initialBufferSize];
846 private final Reader in;
847 private int count = 0;
848 private Writer writer = this;
849 private boolean flushed = false;
850 private boolean written = false;
853 private DocumentHandler extDocumentHandler = this;
854 private DocumentHandler documentHandler = this;
855 private ErrorHandler errorHandler = this;
856 private final Stack tags = new Stack();
857 private int lineNumber = 1;
858 private int columnNumber = 0;
859 private final int initialBufferSize;
860 private final int bufferIncrement;
862 private static final byte[] charClasses = {
866 -1, -1, -1, -1, -1, -1, -1, -1, -1, 12, 12, -1, -1, 12, -1, -1,
868 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
869 // SP ! " # $ % & ' ( ) * + , - . /
870 12, 8, 7, 14, 14, 14, 3, 6, 14, 14, 14, 14, 14, 11, 14, 2,
871 // 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
872 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 5, 1, 4,
874 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
876 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 9, 14, 10
879 private static final String[] operands = {
880 "\u0d15\u1611\u1611\u1611\u1611\u1611\u1611\u1611\u1611\u1611\u1611\u1611\u0015\u0010\u1611",
881 "\u1711\u1000\u0b00\u1711\u1711\u1711\u1711\u1711\u1711\u1711\u1711\u0114\u0200\u1811\u0114",
882 "\u1711\u1001\u0b01\u1711\u1711\u1711\u1711\u1711\u1711\u1711\u1711\u1711\u0215\u1811\u0414",
883 "\u1711\u1001\u0b01\u1711\u1911\u1911\u1911\u1911\u1911\u1911\u1911\u1911\u0315\u1811\u0414",
884 "\u1911\u1911\u1911\u1911\u1911\u0606\u1911\u1911\u1911\u1911\u1911\u0414\u0515\u1811\u0414",
885 "\u1911\u1911\u1911\u1911\u1911\u0606\u1911\u1911\u1911\u1911\u1911\u1911\u0515\u1811\u1911",
886 "\u1a11\u1a11\u1a11\u1a11\u1a11\u1a11\u0715\u0815\u1a11\u1a11\u1a11\u1a11\u0615\u1811\u1a11",
887 "\u0714\u0714\u0714\u070e\u0714\u0714\u0307\u0714\u0714\u0714\u0714\u0714\u0714\u1811\u0714",
888 "\u0814\u0814\u0814\u080e\u0814\u0814\u0814\u0307\u0814\u0814\u0814\u0814\u0814\u1811\u0814",
889 "\u1711\u1002\u1711\u1711\u1711\u1711\u1711\u1711\u1711\u1711\u1711\u0914\u0915\u1811\u0914",
890 "\u1b11\u1b11\u0904\u1b11\u1b11\u1b11\u1b11\u1b11\u1215\u1b11\u1b11\u1b11\u1b11\u1811\u0105",
891 "\u1711\u1012\u1711\u1711\u1711\u1711\u1711\u1711\u1711\u1711\u1711\u1711\u1711\u1811\u1711",
892 "\u1711\u1c11\u0912\u1711\u0e12\u1711\u1711\u1711\u1212\u1711\u1711\u1711\u1711\u1811\u0113",
893 "\u1711\u1c11\u0912\u1711\u0e12\u1711\u1711\u1711\u1212\u1711\u1711\u1711\u1711\u1811\u0113",
894 "\u0e15\u0e15\u0e15\u0e15\u0f15\u0e15\u0e15\u0e15\u0e15\u0e15\u0e15\u0e15\u0e15\u1811\u0e15",
895 "\u0e15\u0015\u0e15\u0e15\u0f15\u0e15\u0e15\u0e15\u0e15\u0e15\u0e15\u0e15\u0e15\u1811\u0e15",
896 "\u0c03\u110f\u110f\u110e\u110f\u110f\u110f\u110f\u110f\u110f\u110f\u110f\u1014\u1811\u110f",
897 "\u0a15\u110f\u110f\u110e\u110f\u110f\u110f\u110f\u110f\u110f\u110f\u110f\u110f\u1811\u110f",
898 "\u1d11\u1d11\u1d11\u1d11\u1d11\u1d11\u1d11\u1d11\u1d11\u130c\u1d11\u1408\u1d11\u1811\u1515",
899 "\u130f\u130f\u130f\u130f\u130f\u130f\u130f\u130f\u130f\u130f\u110d\u130f\u130f\u1811\u130f",
900 "\u1415\u1415\u1415\u1415\u1415\u1415\u1415\u1415\u1415\u1415\u1415\u0009\u1415\u1811\u1415",
901 "\u150a\u000b\u1515\u1515\u1515\u1515\u1515\u1515\u1515\u1515\u1515\u1515\u1515\u1811\u1515",
903 "unexpected character in tag",
904 "unexpected end of file found",
905 "attribute name not followed by '='",
906 "invalid attribute value",
909 "unexpected character after <!"
912 ///////////////////////////////////////////////////////////////////////////////
914 private class XMLHelper implements DocumentHandler {
915 private MinML minml = new MinML();
917 public void parse(Reader r) throws IOException, XML.SAXException {
918 minml.setDocumentHandler(this);
919 minml.parse(new InputSource(r));
922 public void startDocument() throws SAXException { }
923 public void endDocument() throws SAXException { }
924 public void processingInstruction (String target, String data) throws SAXException { }
925 public Writer startDocument(final Writer writer) throws SAXException { return null; }
926 public Writer startElement(final String name, final AttributeList attributes, final Writer writer) throws SAXException { return null; }
928 public void setDocumentLocator (Locator locator) {
929 this.locator = locator;
932 private Locator locator = null;
934 public void startElement(String name, AttributeList atts) throws SAXException {
935 String[] keys = new String[atts.getLength()];
936 Object[] vals = new Object[atts.getLength()];
937 for (int i=0; i <atts.getLength(); i++) {
938 keys[i] = atts.getName(i);
939 vals[i] = atts.getValue(i).toString();
941 XML.this.startElement(name, keys, vals,
942 locator == null ? 0 : locator.getLineNumber(), locator == null ? 0 : locator.getColumnNumber());
945 public void endElement(String name) throws SAXException {
946 XML.this.endElement(name, locator == null ? 0 : locator.getLineNumber(), locator == null ? 0 : locator.getColumnNumber());
949 public void characters(char ch[], int start, int length) throws SAXException {
950 XML.this.content(ch, start, length, locator == null ? 0 : locator.getLineNumber(), locator == null ? 0 : locator.getColumnNumber());
952 public void ignorableWhitespace(char ch[], int start, int length) throws SAXException {
953 XML.this.content(ch, start, length, locator == null ? 0 : locator.getLineNumber(), locator == null ? 0 : locator.getColumnNumber());
958 public void parse(Reader r) throws IOException, XML.SAXException {
959 XMLHelper helper = new XMLHelper();
964 /** indicates the start of an element with name <tt>name</tt>, and attributes <tt>attributes</tt>, starting on line <tt>line</tt> */
965 public abstract void startElement(String name, String[] keys, Object[] vals, int line, int col) throws SAXException;
967 /** indicates the end of an element with name <tt>name</tt>, starting on line <tt>line</tt> */
968 public abstract void endElement(String name, int line, int col) throws SAXException;
970 /** indicates a chunk of CDATA content, starting on line <tt>line</tt> */
971 public abstract void content(char[] content, int start, int length, int line, int col) throws SAXException;