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: DOM2TO.java,v 1.5 2005/09/28 13:48:44 pvedula Exp $ 22 */ 23 24 package com.sun.org.apache.xalan.internal.xsltc.trax; 25 26 import java.io.IOException; 27 28 import org.w3c.dom.NamedNodeMap; 29 import org.w3c.dom.Node; 30 import org.w3c.dom.Document; 31 import com.sun.org.apache.xml.internal.serializer.SerializationHandler; 32 import org.xml.sax.ContentHandler; 33 import org.xml.sax.DTDHandler; 34 import org.xml.sax.EntityResolver; 35 import org.xml.sax.ErrorHandler; 36 import org.xml.sax.InputSource; 37 import org.xml.sax.ext.Locator2; 38 import org.xml.sax.SAXException; 39 import org.xml.sax.SAXNotRecognizedException; 40 import org.xml.sax.SAXNotSupportedException; 41 import org.xml.sax.XMLReader; 42 import com.sun.org.apache.xml.internal.serializer.NamespaceMappings; 43 44 /** 45 * @author Santiago Pericas-Geertsen 46 * @author Sunitha Reddy 47 */ 48 public class DOM2TO implements XMLReader, Locator2 { 49 50 private final static String EMPTYSTRING = ""; 51 private static final String XMLNS_PREFIX = "xmlns"; 52 53 /** 54 * A reference to the DOM to be traversed. 55 */ 56 private Node _dom; 57 58 /** 59 * A reference to the output handler receiving the events. 60 */ 61 private SerializationHandler _handler; 62 63 64 private String xmlVersion = null; 65 66 private String xmlEncoding = null; 67 68 69 public DOM2TO(Node root, SerializationHandler handler) { 70 _dom = root; 71 _handler = handler; 72 } 73 74 public ContentHandler getContentHandler() { 75 return null; 76 } 77 78 public void setContentHandler(ContentHandler handler) { 79 // Empty 80 } 81 82 public void parse(InputSource unused) throws IOException, SAXException { 83 parse(_dom); 84 } 85 86 public void parse() throws IOException, SAXException { 87 88 if (_dom != null) { 89 boolean isIncomplete = 90 (_dom.getNodeType() != org.w3c.dom.Node.DOCUMENT_NODE); 91 92 if (isIncomplete) { 93 _handler.startDocument(); 94 parse(_dom); 95 _handler.endDocument(); 96 } 97 else { 98 parse(_dom); 99 } 100 } 101 } 102 103 /** 104 * Traverse the DOM and generate TO events for a handler. Notice that 105 * we need to handle implicit namespace declarations too. 106 */ 107 private void parse(Node node) 108 throws IOException, SAXException 109 { 110 if (node == null) return; 111 112 switch (node.getNodeType()) { 113 case Node.ATTRIBUTE_NODE: // handled by ELEMENT_NODE 114 case Node.DOCUMENT_TYPE_NODE : 115 case Node.ENTITY_NODE : 116 case Node.ENTITY_REFERENCE_NODE: 117 case Node.NOTATION_NODE : 118 // These node types are ignored!!! 119 break; 120 case Node.CDATA_SECTION_NODE: 121 _handler.startCDATA(); 122 _handler.characters(node.getNodeValue()); 123 _handler.endCDATA(); 124 break; 125 126 case Node.COMMENT_NODE: // should be handled!!! 127 _handler.comment(node.getNodeValue()); 128 break; 129 130 case Node.DOCUMENT_NODE: 131 setDocumentInfo((Document)node); 132 _handler.setDocumentLocator(this); 133 _handler.startDocument(); 134 Node next = node.getFirstChild(); 135 while (next != null) { 136 parse(next); 137 next = next.getNextSibling(); 138 } 139 _handler.endDocument(); 140 break; 141 142 case Node.DOCUMENT_FRAGMENT_NODE: 143 next = node.getFirstChild(); 144 while (next != null) { 145 parse(next); 146 next = next.getNextSibling(); 147 } 148 break; 149 150 case Node.ELEMENT_NODE: 151 // Generate SAX event to start element 152 final String qname = node.getNodeName(); 153 _handler.startElement(null, null, qname); 154 155 int colon; 156 String prefix; 157 final NamedNodeMap map = node.getAttributes(); 158 final int length = map.getLength(); 159 160 // Process all namespace attributes first 161 for (int i = 0; i < length; i++) { 162 final Node attr = map.item(i); 163 final String qnameAttr = attr.getNodeName(); 164 165 // Is this a namespace declaration? 166 if (qnameAttr.startsWith(XMLNS_PREFIX)) { 167 final String uriAttr = attr.getNodeValue(); 168 colon = qnameAttr.lastIndexOf(':'); 169 prefix = (colon > 0) ? qnameAttr.substring(colon + 1) 170 : EMPTYSTRING; 171 _handler.namespaceAfterStartElement(prefix, uriAttr); 172 } 173 } 174 175 // Process all non-namespace attributes next 176 NamespaceMappings nm = new NamespaceMappings(); 177 for (int i = 0; i < length; i++) { 178 final Node attr = map.item(i); 179 final String qnameAttr = attr.getNodeName(); 180 181 // Is this a regular attribute? 182 if (!qnameAttr.startsWith(XMLNS_PREFIX)) { 183 final String uriAttr = attr.getNamespaceURI(); 184 // Uri may be implicitly declared 185 if (uriAttr != null && !uriAttr.equals(EMPTYSTRING) ) { 186 colon = qnameAttr.lastIndexOf(':'); 187 188 // Fix for bug 26319 189 // For attributes not given an prefix explictly 190 // but having a namespace uri we need 191 // to explicitly generate the prefix 192 String newPrefix = nm.lookupPrefix(uriAttr); 193 if (newPrefix == null) 194 newPrefix = nm.generateNextPrefix(); 195 prefix = (colon > 0) ? qnameAttr.substring(0, colon) 196 : newPrefix; 197 _handler.namespaceAfterStartElement(prefix, uriAttr); 198 _handler.addAttribute((prefix + ":" + qnameAttr), 199 attr.getNodeValue()); 200 } else { 201 _handler.addAttribute(qnameAttr, attr.getNodeValue()); 202 } 203 } 204 } 205 206 // Now element namespace and children 207 final String uri = node.getNamespaceURI(); 208 final String localName = node.getLocalName(); 209 210 // Uri may be implicitly declared 211 if (uri != null) { 212 colon = qname.lastIndexOf(':'); 213 prefix = (colon > 0) ? qname.substring(0, colon) : EMPTYSTRING; 214 _handler.namespaceAfterStartElement(prefix, uri); 215 }else { 216 // Fix for bug 26319 217 // If an element foo is created using 218 // createElementNS(null,locName) 219 // then the element should be serialized 220 // <foo xmlns=" "/> 221 if (uri == null && localName != null) { 222 prefix = EMPTYSTRING; 223 _handler.namespaceAfterStartElement(prefix, EMPTYSTRING); 224 } 225 } 226 227 // Traverse all child nodes of the element (if any) 228 next = node.getFirstChild(); 229 while (next != null) { 230 parse(next); 231 next = next.getNextSibling(); 232 } 233 234 // Generate SAX event to close element 235 _handler.endElement(qname); 236 break; 237 238 case Node.PROCESSING_INSTRUCTION_NODE: 239 _handler.processingInstruction(node.getNodeName(), 240 node.getNodeValue()); 241 break; 242 243 case Node.TEXT_NODE: 244 _handler.characters(node.getNodeValue()); 245 break; 246 } 247 } 248 249 /** 250 * This class is only used internally so this method should never 251 * be called. 252 */ 253 public DTDHandler getDTDHandler() { 254 return null; 255 } 256 257 /** 258 * This class is only used internally so this method should never 259 * be called. 260 */ 261 public ErrorHandler getErrorHandler() { 262 return null; 263 } 264 265 /** 266 * This class is only used internally so this method should never 267 * be called. 268 */ 269 public boolean getFeature(String name) throws SAXNotRecognizedException, 270 SAXNotSupportedException 271 { 272 return false; 273 } 274 275 /** 276 * This class is only used internally so this method should never 277 * be called. 278 */ 279 public void setFeature(String name, boolean value) throws 280 SAXNotRecognizedException, SAXNotSupportedException 281 { 282 } 283 284 /** 285 * This class is only used internally so this method should never 286 * be called. 287 */ 288 public void parse(String sysId) throws IOException, SAXException { 289 throw new IOException("This method is not yet implemented."); 290 } 291 292 /** 293 * This class is only used internally so this method should never 294 * be called. 295 */ 296 public void setDTDHandler(DTDHandler handler) throws NullPointerException { 297 } 298 299 /** 300 * This class is only used internally so this method should never 301 * be called. 302 */ 303 public void setEntityResolver(EntityResolver resolver) throws 304 NullPointerException 305 { 306 } 307 308 /** 309 * This class is only used internally so this method should never 310 * be called. 311 */ 312 public EntityResolver getEntityResolver() { 313 return null; 314 } 315 316 /** 317 * This class is only used internally so this method should never 318 * be called. 319 */ 320 public void setErrorHandler(ErrorHandler handler) throws 321 NullPointerException 322 { 323 } 324 325 /** 326 * This class is only used internally so this method should never 327 * be called. 328 */ 329 public void setProperty(String name, Object value) throws 330 SAXNotRecognizedException, SAXNotSupportedException { 331 } 332 333 /** 334 * This class is only used internally so this method should never 335 * be called. 336 */ 337 public Object getProperty(String name) throws SAXNotRecognizedException, 338 SAXNotSupportedException 339 { 340 return null; 341 } 342 343 /** 344 * This class is only used internally so this method should never 345 * be called. 346 */ 347 public int getColumnNumber() { 348 return 0; 349 } 350 351 /** 352 * This class is only used internally so this method should never 353 * be called. 354 */ 355 public int getLineNumber() { 356 return 0; 357 } 358 359 /** 360 * This class is only used internally so this method should never 361 * be called. 362 */ 363 public String getPublicId() { 364 return null; 365 } 366 367 /** 368 * This class is only used internally so this method should never 369 * be called. 370 */ 371 public String getSystemId() { 372 return null; 373 } 374 375 376 private void setDocumentInfo(Document document) { 377 if (!document.getXmlStandalone()) 378 _handler.setStandalone(Boolean.toString(document.getXmlStandalone())); 379 setXMLVersion(document.getXmlVersion()); 380 setEncoding(document.getXmlEncoding()); 381 } 382 383 public String getXMLVersion() { 384 return xmlVersion; 385 } 386 387 private void setXMLVersion(String version) { 388 if (version != null) { 389 xmlVersion = version; 390 _handler.setVersion(xmlVersion); 391 } 392 } 393 394 public String getEncoding() { 395 return xmlEncoding; 396 } 397 398 private void setEncoding(String encoding) { 399 if (encoding != null) { 400 xmlEncoding = encoding; 401 _handler.setEncoding(encoding); 402 } 403 } 404 405 // Debugging 406 private String getNodeTypeFromCode(short code) { 407 String retval = null; 408 switch (code) { 409 case Node.ATTRIBUTE_NODE : 410 retval = "ATTRIBUTE_NODE"; break; 411 case Node.CDATA_SECTION_NODE : 412 retval = "CDATA_SECTION_NODE"; break; 413 case Node.COMMENT_NODE : 414 retval = "COMMENT_NODE"; break; 415 case Node.DOCUMENT_FRAGMENT_NODE : 416 retval = "DOCUMENT_FRAGMENT_NODE"; break; 417 case Node.DOCUMENT_NODE : 418 retval = "DOCUMENT_NODE"; break; 419 case Node.DOCUMENT_TYPE_NODE : 420 retval = "DOCUMENT_TYPE_NODE"; break; 421 case Node.ELEMENT_NODE : 422 retval = "ELEMENT_NODE"; break; 423 case Node.ENTITY_NODE : 424 retval = "ENTITY_NODE"; break; 425 case Node.ENTITY_REFERENCE_NODE : 426 retval = "ENTITY_REFERENCE_NODE"; break; 427 case Node.NOTATION_NODE : 428 retval = "NOTATION_NODE"; break; 429 case Node.PROCESSING_INSTRUCTION_NODE : 430 retval = "PROCESSING_INSTRUCTION_NODE"; break; 431 case Node.TEXT_NODE: 432 retval = "TEXT_NODE"; break; 433 } 434 return retval; 435 } 436 }