1 /*
2 * reserved comment block
3 * DO NOT REMOVE OR ALTER!
4 */
5 /*
6 * Copyright 2001-2004 The Apache Software Foundation.
7 *
8 * Licensed under the Apache License, Version 2.0 (the "License");
9 * you may not use this file except in compliance with the License.
10 * You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing, software
15 * distributed under the License is distributed on an "AS IS" BASIS,
16 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17 * See the License for the specific language governing permissions and
18 * limitations under the License.
19 */
20 /*
21 * $Id: ToSAXHandler.java,v 1.2.4.1 2005/09/22 11:03:15 pvedula Exp $
22 */
23 package com.sun.org.apache.xml.internal.serializer;
24
25 import java.util.Vector;
26
27 import org.xml.sax.Attributes;
28 import org.xml.sax.ContentHandler;
29 import org.xml.sax.ErrorHandler;
30 import org.xml.sax.SAXException;
31 import org.xml.sax.SAXParseException;
32 import org.xml.sax.ext.LexicalHandler;
33
34 /**
35 * This class is used to provide a base behavior to be inherited
36 * by other To...SAXHandler serializers.
37 *
38 * This class is not a public API.
39 *
40 * @xsl.usage internal
41 */
42 public abstract class ToSAXHandler extends SerializerBase
43 {
44 public ToSAXHandler()
45 {
46 }
47
48 public ToSAXHandler(
49 ContentHandler hdlr,
50 LexicalHandler lex,
51 String encoding)
52 {
53 setContentHandler(hdlr);
54 setLexHandler(lex);
55 setEncoding(encoding);
56 }
57 public ToSAXHandler(ContentHandler handler, String encoding)
58 {
59 setContentHandler(handler);
60 setEncoding(encoding);
61 }
62
63 /**
64 * Underlying SAX handler. Taken from XSLTC
65 */
66 protected ContentHandler m_saxHandler;
67
68 /**
69 * Underlying LexicalHandler. Taken from XSLTC
70 */
71 protected LexicalHandler m_lexHandler;
72
73 /**
74 * A startPrefixMapping() call on a ToSAXHandler will pass that call
75 * on to the wrapped ContentHandler, but should we also mirror these calls
76 * with matching attributes, if so this field is true.
77 * For example if this field is true then a call such as
78 * startPrefixMapping("prefix1","uri1") will also cause the additional
79 * internally generated attribute xmlns:prefix1="uri1" to be effectively added
80 * to the attributes passed to the wrapped ContentHandler.
81 */
82 private boolean m_shouldGenerateNSAttribute = true;
83
84 /** If this is true, then the content handler wrapped by this
85 * serializer implements the TransformState interface which
86 * will give the content handler access to the state of
87 * the transform. */
88 protected TransformStateSetter m_state = null;
89
90 /**
91 * Pass callback to the SAX Handler
92 */
93 protected void startDocumentInternal() throws SAXException
94 {
95 if (m_needToCallStartDocument)
96 {
97 super.startDocumentInternal();
98
99 m_saxHandler.startDocument();
100 m_needToCallStartDocument = false;
101 }
102 }
103 /**
104 * Do nothing.
105 * @see org.xml.sax.ext.LexicalHandler#startDTD(String, String, String)
106 */
107 public void startDTD(String arg0, String arg1, String arg2)
108 throws SAXException
109 {
110 // do nothing for now
111 }
112
113 /**
114 * Receive notification of character data.
115 *
116 * @param characters The string of characters to process.
117 *
118 * @throws org.xml.sax.SAXException
119 *
120 * @see ExtendedContentHandler#characters(String)
121 */
122 public void characters(String characters) throws SAXException
123 {
124 final int len = characters.length();
125 if (len > m_charsBuff.length)
126 {
127 m_charsBuff = new char[len*2 + 1];
128 }
129 characters.getChars(0,len, m_charsBuff, 0);
130 characters(m_charsBuff, 0, len);
131 }
132
133 /**
134 * Receive notification of a comment.
135 *
136 * @see ExtendedLexicalHandler#comment(String)
137 */
138 public void comment(String comment) throws SAXException
139 {
140 flushPending();
141
142 // Ignore if a lexical handler has not been set
143 if (m_lexHandler != null)
144 {
145 final int len = comment.length();
146 if (len > m_charsBuff.length)
147 {
148 m_charsBuff = new char[len*2 + 1];
149 }
150 comment.getChars(0,len, m_charsBuff, 0);
151 m_lexHandler.comment(m_charsBuff, 0, len);
152 // time to fire off comment event
153 if (m_tracer != null)
154 super.fireCommentEvent(m_charsBuff, 0, len);
155 }
156
157 }
158
159 /**
160 * Do nothing as this is an abstract class. All subclasses will need to
161 * define their behavior if it is different.
162 * @see org.xml.sax.ContentHandler#processingInstruction(String, String)
163 */
164 public void processingInstruction(String target, String data)
165 throws SAXException
166 {
167 // Redefined in SAXXMLOutput
168 }
169
170 protected void closeStartTag() throws SAXException
171 {
172 }
173
174 protected void closeCDATA() throws SAXException
175 {
176 // Redefined in SAXXMLOutput
177 }
178
179 /**
180 * Receive notification of the beginning of an element, although this is a
181 * SAX method additional namespace or attribute information can occur before
182 * or after this call, that is associated with this element.
183 *
184 * @throws org.xml.sax.SAXException Any SAX exception, possibly
185 * wrapping another exception.
186 * @see org.xml.sax.ContentHandler#startElement
187 * @see org.xml.sax.ContentHandler#endElement
188 * @see org.xml.sax.AttributeList
189 *
190 * @throws org.xml.sax.SAXException
191 *
192 * @see org.xml.sax.ContentHandler#startElement(String,String,String,Attributes)
193 */
194 public void startElement(
195 String arg0,
196 String arg1,
197 String arg2,
198 Attributes arg3)
199 throws SAXException
200 {
201 if (m_state != null) {
202 m_state.resetState(getTransformer());
203 }
204
205 // fire off the start element event
206 if (m_tracer != null)
207 super.fireStartElem(arg2);
208 }
209
210 /**
211 * Sets the LexicalHandler.
212 * @param _lexHandler The LexicalHandler to set
213 */
214 public void setLexHandler(LexicalHandler _lexHandler)
215 {
216 this.m_lexHandler = _lexHandler;
217 }
218
219 /**
220 * Sets the SAX ContentHandler.
221 * @param _saxHandler The ContentHandler to set
222 */
223 public void setContentHandler(ContentHandler _saxHandler)
224 {
225 this.m_saxHandler = _saxHandler;
226 if (m_lexHandler == null && _saxHandler instanceof LexicalHandler)
227 {
228 // we are not overwriting an existing LexicalHandler, and _saxHandler
229 // is also implements LexicalHandler, so lets use it
230 m_lexHandler = (LexicalHandler) _saxHandler;
231 }
232 }
233
234 /**
235 * Does nothing. The setting of CDATA section elements has an impact on
236 * stream serializers.
237 * @see SerializationHandler#setCdataSectionElements(java.util.Vector)
238 */
239 public void setCdataSectionElements(Vector URI_and_localNames)
240 {
241 // do nothing
242 }
243
244 /** Set whether or not namespace declarations (e.g.
245 * xmlns:foo) should appear as attributes of
246 * elements
247 * @param doOutputNSAttr whether or not namespace declarations
248 * should appear as attributes
249 */
250 public void setShouldOutputNSAttr(boolean doOutputNSAttr)
251 {
252 m_shouldGenerateNSAttribute = doOutputNSAttr;
253 }
254
255 /**
256 * Returns true if namespace declarations from calls such as
257 * startPrefixMapping("prefix1","uri1") should
258 * also be mirrored with self generated additional attributes of elements
259 * that declare the namespace, for example the attribute xmlns:prefix1="uri1"
260 */
261 boolean getShouldOutputNSAttr()
262 {
263 return m_shouldGenerateNSAttribute;
264 }
265
266 /**
267 * This method flushes any pending events, which can be startDocument()
268 * closing the opening tag of an element, or closing an open CDATA section.
269 */
270 public void flushPending() throws SAXException
271 {
272
273 if (m_needToCallStartDocument)
274 {
275 startDocumentInternal();
276 m_needToCallStartDocument = false;
277 }
278
279 if (m_elemContext.m_startTagOpen)
280 {
281 closeStartTag();
282 m_elemContext.m_startTagOpen = false;
283 }
284
285 if (m_cdataTagOpen)
286 {
287 closeCDATA();
288 m_cdataTagOpen = false;
289 }
290
291 }
292
293 /**
294 * Pass in a reference to a TransformState object, which
295 * can be used during SAX ContentHandler events to obtain
296 * information about he state of the transformation. This
297 * method will be called before each startDocument event.
298 *
299 * @param ts A reference to a TransformState object
300 */
301 public void setTransformState(TransformStateSetter ts) {
302 this.m_state = ts;
303 }
304
305 /**
306 * Receives notification that an element starts, but attributes are not
307 * fully known yet.
308 *
309 * @param uri the URI of the namespace of the element (optional)
310 * @param localName the element name, but without prefix (optional)
311 * @param qName the element name, with prefix, if any (required)
312 *
313 * @see ExtendedContentHandler#startElement(String, String, String)
314 */
315 public void startElement(String uri, String localName, String qName)
316 throws SAXException {
317
318 if (m_state != null) {
319 m_state.resetState(getTransformer());
320 }
321
322 // fire off the start element event
323 if (m_tracer != null)
324 super.fireStartElem(qName);
325 }
326
327 /**
328 * An element starts, but attributes are not fully known yet.
329 *
330 * @param qName the element name, with prefix (if any).
331
332 * @see ExtendedContentHandler#startElement(String)
333 */
334 public void startElement(String qName) throws SAXException {
335 if (m_state != null) {
336 m_state.resetState(getTransformer());
337 }
338 // fire off the start element event
339 if (m_tracer != null)
340 super.fireStartElem(qName);
341 }
342
343 /**
344 * This method gets the node's value as a String and uses that String as if
345 * it were an input character notification.
346 * @param node the Node to serialize
347 * @throws org.xml.sax.SAXException
348 */
349 public void characters(org.w3c.dom.Node node)
350 throws org.xml.sax.SAXException
351 {
352 // remember the current node
353 if (m_state != null)
354 {
355 m_state.setCurrentNode(node);
356 }
357
358 // Get the node's value as a String and use that String as if
359 // it were an input character notification.
360 String data = node.getNodeValue();
361 if (data != null) {
362 this.characters(data);
363 }
364 }
365
366 /**
367 * @see org.xml.sax.ErrorHandler#fatalError(SAXParseException)
368 */
369 public void fatalError(SAXParseException exc) throws SAXException {
370 super.fatalError(exc);
371
372 m_needToCallStartDocument = false;
373
374 if (m_saxHandler instanceof ErrorHandler) {
375 ((ErrorHandler)m_saxHandler).fatalError(exc);
376 }
377 }
378
379 /**
380 * @see org.xml.sax.ErrorHandler#error(SAXParseException)
381 */
382 public void error(SAXParseException exc) throws SAXException {
383 super.error(exc);
384
385 if (m_saxHandler instanceof ErrorHandler)
386 ((ErrorHandler)m_saxHandler).error(exc);
387
388 }
389
390 /**
391 * @see org.xml.sax.ErrorHandler#warning(SAXParseException)
392 */
393 public void warning(SAXParseException exc) throws SAXException {
394 super.warning(exc);
395
396 if (m_saxHandler instanceof ErrorHandler)
397 ((ErrorHandler)m_saxHandler).warning(exc);
398 }
399
400
401 /**
402 * Try's to reset the super class and reset this class for
403 * re-use, so that you don't need to create a new serializer
404 * (mostly for performance reasons).
405 *
406 * @return true if the class was successfuly reset.
407 * @see Serializer#reset()
408 */
409 public boolean reset()
410 {
411 boolean wasReset = false;
412 if (super.reset())
413 {
414 resetToSAXHandler();
415 wasReset = true;
416 }
417 return wasReset;
418 }
419
420 /**
421 * Reset all of the fields owned by ToSAXHandler class
422 *
423 */
424 private void resetToSAXHandler()
425 {
426 this.m_lexHandler = null;
427 this.m_saxHandler = null;
428 this.m_state = null;
429 this.m_shouldGenerateNSAttribute = false;
430 }
431
432 /**
433 * Add a unique attribute
434 */
435 public void addUniqueAttribute(String qName, String value, int flags)
436 throws SAXException
437 {
438 addAttribute(qName, value);
439 }
440 }