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.ArrayList; 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.ArrayList<String>) 238 */ 239 public void setCdataSectionElements(ArrayList<String> 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 }