001: /*
002: * (C) Copyright 2002-2003, Andy Clark. All rights reserved.
003: *
004: * This file is distributed under an Apache style license. Please
005: * refer to the LICENSE file for specific details.
006: */
007:
008: package org.cyberneko.pull.util;
009:
010: import java.lang.reflect.InvocationTargetException;
011: import java.lang.reflect.Method;
012:
013: import org.cyberneko.pull.XMLEvent;
014: import org.cyberneko.pull.event.CDATAEvent;
015: import org.cyberneko.pull.event.CharactersEvent;
016: import org.cyberneko.pull.event.CommentEvent;
017: import org.cyberneko.pull.event.DoctypeDeclEvent;
018: import org.cyberneko.pull.event.DocumentEvent;
019: import org.cyberneko.pull.event.ElementEvent;
020: import org.cyberneko.pull.event.GeneralEntityEvent;
021: import org.cyberneko.pull.event.PrefixMappingEvent;
022: import org.cyberneko.pull.event.ProcessingInstructionEvent;
023: import org.cyberneko.pull.event.TextDeclEvent;
024:
025: import org.apache.xerces.xni.Augmentations;
026: import org.apache.xerces.xni.NamespaceContext;
027: import org.apache.xerces.xni.XMLDocumentHandler;
028: import org.apache.xerces.xni.XMLLocator;
029: import org.apache.xerces.xni.XMLResourceIdentifier;
030: import org.apache.xerces.xni.XNIException;
031: import org.apache.xerces.xni.parser.XMLDocumentSource;
032:
033: /**
034: * This class converts pull parser event objects into XNI document handler
035: * callbacks. The user of this class is responsible for queueing of the
036: * event objects and should call <code>dispatchEvent</code> for each event
037: * to be delivered via the XNI document handler callbacks.
038: *
039: * @see EventCollector
040: *
041: * @author Andy Clark
042: *
043: * @version $Id$
044: */
045: public class EventDispatcher implements XMLDocumentSource {
046:
047: //
048: // Data
049: //
050:
051: /** The document handler. */
052: protected XMLDocumentHandler fDocumentHandler;
053:
054: // temp vars
055:
056: /** A resource identifier proxy. */
057: private final ResourceIdentifierProxy fResourceIdentifierProxy = new ResourceIdentifierProxy();
058:
059: //
060: // XMLDocumentSource methods
061: //
062:
063: /** Sets the document handler. */
064: public void setDocumentHandler(XMLDocumentHandler handler) {
065: fDocumentHandler = handler;
066: } // setDocumentHandler(XMLDocumentHandler)
067:
068: // @since Xerces 2.1.0
069:
070: /** Returns the document handler. */
071: public XMLDocumentHandler getDocumentHandler() {
072: return fDocumentHandler;
073: } // getDocumentHandler():XMLDocumentHandler
074:
075: //
076: // Public methods
077: //
078:
079: /**
080: * Dispatches a pull parser event object by calling the appropriate
081: *
082: * @param event The pull parser event to deliver.
083: *
084: * @throws XNIException Thrown by the handler to signal an error.
085: */
086: public void dispatchEvent(XMLEvent event) throws XNIException {
087:
088: // is there anything to do?
089: if (fDocumentHandler == null) {
090: return;
091: }
092:
093: // dispatch event
094: switch (event.type) {
095:
096: // start/empty/endElement
097: case XMLEvent.ELEMENT: {
098: ElementEvent elementEvent = (ElementEvent) event;
099: if (elementEvent.start) {
100: if (elementEvent.empty) {
101: fDocumentHandler.emptyElement(elementEvent.element,
102: elementEvent.attributes, elementEvent.augs);
103: } else {
104: fDocumentHandler.startElement(elementEvent.element,
105: elementEvent.attributes, elementEvent.augs);
106: }
107: } else if (!elementEvent.empty) {
108: fDocumentHandler.endElement(elementEvent.element,
109: elementEvent.augs);
110: }
111: break;
112: }
113:
114: // characters, ignorableWhitespace
115: case XMLEvent.CHARACTERS: {
116: CharactersEvent charactersEvent = (CharactersEvent) event;
117: if (charactersEvent.ignorable) {
118: fDocumentHandler.ignorableWhitespace(
119: charactersEvent.text, charactersEvent.augs);
120: } else {
121: fDocumentHandler.characters(charactersEvent.text,
122: charactersEvent.augs);
123: }
124: break;
125: }
126:
127: // start/endPrefixMapping
128: case XMLEvent.PREFIX_MAPPING: {
129: PrefixMappingEvent prefixMappingEvent = (PrefixMappingEvent) event;
130: if (prefixMappingEvent.start) {
131: Class cls = fDocumentHandler.getClass();
132: Class[] types = { String.class, String.class,
133: Augmentations.class };
134: try {
135: Method method = cls.getMethod("startPrefixMapping",
136: types);
137: Object[] args = { prefixMappingEvent.prefix,
138: prefixMappingEvent.uri,
139: prefixMappingEvent.augs };
140: method.invoke(fDocumentHandler, args);
141: } catch (NoSuchMethodException e) {
142: // ignore
143: } catch (IllegalAccessException e) {
144: // ignore
145: } catch (InvocationTargetException e) {
146: // ignore
147: }
148: } else {
149: Class cls = fDocumentHandler.getClass();
150: Class[] types = { String.class, String.class,
151: Augmentations.class };
152: try {
153: Method method = cls.getMethod("endPrefixMapping",
154: types);
155: Object[] args = { prefixMappingEvent.prefix,
156: prefixMappingEvent.augs };
157: method.invoke(fDocumentHandler, args);
158: } catch (NoSuchMethodException e) {
159: // ignore
160: } catch (IllegalAccessException e) {
161: // ignore
162: } catch (InvocationTargetException e) {
163: // ignore
164: }
165: }
166: break;
167: }
168:
169: // start/endCDATA
170: case XMLEvent.CDATA: {
171: CDATAEvent cdataEvent = (CDATAEvent) event;
172: if (cdataEvent.start) {
173: fDocumentHandler.startCDATA(cdataEvent.augs);
174: } else {
175: fDocumentHandler.endCDATA(cdataEvent.augs);
176: }
177: break;
178: }
179:
180: // start/endGeneralEntity
181: case XMLEvent.GENERAL_ENTITY: {
182: GeneralEntityEvent generalEntityEvent = (GeneralEntityEvent) event;
183: if (generalEntityEvent.start) {
184: fResourceIdentifierProxy
185: .setGeneralEntityEvent(generalEntityEvent);
186: fDocumentHandler.startGeneralEntity(
187: generalEntityEvent.name,
188: fResourceIdentifierProxy,
189: generalEntityEvent.encoding,
190: generalEntityEvent.augs);
191: } else {
192: fDocumentHandler.endGeneralEntity(
193: generalEntityEvent.name,
194: generalEntityEvent.augs);
195: }
196: break;
197: }
198:
199: // comment
200: case XMLEvent.COMMENT: {
201: CommentEvent commentEvent = (CommentEvent) event;
202: fDocumentHandler.comment(commentEvent.text,
203: commentEvent.augs);
204: break;
205: }
206:
207: // processingInstruction
208: case XMLEvent.PROCESSING_INSTRUCTION: {
209: ProcessingInstructionEvent processingInstructionEvent = (ProcessingInstructionEvent) event;
210: fDocumentHandler.processingInstruction(
211: processingInstructionEvent.target,
212: processingInstructionEvent.data,
213: processingInstructionEvent.augs);
214: break;
215: }
216:
217: // xmlDecl, textDecl
218: case XMLEvent.TEXT_DECL: {
219: TextDeclEvent textDeclEvent = (TextDeclEvent) event;
220: if (textDeclEvent.xmldecl) {
221: fDocumentHandler.xmlDecl(textDeclEvent.version,
222: textDeclEvent.encoding,
223: textDeclEvent.standalone, textDeclEvent.augs);
224: } else {
225: fDocumentHandler.textDecl(textDeclEvent.version,
226: textDeclEvent.encoding, textDeclEvent.augs);
227: }
228: break;
229: }
230:
231: // doctypeDecl
232: case XMLEvent.DOCTYPE_DECL: {
233: DoctypeDeclEvent doctypeDeclEvent = (DoctypeDeclEvent) event;
234: fDocumentHandler.doctypeDecl(doctypeDeclEvent.root,
235: doctypeDeclEvent.pubid, doctypeDeclEvent.sysid,
236: doctypeDeclEvent.augs);
237: break;
238: }
239:
240: // start/endDocument
241: case XMLEvent.DOCUMENT: {
242: DocumentEvent documentEvent = (DocumentEvent) event;
243: if (documentEvent.start) {
244: XMLLocator locator = documentEvent.locator;
245: String encoding = documentEvent.encoding;
246: NamespaceContext nscontext = null;
247: Augmentations augs = documentEvent.augs;
248: try {
249: // NOTE: Hack to allow the default filter to work with
250: // old and new versions of the XNI document handler
251: // interface. -Ac
252: Class cls = fDocumentHandler.getClass();
253: Class[] types = { XMLLocator.class, String.class,
254: NamespaceContext.class, Augmentations.class };
255: Method method = cls.getMethod("startDocument",
256: types);
257: Object[] params = { locator, encoding, nscontext,
258: augs };
259: method.invoke(fDocumentHandler, params);
260: } catch (XNIException e) {
261: throw e;
262: } catch (Exception e) {
263: try {
264: // NOTE: Hack to allow the default filter to work with
265: // old and new versions of the XNI document handler
266: // interface. -Ac
267: Class cls = fDocumentHandler.getClass();
268: Class[] types = { XMLLocator.class,
269: String.class, Augmentations.class };
270: Method method = cls.getMethod("startDocument",
271: types);
272: Object[] params = { locator, encoding, augs };
273: method.invoke(fDocumentHandler, params);
274: } catch (XNIException ex) {
275: throw ex;
276: } catch (Exception ex) {
277: // NOTE: Should never reach here!
278: throw new XNIException(ex);
279: }
280: }
281: } else {
282: fDocumentHandler.endDocument(documentEvent.augs);
283: }
284: break;
285: }
286:
287: // error
288: default: {
289: throw new XNIException("unknown event type (" + event.type
290: + ')');
291: }
292: }
293:
294: } // dispatchEvent(XMLEvent)
295:
296: //
297: // Classes
298: //
299:
300: /**
301: * A proxy object for resource identifier passed to the start general
302: * entity method in the XNI document handler.
303: *
304: * @author Andy Clark
305: */
306: public static class ResourceIdentifierProxy implements
307: XMLResourceIdentifier {
308:
309: //
310: // Data
311: //
312:
313: /** The general entity event to be proxied. */
314: protected GeneralEntityEvent fEvent;
315:
316: //
317: // Public methods
318: //
319:
320: /** Sets the general entity event. */
321: public void setGeneralEntityEvent(GeneralEntityEvent event) {
322: fEvent = event;
323: } // setGeneralEntityEvent(GeneralEntityEvent)
324:
325: //
326: // XMLResourceIdentifier methods
327: //
328:
329: /** Returns the public identifier. */
330: public String getPublicId() {
331: return fEvent.publicId;
332: } // getPublicId():String
333:
334: /** Returns the base system identifier. */
335: public String getBaseSystemId() {
336: return fEvent.baseSystemId;
337: } // getBaseSystemId():String
338:
339: /** Returns the literal system identifier. */
340: public String getLiteralSystemId() {
341: return fEvent.literalSystemId;
342: } // getLiteralSystemId():String
343:
344: /** Returns the expanded system identifier. */
345: public String getExpandedSystemId() {
346: return fEvent.expandedSystemId;
347: } // getExpandedSystemId():String
348:
349: // @since Xerces-J 2.3.0
350:
351: /** Sets the public identifier. */
352: public void setPublicId(String publicId) {
353: fEvent.publicId = publicId;
354: } // setPublicId(String)
355:
356: /** Sets the base system identifier. */
357: public void setBaseSystemId(String baseSystemId) {
358: fEvent.baseSystemId = baseSystemId;
359: } // setBaseSystemId(String)
360:
361: /** Sets the literal system identifier. */
362: public void setLiteralSystemId(String literalSystemId) {
363: fEvent.literalSystemId = literalSystemId;
364: } // setLiteralSystemId(String)
365:
366: /** Sets the expanded system identifier. */
367: public void setExpandedSystemId(String expandedSystemId) {
368: fEvent.expandedSystemId = expandedSystemId;
369: } // setExpandedSystemId(String)
370:
371: // @since Xerces-J 2.4.0
372:
373: /** Returns the namespace. */
374: public String getNamespace() {
375: return fEvent.namespace;
376: } // getNamespace():String
377:
378: /** Sets the namespace. */
379: public void setNamespace(String namespace) {
380: fEvent.namespace = namespace;
381: } // getNamespace(String)
382:
383: } // class ResourceIdentifierProxy
384:
385: } // class EventDispatcher
|