001: /*
002: * Copyright 2001-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: /*
017: * $Id: ToSAXHandler.java,v 1.16 2005/04/07 04:29:03 minchau Exp $
018: */
019: package org.apache.xml.serializer;
020:
021: import java.util.Vector;
022:
023: import org.xml.sax.Attributes;
024: import org.xml.sax.ContentHandler;
025: import org.xml.sax.ErrorHandler;
026: import org.xml.sax.SAXException;
027: import org.xml.sax.SAXParseException;
028: import org.xml.sax.ext.LexicalHandler;
029:
030: /**
031: * This class is used to provide a base behavior to be inherited
032: * by other To...SAXHandler serializers.
033: *
034: * This class is not a public API.
035: *
036: * @xsl.usage internal
037: */
038: public abstract class ToSAXHandler extends SerializerBase {
039: public ToSAXHandler() {
040: }
041:
042: public ToSAXHandler(ContentHandler hdlr, LexicalHandler lex,
043: String encoding) {
044: setContentHandler(hdlr);
045: setLexHandler(lex);
046: setEncoding(encoding);
047: }
048:
049: public ToSAXHandler(ContentHandler handler, String encoding) {
050: setContentHandler(handler);
051: setEncoding(encoding);
052: }
053:
054: /**
055: * Underlying SAX handler. Taken from XSLTC
056: */
057: protected ContentHandler m_saxHandler;
058:
059: /**
060: * Underlying LexicalHandler. Taken from XSLTC
061: */
062: protected LexicalHandler m_lexHandler;
063:
064: /**
065: * A startPrefixMapping() call on a ToSAXHandler will pass that call
066: * on to the wrapped ContentHandler, but should we also mirror these calls
067: * with matching attributes, if so this field is true.
068: * For example if this field is true then a call such as
069: * startPrefixMapping("prefix1","uri1") will also cause the additional
070: * internally generated attribute xmlns:prefix1="uri1" to be effectively added
071: * to the attributes passed to the wrapped ContentHandler.
072: */
073: private boolean m_shouldGenerateNSAttribute = true;
074:
075: /** If this is true, then the content handler wrapped by this
076: * serializer implements the TransformState interface which
077: * will give the content handler access to the state of
078: * the transform. */
079: protected TransformStateSetter m_state = null;
080:
081: /**
082: * Pass callback to the SAX Handler
083: */
084: protected void startDocumentInternal() throws SAXException {
085: if (m_needToCallStartDocument) {
086: super .startDocumentInternal();
087:
088: m_saxHandler.startDocument();
089: m_needToCallStartDocument = false;
090: }
091: }
092:
093: /**
094: * Do nothing.
095: * @see org.xml.sax.ext.LexicalHandler#startDTD(String, String, String)
096: */
097: public void startDTD(String arg0, String arg1, String arg2)
098: throws SAXException {
099: // do nothing for now
100: }
101:
102: /**
103: * Receive notification of character data.
104: *
105: * @param characters The string of characters to process.
106: *
107: * @throws org.xml.sax.SAXException
108: *
109: * @see ExtendedContentHandler#characters(String)
110: */
111: public void characters(String characters) throws SAXException {
112: final int len = characters.length();
113: if (len > m_charsBuff.length) {
114: m_charsBuff = new char[len * 2 + 1];
115: }
116: characters.getChars(0, len, m_charsBuff, 0);
117: characters(m_charsBuff, 0, len);
118: }
119:
120: /**
121: * Receive notification of a comment.
122: *
123: * @see ExtendedLexicalHandler#comment(String)
124: */
125: public void comment(String comment) throws SAXException {
126: flushPending();
127:
128: // Ignore if a lexical handler has not been set
129: if (m_lexHandler != null) {
130: final int len = comment.length();
131: if (len > m_charsBuff.length) {
132: m_charsBuff = new char[len * 2 + 1];
133: }
134: comment.getChars(0, len, m_charsBuff, 0);
135: m_lexHandler.comment(m_charsBuff, 0, len);
136: // time to fire off comment event
137: if (m_tracer != null)
138: super .fireCommentEvent(m_charsBuff, 0, len);
139: }
140:
141: }
142:
143: /**
144: * Do nothing as this is an abstract class. All subclasses will need to
145: * define their behavior if it is different.
146: * @see org.xml.sax.ContentHandler#processingInstruction(String, String)
147: */
148: public void processingInstruction(String target, String data)
149: throws SAXException {
150: // Redefined in SAXXMLOutput
151: }
152:
153: protected void closeStartTag() throws SAXException {
154: }
155:
156: protected void closeCDATA() throws SAXException {
157: // Redefined in SAXXMLOutput
158: }
159:
160: /**
161: * Receive notification of the beginning of an element, although this is a
162: * SAX method additional namespace or attribute information can occur before
163: * or after this call, that is associated with this element.
164: *
165: * @throws org.xml.sax.SAXException Any SAX exception, possibly
166: * wrapping another exception.
167: * @see org.xml.sax.ContentHandler#startElement
168: * @see org.xml.sax.ContentHandler#endElement
169: * @see org.xml.sax.AttributeList
170: *
171: * @throws org.xml.sax.SAXException
172: *
173: * @see org.xml.sax.ContentHandler#startElement(String,String,String,Attributes)
174: */
175: public void startElement(String arg0, String arg1, String arg2,
176: Attributes arg3) throws SAXException {
177: if (m_state != null) {
178: m_state.resetState(getTransformer());
179: }
180:
181: // fire off the start element event
182: if (m_tracer != null)
183: super .fireStartElem(arg2);
184: }
185:
186: /**
187: * Sets the LexicalHandler.
188: * @param _lexHandler The LexicalHandler to set
189: */
190: public void setLexHandler(LexicalHandler _lexHandler) {
191: this .m_lexHandler = _lexHandler;
192: }
193:
194: /**
195: * Sets the SAX ContentHandler.
196: * @param _saxHandler The ContentHandler to set
197: */
198: public void setContentHandler(ContentHandler _saxHandler) {
199: this .m_saxHandler = _saxHandler;
200: if (m_lexHandler == null
201: && _saxHandler instanceof LexicalHandler) {
202: // we are not overwriting an existing LexicalHandler, and _saxHandler
203: // is also implements LexicalHandler, so lets use it
204: m_lexHandler = (LexicalHandler) _saxHandler;
205: }
206: }
207:
208: /**
209: * Does nothing. The setting of CDATA section elements has an impact on
210: * stream serializers.
211: * @see SerializationHandler#setCdataSectionElements(java.util.Vector)
212: */
213: public void setCdataSectionElements(Vector URI_and_localNames) {
214: // do nothing
215: }
216:
217: /** Set whether or not namespace declarations (e.g.
218: * xmlns:foo) should appear as attributes of
219: * elements
220: * @param doOutputNSAttr whether or not namespace declarations
221: * should appear as attributes
222: */
223: public void setShouldOutputNSAttr(boolean doOutputNSAttr) {
224: m_shouldGenerateNSAttribute = doOutputNSAttr;
225: }
226:
227: /**
228: * Returns true if namespace declarations from calls such as
229: * startPrefixMapping("prefix1","uri1") should
230: * also be mirrored with self generated additional attributes of elements
231: * that declare the namespace, for example the attribute xmlns:prefix1="uri1"
232: */
233: boolean getShouldOutputNSAttr() {
234: return m_shouldGenerateNSAttribute;
235: }
236:
237: /**
238: * This method flushes any pending events, which can be startDocument()
239: * closing the opening tag of an element, or closing an open CDATA section.
240: */
241: public void flushPending() throws SAXException {
242:
243: if (m_needToCallStartDocument) {
244: startDocumentInternal();
245: m_needToCallStartDocument = false;
246: }
247:
248: if (m_elemContext.m_startTagOpen) {
249: closeStartTag();
250: m_elemContext.m_startTagOpen = false;
251: }
252:
253: if (m_cdataTagOpen) {
254: closeCDATA();
255: m_cdataTagOpen = false;
256: }
257:
258: }
259:
260: /**
261: * Pass in a reference to a TransformState object, which
262: * can be used during SAX ContentHandler events to obtain
263: * information about he state of the transformation. This
264: * method will be called before each startDocument event.
265: *
266: * @param ts A reference to a TransformState object
267: */
268: public void setTransformState(TransformStateSetter ts) {
269: this .m_state = ts;
270: }
271:
272: /**
273: * Receives notification that an element starts, but attributes are not
274: * fully known yet.
275: *
276: * @param uri the URI of the namespace of the element (optional)
277: * @param localName the element name, but without prefix (optional)
278: * @param qName the element name, with prefix, if any (required)
279: *
280: * @see ExtendedContentHandler#startElement(String, String, String)
281: */
282: public void startElement(String uri, String localName, String qName)
283: throws SAXException {
284:
285: if (m_state != null) {
286: m_state.resetState(getTransformer());
287: }
288:
289: // fire off the start element event
290: if (m_tracer != null)
291: super .fireStartElem(qName);
292: }
293:
294: /**
295: * An element starts, but attributes are not fully known yet.
296: *
297: * @param qName the element name, with prefix (if any).
298:
299: * @see ExtendedContentHandler#startElement(String)
300: */
301: public void startElement(String qName) throws SAXException {
302: if (m_state != null) {
303: m_state.resetState(getTransformer());
304: }
305: // fire off the start element event
306: if (m_tracer != null)
307: super .fireStartElem(qName);
308: }
309:
310: /**
311: * This method gets the node's value as a String and uses that String as if
312: * it were an input character notification.
313: * @param node the Node to serialize
314: * @throws org.xml.sax.SAXException
315: */
316: public void characters(org.w3c.dom.Node node)
317: throws org.xml.sax.SAXException {
318: // remember the current node
319: if (m_state != null) {
320: m_state.setCurrentNode(node);
321: }
322:
323: // Get the node's value as a String and use that String as if
324: // it were an input character notification.
325: String data = node.getNodeValue();
326: if (data != null) {
327: this .characters(data);
328: }
329: }
330:
331: /**
332: * @see org.xml.sax.ErrorHandler#fatalError(SAXParseException)
333: */
334: public void fatalError(SAXParseException exc) throws SAXException {
335: super .fatalError(exc);
336:
337: m_needToCallStartDocument = false;
338:
339: if (m_saxHandler instanceof ErrorHandler) {
340: ((ErrorHandler) m_saxHandler).fatalError(exc);
341: }
342: }
343:
344: /**
345: * @see org.xml.sax.ErrorHandler#error(SAXParseException)
346: */
347: public void error(SAXParseException exc) throws SAXException {
348: super .error(exc);
349:
350: if (m_saxHandler instanceof ErrorHandler)
351: ((ErrorHandler) m_saxHandler).error(exc);
352:
353: }
354:
355: /**
356: * @see org.xml.sax.ErrorHandler#warning(SAXParseException)
357: */
358: public void warning(SAXParseException exc) throws SAXException {
359: super .warning(exc);
360:
361: if (m_saxHandler instanceof ErrorHandler)
362: ((ErrorHandler) m_saxHandler).warning(exc);
363: }
364:
365: /**
366: * Try's to reset the super class and reset this class for
367: * re-use, so that you don't need to create a new serializer
368: * (mostly for performance reasons).
369: *
370: * @return true if the class was successfuly reset.
371: * @see Serializer#reset()
372: */
373: public boolean reset() {
374: boolean wasReset = false;
375: if (super .reset()) {
376: resetToSAXHandler();
377: wasReset = true;
378: }
379: return wasReset;
380: }
381:
382: /**
383: * Reset all of the fields owned by ToSAXHandler class
384: *
385: */
386: private void resetToSAXHandler() {
387: this .m_lexHandler = null;
388: this .m_saxHandler = null;
389: this .m_state = null;
390: this .m_shouldGenerateNSAttribute = false;
391: }
392:
393: /**
394: * Add a unique attribute
395: */
396: public void addUniqueAttribute(String qName, String value, int flags)
397: throws SAXException {
398: addAttribute(qName, value);
399: }
400: }
|