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;
231 public static final int writeAsWS = 22;
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 state = operands[inComment];
447 continue; // change state to operand
450 // change state if we find "-->"
452 if ((currentChar = buffer.read()) == '-') {
453 // deal with the case where we might have "------->"
454 while ((currentChar = buffer.read()) == '-');
456 if (currentChar == '>') {
457 state = operands[inCharData];
461 continue; // not end of comment, don't change state
471 if (level == 0) break; // outer level <> change state
475 continue; // in nested <>, don't change state
478 // change state if we have found "<![CDATA["
480 if (buffer.read() != 'C') continue; // don't change state
481 if (buffer.read() != 'D') continue; // don't change state
482 if (buffer.read() != 'A') continue; // don't change state
483 if (buffer.read() != 'T') continue; // don't change state
484 if (buffer.read() != 'A') continue; // don't change state
485 if (buffer.read() != '[') continue; // don't change state
486 break; // change state to operand
489 // change state if we find "]]>"
491 if ((currentChar = buffer.read()) == ']') {
492 // deal with the case where we might have "]]]]]]]>"
493 while ((currentChar = buffer.read()) == ']') buffer.write(']');
495 if (currentChar == '>') break; // end of CDATA section, change state to operand
501 buffer.write(currentChar);
502 continue; // not end of CDATA section, don't change state
505 // process character entity
509 currentChar = buffer.read();
512 if ("#amp;&pos;'quot;\"gt;>lt;<".charAt(crefState) == currentChar) {
515 if (currentChar == ';') {
516 buffer.write("#amp;&pos;'quot;\"gt;>lt;<".charAt(crefState));
519 } else if (currentChar == '#') {
522 currentChar = buffer.read();
524 if (currentChar == 'x') {
526 currentChar = buffer.read();
531 int charRef = Character.digit((char)currentChar, radix);
534 currentChar = buffer.read();
536 final int digit = Character.digit((char)currentChar, radix);
538 if (digit == -1) break;
540 charRef = (char)((charRef * radix) + digit);
543 if (currentChar == ';' && charRef != -1) {
544 buffer.write(charRef);
548 fatalError("invalid Character Entitiy", this.lineNumber, this.columnNumber);
550 currentChar = buffer.read();
553 crefState = ("\u0001\u000b\u0006\u00ff\u00ff\u00ff\u00ff\u00ff\u00ff\u00ff\u00ff" +
554 // # a m p ; & p o s ; '
555 // 0 1 2 3 4 5 6 7 8 9 a
556 "\u0011\u00ff\u00ff\u00ff\u00ff\u00ff\u0015\u00ff\u00ff\u00ff" +
557 // q u o t ; " g t ; >
558 // b b d e f 10 11 12 13 14
559 "\u00ff\u00ff\u00ff").charAt(crefState);
563 if (crefState == 255) fatalError("invalid Character Entitiy", this.lineNumber, this.columnNumber);
570 // report fatal error
572 fatalError(operand, this.lineNumber, this.columnNumber);
573 // drop through to exit parser
581 // write character data
582 // this will also write any skipped whitespace
584 buffer.write(currentChar);
585 break; // change state to operand
588 buffer.write((currentChar == '\n' ? currentChar : (char)32));
591 case discardAndChange:
592 // throw saved characters away and change state
595 break; // change state to operand
597 case discardSaveAndChange:
598 // throw saved characters away, save character and change state
601 // drop through to save character and change state
604 // save character and change state
606 buffer.saveChar((char)currentChar);
607 break; // change state to operand
610 // change state to operand
612 break; // change state to operand
618 catch (final IOException e) {
619 this.errorHandler.fatalError(new SAXParseException(e.toString(), null, null, this.lineNumber, this.columnNumber, e));
622 this.errorHandler = this;
623 this.documentHandler = this.extDocumentHandler = this;
624 this.tags.removeAllElements();
628 public void parse(final InputSource source) throws SAXException, IOException {
629 if (source.getCharacterStream() != null)
630 parse(source.getCharacterStream());
631 else if (source.getByteStream() != null)
632 parse(new InputStreamReader(source.getByteStream()));
634 parse(new InputStreamReader(new URL(source.getSystemId()).openStream()));
637 public void parse(final String systemId) throws SAXException, IOException {
638 parse(new InputSource(systemId));
641 public void setLocale(final Locale locale) throws SAXException {
642 throw new SAXException("Not supported");
645 public void setEntityResolver(final EntityResolver resolver) {
649 public void setDTDHandler(final DTDHandler handler) {
653 public void setDocumentHandler(final DocumentHandler handler) {
654 this.documentHandler = (handler == null) ? this : handler;
655 if (handler != null) handler.setDocumentLocator(this);
656 this.extDocumentHandler = this;
659 public void setErrorHandler(final ErrorHandler handler) {
660 this.errorHandler = (handler == null) ? this : handler;
663 public void setDocumentLocator(final Locator locator) {
666 public void startDocument() throws SAXException {
669 public Writer startDocument(final Writer writer) throws SAXException {
670 this.documentHandler.startDocument();
674 public void endDocument() throws SAXException {
677 public void startElement(final String name, final AttributeList attributes) throws SAXException {
680 public Writer startElement(final String name, final AttributeList attributes, final Writer writer)
683 this.documentHandler.startElement(name, attributes);
687 public void endElement(final String name) throws SAXException {
690 public void characters(final char ch[], final int start, final int length) throws SAXException {
693 public void ignorableWhitespace(final char ch[], final int start, final int length) throws SAXException {
696 public void processingInstruction(final String target, final String data) throws SAXException {
699 public void warning(final SAXParseException e) throws SAXException {
702 public void error(final SAXParseException e) throws SAXException {
705 public void fatalError(final SAXParseException e) throws SAXException {
709 public String getPublicId() {
714 public String getSystemId() {
718 public int getLineNumber () {
719 return this.lineNumber;
722 public int getColumnNumber () {
723 return this.columnNumber;
726 private void fatalError(final String msg, final int lineNumber, final int columnNumber) throws SAXException {
727 this.errorHandler.fatalError(new SAXParseException(msg, null, null, lineNumber, columnNumber));
730 private class MinMLBuffer extends Writer {
731 public MinMLBuffer(final Reader in) {
735 public void close() throws IOException {
739 public void flush() throws IOException {
742 if (writer != this) writer.flush();
749 public void write(final int c) throws IOException {
751 chars[count++] = (char)c;
754 public void write(final char[] cbuf, final int off, final int len) throws IOException {
756 System.arraycopy(cbuf, off, chars, count, len);
760 public void saveChar(final char c) {
765 public void pushWriter(final Writer writer) {
766 MinML.this.tags.push(this.writer);
768 this.writer = (writer == null) ? this : writer;
770 flushed = written = false;
773 public Writer getWriter() {
777 public void popWriter() throws IOException {
779 if (!flushed && writer != this) writer.flush();
782 writer = (Writer)MinML.this.tags.pop();
783 flushed = written = false;
787 public String getString() {
788 final String result = new String(chars, 0, count);
794 public void reset() {
798 public int read() throws IOException {
799 if (nextIn == lastIn) {
803 } else if (count >= (chars.length - MinML.this.bufferIncrement)) {
804 final char[] newChars = new char[chars.length + MinML.this.bufferIncrement];
806 System.arraycopy(chars, 0, newChars, 0, count);
811 final int numRead = in.read(chars, count, chars.length - count);
813 if (numRead == -1) return -1;
816 lastIn = count + numRead;
819 return chars[nextIn++];
822 private void _flush() throws IOException {
825 if (writer == this) {
827 MinML.this.documentHandler.characters(chars, 0, count);
829 catch (final SAXException e) {
830 throw new IOException(e.toString());
833 writer.write(chars, 0, count);
842 private int nextIn = 0, lastIn = 0;
843 private char[] chars = new char[MinML.this.initialBufferSize];
844 private final Reader in;
845 private int count = 0;
846 private Writer writer = this;
847 private boolean flushed = false;
848 private boolean written = false;
851 private DocumentHandler extDocumentHandler = this;
852 private DocumentHandler documentHandler = this;
853 private ErrorHandler errorHandler = this;
854 private final Stack tags = new Stack();
855 private int lineNumber = 1;
856 private int columnNumber = 0;
857 private final int initialBufferSize;
858 private final int bufferIncrement;
860 private static final byte[] charClasses = {
864 -1, -1, -1, -1, -1, -1, -1, -1, -1, 12, 12, -1, -1, 12, -1, -1,
866 -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
867 // SP ! " # $ % & ' ( ) * + , - . /
868 12, 8, 7, 14, 14, 14, 3, 6, 14, 14, 14, 14, 14, 11, 14, 2,
869 // 0 1 2 3 4 5 6 7 8 9 : ; < = > ?
870 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 0, 5, 1, 4,
872 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
874 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 9, 14, 10
877 private static final String[] operands = {
878 "\u0d15\u1611\u1611\u1611\u1611\u1611\u1611\u1611\u1611\u1611\u1611\u1611\u0015\u0010\u1611",
879 "\u1711\u1000\u0b00\u1711\u1711\u1711\u1711\u1711\u1711\u1711\u1711\u0114\u0200\u1811\u0114",
880 "\u1711\u1001\u0b01\u1711\u1711\u1711\u1711\u1711\u1711\u1711\u1711\u1711\u0215\u1811\u0414",
881 "\u1711\u1001\u0b01\u1711\u1911\u1911\u1911\u1911\u1911\u1911\u1911\u1911\u0315\u1811\u0414",
882 "\u1911\u1911\u1911\u1911\u1911\u0606\u1911\u1911\u1911\u1911\u1911\u0414\u0515\u1811\u0414",
883 "\u1911\u1911\u1911\u1911\u1911\u0606\u1911\u1911\u1911\u1911\u1911\u1911\u0515\u1811\u1911",
884 "\u1a11\u1a11\u1a11\u1a11\u1a11\u1a11\u0715\u0815\u1a11\u1a11\u1a11\u1a11\u0615\u1811\u1a11",
885 "\u0714\u0714\u0714\u070e\u0714\u0714\u0307\u0714\u0714\u0714\u0714\u0714\u0714\u1811\u0714",
886 "\u0814\u0814\u0814\u080e\u0814\u0814\u0814\u0307\u0814\u0814\u0814\u0814\u0814\u1811\u0814",
887 "\u1711\u1002\u1711\u1711\u1711\u1711\u1711\u1711\u1711\u1711\u1711\u0914\u0915\u1811\u0914",
888 "\u1b11\u1b11\u0904\u1b11\u1b11\u1b11\u1b11\u1b11\u1215\u1b11\u1b11\u1b11\u1b11\u1811\u0105",
889 "\u1711\u1012\u1711\u1711\u1711\u1711\u1711\u1711\u1711\u1711\u1711\u1711\u1711\u1811\u1711",
890 "\u1711\u1c11\u0912\u1711\u0e12\u1711\u1711\u1711\u1212\u1711\u1711\u1711\u1711\u1811\u0113",
891 "\u1711\u1c11\u0912\u1711\u0e12\u1711\u1711\u1711\u1212\u1711\u1711\u1711\u1711\u1811\u0113",
892 "\u0e15\u0e15\u0e15\u0e15\u0f15\u0e15\u0e15\u0e15\u0e15\u0e15\u0e15\u0e15\u0e15\u1811\u0e15",
893 "\u0e15\u0015\u0e15\u0e15\u0f15\u0e15\u0e15\u0e15\u0e15\u0e15\u0e15\u0e15\u0e15\u1811\u0e15",
894 "\u0c03\u110f\u110f\u110e\u110f\u110f\u110f\u110f\u110f\u110f\u110f\u110f\u1014\u1811\u110f",
895 "\u0a15\u110f\u110f\u110e\u110f\u110f\u110f\u110f\u110f\u110f\u110f\u110f\u110f\u1811\u110f",
896 "\u1d11\u1d11\u1d11\u1d11\u1d11\u1d11\u1d11\u1d11\u1d11\u130c\u1d11\u1408\u1d11\u1811\u1515",
897 "\u130f\u130f\u130f\u130f\u130f\u130f\u130f\u130f\u130f\u130f\u110d\u130f\u130f\u1811\u130f",
898 "\u1416\u1416\u1416\u1416\u1416\u1416\u1416\u1416\u1416\u1416\u1416\u0009\u1416\u1811\u1416",
899 // "\u1415\u1415\u1415\u1415\u1415\u1415\u1415\u1415\u1415\u1415\u1415\u0009\u1415\u1811\u1415",
900 "\u150a\u000b\u1515\u1515\u1515\u1515\u1515\u1515\u1515\u1515\u1515\u1515\u1515\u1811\u1515",
902 "unexpected character in tag",
903 "unexpected end of file found",
904 "attribute name not followed by '='",
905 "invalid attribute value",
908 "unexpected character after <!"
911 ///////////////////////////////////////////////////////////////////////////////
913 private class XMLHelper implements DocumentHandler {
914 private MinML minml = new MinML();
916 public void parse(Reader r) throws IOException, XML.SAXException {
917 minml.setDocumentHandler(this);
918 minml.parse(new InputSource(r));
921 public void startDocument() throws SAXException { }
922 public void endDocument() throws SAXException { }
923 public void processingInstruction (String target, String data) throws SAXException { }
924 public Writer startDocument(final Writer writer) throws SAXException { return null; }
925 public Writer startElement(final String name, final AttributeList attributes, final Writer writer) throws SAXException { return null; }
927 public void setDocumentLocator (Locator locator) {
928 this.locator = locator;
931 private Locator locator = null;
933 public void startElement(String name, AttributeList atts) throws SAXException {
934 String[] keys = new String[atts.getLength()];
935 Object[] vals = new Object[atts.getLength()];
936 for (int i=0; i <atts.getLength(); i++) {
937 keys[i] = atts.getName(i);
938 vals[i] = atts.getValue(i).toString();
940 XML.this.startElement(name, keys, vals,
941 locator == null ? 0 : locator.getLineNumber(), locator == null ? 0 : locator.getColumnNumber());
944 public void endElement(String name) throws SAXException {
945 XML.this.endElement(name, locator == null ? 0 : locator.getLineNumber(), locator == null ? 0 : locator.getColumnNumber());
948 public void characters(char ch[], int start, int length) throws SAXException {
949 XML.this.content(ch, start, length, locator == null ? 0 : locator.getLineNumber(), locator == null ? 0 : locator.getColumnNumber());
951 public void ignorableWhitespace(char ch[], int start, int length) throws SAXException {
952 XML.this.content(ch, start, length, locator == null ? 0 : locator.getLineNumber(), locator == null ? 0 : locator.getColumnNumber());
957 public void parse(Reader r) throws IOException, XML.SAXException {
958 XMLHelper helper = new XMLHelper();
963 /** indicates the start of an element with name <tt>name</tt>, and attributes <tt>attributes</tt>, starting on line <tt>line</tt> */
964 public abstract void startElement(String name, String[] keys, Object[] vals, int line, int col) throws SAXException;
966 /** indicates the end of an element with name <tt>name</tt>, starting on line <tt>line</tt> */
967 public abstract void endElement(String name, int line, int col) throws SAXException;
969 /** indicates a chunk of CDATA content, starting on line <tt>line</tt> */
970 public abstract void content(char[] content, int start, int length, int line, int col) throws SAXException;