001: /*
002: * Copyright 1999-2004 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.outerj.daisy.xmlutil;
017:
018: import org.xml.sax.ContentHandler;
019: import org.xml.sax.SAXException;
020: import org.xml.sax.Locator;
021: import org.xml.sax.Attributes;
022: import org.xml.sax.ext.LexicalHandler;
023:
024: import java.util.List;
025: import java.util.ArrayList;
026: import java.util.Iterator;
027: import java.util.Collections;
028: import java.io.Serializable;
029: import java.io.IOException;
030: import java.io.Writer;
031:
032: /**
033: * A class that can record SAX events and replay them later.
034: *
035: * <p>This class was copied form the Apache Cocoon.
036: */
037: public class SaxBuffer implements ContentHandler, LexicalHandler,
038: Serializable {
039:
040: /**
041: * Stores list of {@link SaxBit} objects.
042: */
043: protected List<SaxBit> saxbits = new ArrayList<SaxBit>();
044:
045: /**
046: * Creates empty SaxBuffer
047: */
048: public SaxBuffer() {
049: }
050:
051: /**
052: * Creates copy of another SaxBuffer
053: */
054: public SaxBuffer(SaxBuffer saxBuffer) {
055: this .saxbits.addAll(saxBuffer.saxbits);
056: }
057:
058: public void skippedEntity(String name) throws SAXException {
059: saxbits.add(new SkippedEntity(name));
060: }
061:
062: public void setDocumentLocator(Locator locator) {
063: // don't record this event
064: }
065:
066: public void ignorableWhitespace(char ch[], int start, int length)
067: throws SAXException {
068: saxbits.add(new IgnorableWhitespace(ch, start, length));
069: }
070:
071: public void processingInstruction(String target, String data)
072: throws SAXException {
073: saxbits.add(new PI(target, data));
074: }
075:
076: public void startDocument() throws SAXException {
077: saxbits.add(StartDocument.SINGLETON);
078: }
079:
080: public void startElement(String namespaceURI, String localName,
081: String qName, Attributes atts) throws SAXException {
082: saxbits.add(new StartElement(namespaceURI, localName, qName,
083: atts));
084: }
085:
086: public void endPrefixMapping(String prefix) throws SAXException {
087: saxbits.add(new EndPrefixMapping(prefix));
088: }
089:
090: public void characters(char ch[], int start, int length)
091: throws SAXException {
092: saxbits.add(new Characters(ch, start, length));
093: }
094:
095: public void endElement(String namespaceURI, String localName,
096: String qName) throws SAXException {
097: saxbits.add(new EndElement(namespaceURI, localName, qName));
098: }
099:
100: public void endDocument() throws SAXException {
101: saxbits.add(EndDocument.SINGLETON);
102: }
103:
104: public void startPrefixMapping(String prefix, String uri)
105: throws SAXException {
106: saxbits.add(new StartPrefixMapping(prefix, uri));
107: }
108:
109: public void endCDATA() throws SAXException {
110: saxbits.add(EndCDATA.SINGLETON);
111: }
112:
113: public void comment(char ch[], int start, int length)
114: throws SAXException {
115: saxbits.add(new Comment(ch, start, length));
116: }
117:
118: public void startEntity(String name) throws SAXException {
119: saxbits.add(new StartEntity(name));
120: }
121:
122: public void endDTD() throws SAXException {
123: saxbits.add(EndDTD.SINGLETON);
124: }
125:
126: public void startDTD(String name, String publicId, String systemId)
127: throws SAXException {
128: saxbits.add(new StartDTD(name, publicId, systemId));
129: }
130:
131: public void startCDATA() throws SAXException {
132: saxbits.add(StartCDATA.SINGLETON);
133: }
134:
135: public void endEntity(String name) throws SAXException {
136: saxbits.add(new EndEntity(name));
137: }
138:
139: /**
140: * Adds a SaxBit to the bits list
141: */
142: protected final void addBit(SaxBit bit) {
143: saxbits.add(bit);
144: }
145:
146: /**
147: * Iterates through the bits list
148: */
149: protected final Iterator bits() {
150: return saxbits.iterator();
151: }
152:
153: public boolean isEmpty() {
154: return saxbits.isEmpty();
155: }
156:
157: public List<SaxBit> getBits() {
158: return Collections.unmodifiableList(saxbits);
159: }
160:
161: public void toSAX(ContentHandler contentHandler)
162: throws SAXException {
163: for (SaxBit saxbit : saxbits) {
164: saxbit.send(contentHandler);
165: }
166: }
167:
168: /*
169: * NOTE: Used in i18n XML bundle implementation
170: */
171: public String toString() {
172: StringBuilder value = new StringBuilder();
173: for (SaxBit saxbit : saxbits) {
174: if (saxbit instanceof Characters) {
175: ((Characters) saxbit).toString(value);
176: }
177: }
178:
179: return value.toString();
180: }
181:
182: public void recycle() {
183: saxbits.clear();
184: }
185:
186: public void dump(Writer writer) throws IOException {
187: for (SaxBit saxbit : saxbits) {
188: saxbit.dump(writer);
189: }
190: writer.flush();
191: }
192:
193: /**
194: * SaxBit is a representation of the SAX event. Every SaxBit is immutable object.
195: */
196: public interface SaxBit {
197: public void send(ContentHandler contentHandler)
198: throws SAXException;
199:
200: public void dump(Writer writer) throws IOException;
201: }
202:
203: public static final class StartDocument implements SaxBit,
204: Serializable {
205: public static final StartDocument SINGLETON = new StartDocument();
206:
207: public void send(ContentHandler contentHandler)
208: throws SAXException {
209: contentHandler.startDocument();
210: }
211:
212: public void dump(Writer writer) throws IOException {
213: writer.write("[StartDocument]\n");
214: }
215: }
216:
217: public static final class EndDocument implements SaxBit,
218: Serializable {
219: public static final EndDocument SINGLETON = new EndDocument();
220:
221: public void send(ContentHandler contentHandler)
222: throws SAXException {
223: contentHandler.endDocument();
224: }
225:
226: public void dump(Writer writer) throws IOException {
227: writer.write("[EndDocument]\n");
228: }
229: }
230:
231: public static final class PI implements SaxBit, Serializable {
232: public final String target;
233: public final String data;
234:
235: public PI(String target, String data) {
236: this .target = target;
237: this .data = data;
238: }
239:
240: public void send(ContentHandler contentHandler)
241: throws SAXException {
242: contentHandler.processingInstruction(target, data);
243: }
244:
245: public void dump(Writer writer) throws IOException {
246: writer.write("[ProcessingInstruction] target=" + target
247: + ",data=" + data + "\n");
248: }
249: }
250:
251: public static final class StartDTD implements SaxBit, Serializable {
252: public final String name;
253: public final String publicId;
254: public final String systemId;
255:
256: public StartDTD(String name, String publicId, String systemId) {
257: this .name = name;
258: this .publicId = publicId;
259: this .systemId = systemId;
260: }
261:
262: public void send(ContentHandler contentHandler)
263: throws SAXException {
264: if (contentHandler instanceof LexicalHandler)
265: ((LexicalHandler) contentHandler).startDTD(name,
266: publicId, systemId);
267: }
268:
269: public void dump(Writer writer) throws IOException {
270: writer.write("[StartDTD] name=" + name + ",publicId="
271: + publicId + ",systemId=" + systemId + "\n");
272: }
273: }
274:
275: public static final class EndDTD implements SaxBit, Serializable {
276: public static final EndDTD SINGLETON = new EndDTD();
277:
278: public void send(ContentHandler contentHandler)
279: throws SAXException {
280: if (contentHandler instanceof LexicalHandler)
281: ((LexicalHandler) contentHandler).endDTD();
282: }
283:
284: public void dump(Writer writer) throws IOException {
285: writer.write("[EndDTD]\n");
286: }
287: }
288:
289: public static final class StartEntity implements SaxBit,
290: Serializable {
291: public final String name;
292:
293: public StartEntity(String name) {
294: this .name = name;
295: }
296:
297: public void send(ContentHandler contentHandler)
298: throws SAXException {
299: if (contentHandler instanceof LexicalHandler)
300: ((LexicalHandler) contentHandler).startEntity(name);
301: }
302:
303: public void dump(Writer writer) throws IOException {
304: writer.write("[StartEntity] name=" + name + "\n");
305: }
306: }
307:
308: public static final class EndEntity implements SaxBit, Serializable {
309: public final String name;
310:
311: public EndEntity(String name) {
312: this .name = name;
313: }
314:
315: public void send(ContentHandler contentHandler)
316: throws SAXException {
317: if (contentHandler instanceof LexicalHandler)
318: ((LexicalHandler) contentHandler).endEntity(name);
319: }
320:
321: public void dump(Writer writer) throws IOException {
322: writer.write("[EndEntity] name=" + name + "\n");
323: }
324: }
325:
326: public static final class SkippedEntity implements SaxBit,
327: Serializable {
328: public final String name;
329:
330: public SkippedEntity(String name) {
331: this .name = name;
332: }
333:
334: public void send(ContentHandler contentHandler)
335: throws SAXException {
336: contentHandler.skippedEntity(name);
337: }
338:
339: public void dump(Writer writer) throws IOException {
340: writer.write("[SkippedEntity] name=" + name + "\n");
341: }
342: }
343:
344: public static final class StartPrefixMapping implements SaxBit,
345: Serializable {
346: public final String prefix;
347: public final String uri;
348:
349: public StartPrefixMapping(String prefix, String uri) {
350: this .prefix = prefix;
351: this .uri = uri;
352: }
353:
354: public void send(ContentHandler contentHandler)
355: throws SAXException {
356: contentHandler.startPrefixMapping(prefix, uri);
357: }
358:
359: public void dump(Writer writer) throws IOException {
360: writer.write("[StartPrefixMapping] prefix=" + prefix
361: + ",uri=" + uri + "\n");
362: }
363: }
364:
365: public static final class EndPrefixMapping implements SaxBit,
366: Serializable {
367: public final String prefix;
368:
369: public EndPrefixMapping(String prefix) {
370: this .prefix = prefix;
371: }
372:
373: public void send(ContentHandler contentHandler)
374: throws SAXException {
375: contentHandler.endPrefixMapping(prefix);
376: }
377:
378: public void dump(Writer writer) throws IOException {
379: writer.write("[EndPrefixMapping] prefix=" + prefix + "\n");
380: }
381: }
382:
383: public static final class StartElement implements SaxBit,
384: Serializable {
385: public final String namespaceURI;
386: public final String localName;
387: public final String qName;
388: public final Attributes attrs;
389:
390: public StartElement(String namespaceURI, String localName,
391: String qName, Attributes attrs) {
392: this .namespaceURI = namespaceURI;
393: this .localName = localName;
394: this .qName = qName;
395: this .attrs = new org.xml.sax.helpers.AttributesImpl(attrs);
396: }
397:
398: public void send(ContentHandler contentHandler)
399: throws SAXException {
400: contentHandler.startElement(namespaceURI, localName, qName,
401: attrs);
402: }
403:
404: public void dump(Writer writer) throws IOException {
405: writer.write("[StartElement] namespaceURI=" + namespaceURI
406: + ",localName=" + localName + ",qName=" + qName
407: + "\n");
408: for (int i = 0; i < attrs.getLength(); i++) {
409: writer.write(" [Attribute] namespaceURI="
410: + attrs.getURI(i) + ",localName="
411: + attrs.getLocalName(i) + ",qName="
412: + attrs.getQName(i) + ",type="
413: + attrs.getType(i) + ",value="
414: + attrs.getValue(i) + "\n");
415: }
416: }
417: }
418:
419: public static final class EndElement implements SaxBit,
420: Serializable {
421: public final String namespaceURI;
422: public final String localName;
423: public final String qName;
424:
425: public EndElement(String namespaceURI, String localName,
426: String qName) {
427: this .namespaceURI = namespaceURI;
428: this .localName = localName;
429: this .qName = qName;
430: }
431:
432: public void send(ContentHandler contentHandler)
433: throws SAXException {
434: contentHandler.endElement(namespaceURI, localName, qName);
435: }
436:
437: public void dump(Writer writer) throws IOException {
438: writer.write("[EndElement] namespaceURI=" + namespaceURI
439: + ",localName=" + localName + ",qName=" + qName
440: + "\n");
441: }
442: }
443:
444: public static final class Characters implements SaxBit,
445: Serializable {
446: public final char[] ch;
447:
448: public Characters(char[] ch, int start, int length) {
449: // make a copy so that we don't hold references to a potentially large array we don't control
450: this .ch = new char[length];
451: System.arraycopy(ch, start, this .ch, 0, length);
452: }
453:
454: public void send(ContentHandler contentHandler)
455: throws SAXException {
456: contentHandler.characters(ch, 0, ch.length);
457: }
458:
459: public void toString(StringBuilder value) {
460: value.append(ch);
461: }
462:
463: public void dump(Writer writer) throws IOException {
464: writer.write("[Characters] ch=" + new String(ch) + "\n");
465: }
466: }
467:
468: public static final class Comment implements SaxBit, Serializable {
469: public final char[] ch;
470:
471: public Comment(char[] ch, int start, int length) {
472: // make a copy so that we don't hold references to a potentially large array we don't control
473: this .ch = new char[length];
474: System.arraycopy(ch, start, this .ch, 0, length);
475: }
476:
477: public void send(ContentHandler contentHandler)
478: throws SAXException {
479: if (contentHandler instanceof LexicalHandler)
480: ((LexicalHandler) contentHandler).comment(ch, 0,
481: ch.length);
482: }
483:
484: public void dump(Writer writer) throws IOException {
485: writer.write("[Comment] ch=" + new String(ch) + "\n");
486: }
487: }
488:
489: public static final class StartCDATA implements SaxBit,
490: Serializable {
491: public static final StartCDATA SINGLETON = new StartCDATA();
492:
493: public void send(ContentHandler contentHandler)
494: throws SAXException {
495: if (contentHandler instanceof LexicalHandler)
496: ((LexicalHandler) contentHandler).startCDATA();
497: }
498:
499: public void dump(Writer writer) throws IOException {
500: writer.write("[StartCDATA]\n");
501: }
502: }
503:
504: public static final class EndCDATA implements SaxBit, Serializable {
505: public static final EndCDATA SINGLETON = new EndCDATA();
506:
507: public void send(ContentHandler contentHandler)
508: throws SAXException {
509: if (contentHandler instanceof LexicalHandler)
510: ((LexicalHandler) contentHandler).endCDATA();
511: }
512:
513: public void dump(Writer writer) throws IOException {
514: writer.write("[EndCDATA]\n");
515: }
516: }
517:
518: public static final class IgnorableWhitespace implements SaxBit,
519: Serializable {
520: public final char[] ch;
521:
522: public IgnorableWhitespace(char[] ch, int start, int length) {
523: // make a copy so that we don't hold references to a potentially large array we don't control
524: this .ch = new char[length];
525: System.arraycopy(ch, start, this .ch, 0, length);
526: }
527:
528: public void send(ContentHandler contentHandler)
529: throws SAXException {
530: contentHandler.ignorableWhitespace(ch, 0, ch.length);
531: }
532:
533: public void dump(Writer writer) throws IOException {
534: writer.write("IgnorableWhitespace] ch=" + new String(ch)
535: + "\n");
536: }
537: }
538: }
|