8 /** an event-driven XML parser, derived from MinML (http://www.wilson.co.uk/xml/minml.htm) */
9 public abstract class XML {
11 /////////////////////////////////////////////////////////////////////////////////////////////
12 // The following code was copied from the w3c's org.xml.sax.* classes
13 /////////////////////////////////////////////////////////////////////////////////////////////
15 protected static interface AttributeList {
16 public abstract int getLength ();
17 public abstract String getName (int i);
18 public abstract String getType (int i);
19 public abstract String getValue (int i);
20 public abstract String getType (String name);
21 public abstract String getValue (String name);
24 protected static interface DTDHandler {
25 public abstract void notationDecl (String name, String publicId, String systemId) throws SAXException;
26 public abstract void unparsedEntityDecl (String name, String publicId, String systemId, String notationName) throws SAXException;
29 protected static interface EntityResolver {
30 public abstract InputSource resolveEntity (String publicId, String systemId) throws SAXException, IOException;
33 protected static interface ErrorHandler {
34 public abstract void warning (SAXParseException exception) throws SAXException;
35 public abstract void error (SAXParseException exception) throws SAXException;
36 public abstract void fatalError (SAXParseException exception) throws SAXException;
39 private static class InputSource {
40 public InputSource () { }
41 public InputSource (String systemId) { setSystemId(systemId); }
42 public InputSource (InputStream byteStream) { setByteStream(byteStream); }
43 public InputSource (Reader characterStream) { setCharacterStream(characterStream); }
44 public void setPublicId (String publicId) { this.publicId = publicId; }
45 public String getPublicId () { return publicId; }
46 public void setSystemId (String systemId) { this.systemId = systemId; }
47 public String getSystemId() { return systemId; }
48 public void setByteStream (InputStream byteStream) { this.byteStream = byteStream; }
49 public InputStream getByteStream() { return byteStream; }
50 public void setEncoding (String encoding) { this.encoding = encoding; }
51 public String getEncoding() { return encoding; }
52 public void setCharacterStream (Reader characterStream) { this.characterStream = characterStream; }
53 public Reader getCharacterStream () { return characterStream; }
54 private String publicId;
55 private String systemId;
56 private InputStream byteStream;
57 private String encoding;
58 private Reader characterStream;
61 protected static interface Locator {
62 public abstract String getPublicId ();
63 public abstract String getSystemId ();
64 public abstract int getLineNumber ();
65 public abstract int getColumnNumber ();
68 protected static interface Parser {
69 public abstract void setLocale (Locale locale) throws SAXException;
70 public abstract void setEntityResolver (EntityResolver resolver);
71 public abstract void setDTDHandler (DTDHandler handler);
72 public abstract void setDocumentHandler (DocumentHandler handler);
73 public abstract void setErrorHandler (ErrorHandler handler);
74 public abstract void parse (InputSource source) throws SAXException, IOException;
75 public abstract void parse (String systemId) throws SAXException, IOException;
78 public static class SAXException extends Exception {
79 public SAXException (String message) {
81 this.message = message;
82 this.exception = null;
85 public SAXException (Exception e) {
91 public SAXException (String message, Exception e) {
93 this.message = message;
97 public String getMessage () {
98 if (message == null && exception != null) {
99 return exception.getMessage();
105 public Exception getException () { return exception; }
106 public String toString () { return getMessage(); }
107 private String message;
108 private Exception exception;
111 static class SAXParseException extends SAXException {
112 public SAXParseException (String message, Locator locator) {
114 this.publicId = locator.getPublicId();
115 this.systemId = locator.getSystemId();
116 this.lineNumber = locator.getLineNumber();
117 this.columnNumber = locator.getColumnNumber();
119 public SAXParseException (String message, Locator locator, Exception e) {
121 this.publicId = locator.getPublicId();
122 this.systemId = locator.getSystemId();
123 this.lineNumber = locator.getLineNumber();
124 this.columnNumber = locator.getColumnNumber();
126 public SAXParseException (String message, String publicId, String systemId, int lineNumber, int columnNumber) {
128 this.publicId = publicId;
129 this.systemId = systemId;
130 this.lineNumber = lineNumber;
131 this.columnNumber = columnNumber;
133 public SAXParseException (String message, String publicId, String systemId, int lineNumber, int columnNumber, Exception e) {
135 this.publicId = publicId;
136 this.systemId = systemId;
137 this.lineNumber = lineNumber;
138 this.columnNumber = columnNumber;
140 public String getPublicId() { return this.publicId; }
141 public String getSystemId() { return this.systemId; }
142 public int getLineNumber () { return this.lineNumber; }
143 public int getColumnNumber () { return this.columnNumber; }
144 private String publicId;
145 private String systemId;
146 private int lineNumber;
147 private int columnNumber;
150 protected static interface DocumentHandler {
151 public abstract void setDocumentLocator (Locator locator);
152 public abstract void startDocument() throws SAXException;
153 public abstract void endDocument() throws SAXException;
154 public abstract void startElement(String name, AttributeList atts) throws SAXException;
155 public abstract void endElement(String name) throws SAXException;
156 public abstract void characters(char ch[], int start, int length) throws SAXException;
157 public abstract void ignorableWhitespace(char ch[], int start, int length) throws SAXException;
158 public abstract void processingInstruction (String target, String data) throws SAXException;
159 Writer startDocument(final Writer writer) throws SAXException;
160 Writer startElement(final String name, final AttributeList attributes, final Writer writer) throws SAXException;
165 /////////////////////////////////////////////////////////////////////////////////////////////
166 // Everything from here down is copied verbatim from the MinML 1.7
167 // distribution, except for these modifications:
168 // - some classes have been changed from 'public' to 'private static'
169 // - extraneous import and package declarations have been removed
170 // - the advertising clause of the copyright notice has been removed
171 // as approved by John Wilson in an email to Adam Megacz.
172 /////////////////////////////////////////////////////////////////////////////////////////////
174 // Copyright (c) 2000, 2001, 2002 The Wilson Partnership.
175 // All Rights Reserved.
176 // @(#)MinML.java, 1.8(provisional), 2nd March 2002
177 // Author: John Wilson - tug@wilson.co.uk
180 Copyright (c) 2000, 2001 John Wilson (tug@wilson.co.uk).
182 Redistribution and use in source and binary forms,
183 with or without modification, are permitted provided
184 that the following conditions are met:
186 Redistributions of source code must retain the above
187 copyright notice, this list of conditions and the
188 following disclaimer.
190 Redistributions in binary form must reproduce the
191 above copyright notice, this list of conditions and
192 the following disclaimer in the documentation and/or
193 other materials provided with the distribution.
195 THIS SOFTWARE IS PROVIDED BY JOHN WILSON ``AS IS'' AND ANY
196 EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
197 THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
198 PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JOHN WILSON
199 BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
200 EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
201 TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
202 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
203 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
204 LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
205 IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
206 OF THE POSSIBILITY OF SUCH DAMAGE
209 private static class MinML implements Parser, Locator, DocumentHandler, ErrorHandler {
210 public static final int endStartName = 0;
211 public static final int emitStartElement = 1;
212 public static final int emitEndElement = 2;
213 public static final int possiblyEmitCharacters = 3;
214 public static final int emitCharacters = 4;
215 public static final int emitCharactersSave = 5;
216 public static final int saveAttributeName = 6;
217 public static final int saveAttributeValue = 7;
218 public static final int startComment = 8;
219 public static final int endComment = 9;
220 public static final int incLevel = 10;
221 public static final int decLevel = 11;
222 public static final int startCDATA = 12;
223 public static final int endCDATA = 13;
224 public static final int processCharRef = 14;
225 public static final int writeCdata = 15;
226 public static final int exitParser = 16;
227 public static final int parseError = 17;
228 public static final int discardAndChange = 18;
229 public static final int discardSaveAndChange = 19;
230 public static final int saveAndChange = 20;
231 public static final int change = 21;
233 public static final int inSkipping = 0;
234 public static final int inSTag = 1;
235 public static final int inPossiblyAttribute = 2;
236 public static final int inNextAttribute = 3;
237 public static final int inAttribute = 4;
238 public static final int inAttribute1 = 5;
239 public static final int inAttributeValue = 6;
240 public static final int inAttributeQuoteValue = 7;
241 public static final int inAttributeQuotesValue = 8;
242 public static final int inETag = 9;
243 public static final int inETag1 = 10;
244 public static final int inMTTag = 11;
245 public static final int inTag = 12;
246 public static final int inTag1 = 13;
247 public static final int inPI = 14;
248 public static final int inPI1 = 15;
249 public static final int inPossiblySkipping = 16;
250 public static final int inCharData = 17;
251 public static final int inCDATA = 18;
252 public static final int inCDATA1 = 19;
253 public static final int inComment =20;
254 public static final int inDTD = 21;
256 public MinML(final int initialBufferSize, final int bufferIncrement) {
257 this.initialBufferSize = initialBufferSize;
258 this.bufferIncrement = bufferIncrement;
265 public void parse(final Reader in) throws SAXException, IOException {
266 final Vector attributeNames = new Vector();
267 final Vector attributeValues = new Vector();
269 final AttributeList attrs = new AttributeList() {
270 public int getLength() {
271 return attributeNames.size();
274 public String getName(final int i) {
275 return (String)attributeNames.elementAt(i);
278 public String getType(final int i) {
282 public String getValue(final int i) {
283 return (String)attributeValues.elementAt(i);
286 public String getType(final String name) {
290 public String getValue(final String name) {
291 final int index = attributeNames.indexOf(name);
293 return (index == -1) ? null : (String)attributeValues.elementAt(index);
297 final MinMLBuffer buffer = new MinMLBuffer(in);
298 int currentChar = 0, charCount = 0;
300 int mixedContentLevel = -1;
301 String elementName = null;
302 String state = operands[inSkipping];
305 this.columnNumber = 0;
312 // this is to try and make the loop a bit faster
313 // currentChar = buffer.read(); is simpler but is a bit slower.
315 currentChar = (buffer.nextIn == buffer.lastIn) ? buffer.read() : buffer.chars[buffer.nextIn++];
317 final int transition;
319 if (currentChar > ']') {
320 transition = state.charAt(14);
322 final int charClass = charClasses[currentChar + 1];
324 if (charClass == -1) fatalError("Document contains illegal control character with value " + currentChar, this.lineNumber, this.columnNumber);
326 if (charClass == 12) {
327 if (currentChar == '\r') {
332 if (currentChar == '\n') {
333 if (charCount == 0) continue; // preceeded by '\r' so ignore
335 if (charCount != -1) charCount = 0;
338 this.columnNumber = 0;
342 transition = state.charAt(charClass);
347 final String operand = operands[transition >>> 8];
349 switch (transition & 0XFF) {
351 // end of start element name
352 elementName = buffer.getString();
353 if (currentChar != '>' && currentChar != '/') break; // change state to operand
354 // drop through to emit start element (we have no attributes)
356 case emitStartElement:
357 // emit start element
359 final Writer newWriter = this.extDocumentHandler.startElement(elementName, attrs,
360 (this.tags.empty()) ?
361 this.extDocumentHandler.startDocument(buffer)
365 buffer.pushWriter(newWriter);
366 this.tags.push(elementName);
368 attributeValues.removeAllElements();
369 attributeNames.removeAllElements();
371 if (mixedContentLevel != -1) mixedContentLevel++;
373 if (currentChar != '/') break; // change state to operand
375 // <element/> drop through
381 final String begin = (String)this.tags.pop();
384 elementName = buffer.getString();
386 if (currentChar != '/' && !elementName.equals(begin)) {
387 fatalError("end tag </" + elementName + "> does not match begin tag <" + begin + ">",
388 this.lineNumber, this.columnNumber);
390 this.documentHandler.endElement(begin);
392 if (this.tags.empty()) {
393 this.documentHandler.endDocument();
398 catch (final EmptyStackException e) {
399 fatalError("end tag at begining of document", this.lineNumber, this.columnNumber);
402 if (mixedContentLevel != -1) --mixedContentLevel;
404 break; // change state to operand
410 break; // change state to operand
412 case emitCharactersSave:
413 // emit characters and save current character
415 if (mixedContentLevel == -1) mixedContentLevel = 0;
419 buffer.saveChar((char)currentChar);
421 break; // change state to operand
423 case possiblyEmitCharacters:
424 // write any skipped whitespace if in mixed content
426 if (mixedContentLevel != -1) buffer.flush();
427 break; // change state to operand
429 case saveAttributeName:
430 // save attribute name
432 attributeNames.addElement(buffer.getString());
433 break; // change state to operand
435 case saveAttributeValue:
436 // save attribute value
438 attributeValues.addElement(buffer.getString());
439 break; // change state to operand
442 // change state if we have found "<!--"
444 if (buffer.read() != '-') continue; // not "<!--"
446 char[] lastthree = new char[3];
449 currentChar = buffer.read();
450 lastthree[pos] = (char)currentChar;
451 if (lastthree[pos] == '>' && lastthree[(pos + 2) % 3] == '-' && lastthree[(pos + 1) % 3] == '-') break;
455 state = operands[inCharData];
456 continue; // change state to operand
459 // change state if we find "-->"
461 if ((currentChar = buffer.read()) == '-') {
462 // deal with the case where we might have "------->"
463 while ((currentChar = buffer.read()) == '-');
465 if (currentChar == '>') break; // end of comment, change state to operand
468 continue; // not end of comment, don't change state
478 if (level == 0) break; // outer level <> change state
482 continue; // in nested <>, don't change state
485 // change state if we have found "<![CDATA["
487 if (buffer.read() != 'C') continue; // don't change state
488 if (buffer.read() != 'D') continue; // don't change state
489 if (buffer.read() != 'A') continue; // don't change state
490 if (buffer.read() != 'T') continue; // don't change state
491 if (buffer.read() != 'A') continue; // don't change state
492 if (buffer.read() != '[') continue; // don't change state
493 break; // change state to operand
496 // change state if we find "]]>"
498 if ((currentChar = buffer.read()) == ']') {
499 // deal with the case where we might have "]]]]]]]>"
500 while ((currentChar = buffer.read()) == ']') buffer.write(']');
502 if (currentChar == '>') break; // end of CDATA section, change state to operand
508 buffer.write(currentChar);
509 continue; // not end of CDATA section, don't change state
512 // process character entity
516 currentChar = buffer.read();
519 if ("#amp;&pos;'quot;\"gt;>lt;<".charAt(crefState) == currentChar) {
522 if (currentChar == ';') {
523 buffer.write("#amp;&pos;'quot;\"gt;>lt;<".charAt(crefState));
526 } else if (currentChar == '#') {
529 currentChar = buffer.read();
531 if (currentChar == 'x') {
533 currentChar = buffer.read();
538 int charRef = Character.digit((char)currentChar, radix);
541 currentChar = buffer.read();
543 final int digit = Character.digit((char)currentChar, radix);
545 if (digit == -1) break;
547 charRef = (char)((charRef * radix) + digit);
550 if (currentChar == ';' && charRef != -1) {
551 buffer.write(charRef);
555 fatalError("invalid Character Entitiy", this.lineNumber, this.columnNumber);
557 currentChar = buffer.read();
560 crefState = ("\u0001\u000b\u0006\u00ff\u00ff\u00ff\u00ff\u00ff\u00ff\u00ff\u00ff" +
561 // # a m p ; & p o s ; '
562 // 0 1 2 3 4 5 6 7 8 9 a
563 "\u0011\u00ff\u00ff\u00ff\u00ff\u00ff\u0015\u00ff\u00ff\u00ff" +
564 // q u o t ; " g t ; >
565 // b b d e f 10 11 12 13 14
566 "\u00ff\u00ff\u00ff").charAt(crefState);
570 if (crefState == 255) fatalError("invalid Character Entitiy", this.lineNumber, this.columnNumber);
577 // report fatal error
579 fatalError(operand, this.lineNumber, this.columnNumber);
580 // drop through to exit parser
588 // write character data
589 // this will also write any skipped whitespace
591 buffer.write(currentChar);
592 break; // change state to operand
594 case discardAndChange:
595 // throw saved characters away and change state
598 break; // change state to operand
600 case discardSaveAndChange:
601 // throw saved characters away, save character and change state
604 // drop through to save character and change state
607 // save character and change state
609 buffer.saveChar((char)currentChar);
610 break; // change state to operand
613 // change state to operand
615 break; // change state to operand
621 catch (final IOException e) {
622 this.errorHandler.fatalError(new SAXParseException(e.toString(), null, null, this.lineNumber, this.columnNumber, e));
625 this.errorHandler = this;
626 this.documentHandler = this.extDocumentHandler = this;
627 this.tags.removeAllElements();
631 public void parse(final InputSource source) throws SAXException, IOException {
632 if (source.getCharacterStream() != null)
633 parse(source.getCharacterStream());
634 else if (source.getByteStream() != null)
635 parse(new InputStreamReader(source.getByteStream()));
637 parse(new InputStreamReader(new URL(source.getSystemId()).openStream()));
640 public void parse(final String systemId) throws SAXException, IOException {
641 parse(new InputSource(systemId));
644 public void setLocale(final Locale locale) throws SAXException {
645 throw new SAXException("Not supported");
648 public void setEntityResolver(final EntityResolver resolver) {
652 public void setDTDHandler(final DTDHandler handler) {
656 public void setDocumentHandler(final DocumentHandler handler) {
657 this.documentHandler = (handler == null) ? this : handler;
658 if (handler != null) handler.setDocumentLocator(this);
659 this.extDocumentHandler = this;
662 public void setErrorHandler(final ErrorHandler handler) {
663 this.errorHandler = (handler == null) ? this : handler;
666 public void setDocumentLocator(final Locator locator) {
669 public void startDocument() throws SAXException {
672 public Writer startDocument(final Writer writer) throws SAXException {
673 this.documentHandler.startDocument();
677 public void endDocument() throws SAXException {
680 public void startElement(final String name, final AttributeList attributes) throws SAXException {
683 public Writer startElement(final String name, final AttributeList attributes, final Writer writer)
686 this.documentHandler.startElement(name, attributes);
690 public void endElement(final String name) throws SAXException {
693 public void characters(final char ch[], final int start, final int length) throws SAXException {
696 public void ignorableWhitespace(final char ch[], final int start, final int length) throws SAXException {
699 public void processingInstruction(final String target, final String data) throws SAXException {
702 public void warning(final SAXParseException e) throws SAXException {
705 public void error(final SAXParseException e) throws SAXException {
708 public void fatalError(final SAXParseException e) throws SAXException {
712 public String getPublicId() {
717 public String getSystemId() {
721 public int getLineNumber () {
722 return this.lineNumber;
725 public int getColumnNumber () {
726 return this.columnNumber;
729 private void fatalError(final String msg, final int lineNumber, final int columnNumber) throws SAXException {
730 this.errorHandler.fatalError(new SAXParseException(msg, null, null, lineNumber, columnNumber));
733 private class MinMLBuffer extends Writer {
734 public MinMLBuffer(final Reader in) {
738 public void close() throws IOException {
742 public void flush() throws IOException {
745 if (writer != this) writer.flush();
752 public void write(final int c) throws IOException {
754 chars[count++] = (char)c;
757 public void write(final char[] cbuf, final int off, final int len) throws IOException {
759 System.arraycopy(cbuf, off, chars, count, len);
763 public void saveChar(final char c) {
768 public void pushWriter(final Writer writer) {
769 MinML.this.tags.push(this.writer);
771 this.writer = (writer == null) ? this : writer;
773 flushed = written = false;
776 public Writer getWriter() {
780 public void popWriter() throws IOException {
782 if (!flushed && writer != this) writer.flush();
785 writer = (Writer)MinML.this.tags.pop();
786 flushed = written = false;
790 public String getString() {
791 final String result = new String(chars, 0, count);
797 public void reset() {
801 public int read() throws IOException {
802 if (nextIn == lastIn) {
806 } else if (count >= (chars.length - MinML.this.bufferIncrement)) {
807 final char[] newChars = new char[chars.length + MinML.this.bufferIncrement];
809 System.arraycopy(chars, 0, newChars, 0, count);
814 final int numRead = in.read(chars, count, chars.length - count);
816 if (numRead == -1) return -1;
819 lastIn = count + numRead;
822 return chars[nextIn++];
825 private void _flush() throws IOException {
828 if (writer == this) {
830 MinML.this.documentHandler.characters(chars, 0, count);
832 catch (final SAXException e) {
833 throw new IOException(e.toString());
836 writer.write(chars, 0, count);
845 private int nextIn = 0, lastIn = 0;
846 private char[] chars = new char[MinML.this.initialBufferSize];
847 private final Reader in;
848 private int count = 0;
849 private Writer writer = this;
850 private boolean flushed = false;
851 private boolean written = false;
854 private DocumentHandler extDocumentHandler = this;
855 private DocumentHandler documentHandler = this;
856 private ErrorHandler errorHandler = this;
857 private final Stack tags = new Stack();
858 private int lineNumber = 1;
859 private int columnNumber = 0;
860 private final int initialBufferSize;
861 private final int bufferIncrement;
863 private static final byte[] charClasses = {
867 -1, -1, -1, -1, -1, -1, -1, -1, -1, 12, 12, -1, -1, 12, -1, -1,
869 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
870 // SP ! " # $ % & ' ( ) * + , - . /
871 12, 8, 7, 14, 14, 14, 3, 6, 14, 14, 14, 14, 14, 11, 14, 2,
872 // 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
873 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 5, 1, 4,
875 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
877 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 9, 14, 10
880 private static final String[] operands = {
881 "\u0d15\u1611\u1611\u1611\u1611\u1611\u1611\u1611\u1611\u1611\u1611\u1611\u0015\u0010\u1611",
882 "\u1711\u1000\u0b00\u1711\u1711\u1711\u1711\u1711\u1711\u1711\u1711\u0114\u0200\u1811\u0114",
883 "\u1711\u1001\u0b01\u1711\u1711\u1711\u1711\u1711\u1711\u1711\u1711\u1711\u0215\u1811\u0414",
884 "\u1711\u1001\u0b01\u1711\u1911\u1911\u1911\u1911\u1911\u1911\u1911\u1911\u0315\u1811\u0414",
885 "\u1911\u1911\u1911\u1911\u1911\u0606\u1911\u1911\u1911\u1911\u1911\u0414\u0515\u1811\u0414",
886 "\u1911\u1911\u1911\u1911\u1911\u0606\u1911\u1911\u1911\u1911\u1911\u1911\u0515\u1811\u1911",
887 "\u1a11\u1a11\u1a11\u1a11\u1a11\u1a11\u0715\u0815\u1a11\u1a11\u1a11\u1a11\u0615\u1811\u1a11",
888 "\u0714\u0714\u0714\u070e\u0714\u0714\u0307\u0714\u0714\u0714\u0714\u0714\u0714\u1811\u0714",
889 "\u0814\u0814\u0814\u080e\u0814\u0814\u0814\u0307\u0814\u0814\u0814\u0814\u0814\u1811\u0814",
890 "\u1711\u1002\u1711\u1711\u1711\u1711\u1711\u1711\u1711\u1711\u1711\u0914\u0915\u1811\u0914",
891 "\u1b11\u1b11\u0904\u1b11\u1b11\u1b11\u1b11\u1b11\u1215\u1b11\u1b11\u1b11\u1b11\u1811\u0105",
892 "\u1711\u1012\u1711\u1711\u1711\u1711\u1711\u1711\u1711\u1711\u1711\u1711\u1711\u1811\u1711",
893 "\u1711\u1c11\u0912\u1711\u0e12\u1711\u1711\u1711\u1212\u1711\u1711\u1711\u1711\u1811\u0113",
894 "\u1711\u1c11\u0912\u1711\u0e12\u1711\u1711\u1711\u1212\u1711\u1711\u1711\u1711\u1811\u0113",
895 "\u0e15\u0e15\u0e15\u0e15\u0f15\u0e15\u0e15\u0e15\u0e15\u0e15\u0e15\u0e15\u0e15\u1811\u0e15",
896 "\u0e15\u0015\u0e15\u0e15\u0f15\u0e15\u0e15\u0e15\u0e15\u0e15\u0e15\u0e15\u0e15\u1811\u0e15",
897 "\u0c03\u110f\u110f\u110e\u110f\u110f\u110f\u110f\u110f\u110f\u110f\u110f\u1014\u1811\u110f",
898 "\u0a15\u110f\u110f\u110e\u110f\u110f\u110f\u110f\u110f\u110f\u110f\u110f\u110f\u1811\u110f",
899 "\u1d11\u1d11\u1d11\u1d11\u1d11\u1d11\u1d11\u1d11\u1d11\u130c\u1d11\u1408\u1d11\u1811\u1515",
900 "\u130f\u130f\u130f\u130f\u130f\u130f\u130f\u130f\u130f\u130f\u110d\u130f\u130f\u1811\u130f",
901 "\u1415\u1415\u1415\u1415\u1415\u1415\u1415\u1415\u1415\u1415\u1415\u0009\u1415\u1811\u1415",
902 "\u150a\u000b\u1515\u1515\u1515\u1515\u1515\u1515\u1515\u1515\u1515\u1515\u1515\u1811\u1515",
904 "unexpected character in tag",
905 "unexpected end of file found",
906 "attribute name not followed by '='",
907 "invalid attribute value",
910 "unexpected character after <!"
913 ///////////////////////////////////////////////////////////////////////////////
915 private class XMLHelper implements DocumentHandler {
916 private MinML minml = new MinML();
918 public void parse(Reader r) throws IOException, XML.SAXException {
919 minml.setDocumentHandler(this);
920 minml.parse(new InputSource(r));
923 public void startDocument() throws SAXException { }
924 public void endDocument() throws SAXException { }
925 public void processingInstruction (String target, String data) throws SAXException { }
926 public Writer startDocument(final Writer writer) throws SAXException { return null; }
927 public Writer startElement(final String name, final AttributeList attributes, final Writer writer) throws SAXException { return null; }
929 public void setDocumentLocator (Locator locator) {
930 this.locator = locator;
933 private Locator locator = null;
935 public void startElement(String name, AttributeList atts) throws SAXException {
936 String[] keys = new String[atts.getLength()];
937 Object[] vals = new Object[atts.getLength()];
938 for (int i=0; i <atts.getLength(); i++) {
939 keys[i] = atts.getName(i);
940 vals[i] = atts.getValue(i).toString();
942 XML.this.startElement(name, keys, vals,
943 locator == null ? 0 : locator.getLineNumber(), locator == null ? 0 : locator.getColumnNumber());
946 public void endElement(String name) throws SAXException {
947 XML.this.endElement(name, locator == null ? 0 : locator.getLineNumber(), locator == null ? 0 : locator.getColumnNumber());
950 public void characters(char ch[], int start, int length) throws SAXException {
951 XML.this.content(ch, start, length, locator == null ? 0 : locator.getLineNumber(), locator == null ? 0 : locator.getColumnNumber());
953 public void ignorableWhitespace(char ch[], int start, int length) throws SAXException {
954 XML.this.content(ch, start, length, locator == null ? 0 : locator.getLineNumber(), locator == null ? 0 : locator.getColumnNumber());
959 public void parse(Reader r) throws IOException, XML.SAXException {
960 XMLHelper helper = new XMLHelper();
965 /** indicates the start of an element with name <tt>name</tt>, and attributes <tt>attributes</tt>, starting on line <tt>line</tt> */
966 public abstract void startElement(String name, String[] keys, Object[] vals, int line, int col) throws SAXException;
968 /** indicates the end of an element with name <tt>name</tt>, starting on line <tt>line</tt> */
969 public abstract void endElement(String name, int line, int col) throws SAXException;
971 /** indicates a chunk of CDATA content, starting on line <tt>line</tt> */
972 public abstract void content(char[] content, int start, int length, int line, int col) throws SAXException;