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