1 /* 2 * Copyright (c) 2019, Oracle and/or its affiliates. All rights reserved. 3 */ 4 /* 5 * Licensed to the Apache Software Foundation (ASF) under one or more 6 * contributor license agreements. See the NOTICE file distributed with 7 * this work for additional information regarding copyright ownership. 8 * The ASF licenses this file to You under the Apache License, Version 2.0 9 * (the "License"); you may not use this file except in compliance with 10 * the License. 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 package com.sun.org.apache.xalan.internal.xsltc.trax; 22 23 import java.io.IOException; 24 25 import org.w3c.dom.NamedNodeMap; 26 import org.w3c.dom.Node; 27 import org.w3c.dom.Document; 28 import com.sun.org.apache.xml.internal.serializer.SerializationHandler; 29 import org.xml.sax.ContentHandler; 30 import org.xml.sax.DTDHandler; 31 import org.xml.sax.EntityResolver; 32 import org.xml.sax.ErrorHandler; 33 import org.xml.sax.InputSource; 34 import org.xml.sax.ext.Locator2; 35 import org.xml.sax.SAXException; 36 import org.xml.sax.SAXNotRecognizedException; 37 import org.xml.sax.SAXNotSupportedException; 38 import org.xml.sax.XMLReader; 39 import com.sun.org.apache.xml.internal.serializer.NamespaceMappings; 40 41 /** 42 * @author Santiago Pericas-Geertsen 43 * @author Sunitha Reddy 44 * @LastModified: Nov 2019 45 */ 46 public 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 DOM2TO(Node root, SerializationHandler handler)67 public DOM2TO(Node root, SerializationHandler handler) { 68 _dom = root; 69 _handler = handler; 70 } 71 getContentHandler()72 public ContentHandler getContentHandler() { 73 return null; 74 } 75 setContentHandler(ContentHandler handler)76 public void setContentHandler(ContentHandler handler) { 77 // Empty 78 } 79 parse(InputSource unused)80 public void parse(InputSource unused) throws IOException, SAXException { 81 parse(_dom); 82 } 83 parse()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 */ parse(Node node)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 = null; 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 if (nm == null) nm = new NamespaceMappings(); 191 String newPrefix = nm.lookupPrefix(uriAttr); 192 if (newPrefix == null) 193 newPrefix = nm.generateNextPrefix(); 194 prefix = (colon > 0) ? qnameAttr.substring(0, colon) 195 : newPrefix; 196 _handler.namespaceAfterStartElement(prefix, uriAttr); 197 _handler.addAttribute((prefix + ":" + qnameAttr), 198 attr.getNodeValue()); 199 } else { 200 _handler.addAttribute(qnameAttr, attr.getNodeValue()); 201 } 202 } 203 } 204 205 // Now element namespace and children 206 final String uri = node.getNamespaceURI(); 207 final String localName = node.getLocalName(); 208 209 // Uri may be implicitly declared 210 if (uri != null) { 211 colon = qname.lastIndexOf(':'); 212 prefix = (colon > 0) ? qname.substring(0, colon) : EMPTYSTRING; 213 _handler.namespaceAfterStartElement(prefix, uri); 214 }else { 215 // Fix for bug 26319 216 // If an element foo is created using 217 // createElementNS(null,locName) 218 // then the element should be serialized 219 // <foo xmlns=" "/> 220 if (uri == null && localName != null) { 221 prefix = EMPTYSTRING; 222 _handler.namespaceAfterStartElement(prefix, EMPTYSTRING); 223 } 224 } 225 226 // Traverse all child nodes of the element (if any) 227 next = node.getFirstChild(); 228 while (next != null) { 229 parse(next); 230 next = next.getNextSibling(); 231 } 232 233 // Generate SAX event to close element 234 _handler.endElement(qname); 235 break; 236 237 case Node.PROCESSING_INSTRUCTION_NODE: 238 _handler.processingInstruction(node.getNodeName(), 239 node.getNodeValue()); 240 break; 241 242 case Node.TEXT_NODE: 243 _handler.characters(node.getNodeValue()); 244 break; 245 } 246 } 247 248 /** 249 * This class is only used internally so this method should never 250 * be called. 251 */ getDTDHandler()252 public DTDHandler getDTDHandler() { 253 return null; 254 } 255 256 /** 257 * This class is only used internally so this method should never 258 * be called. 259 */ getErrorHandler()260 public ErrorHandler getErrorHandler() { 261 return null; 262 } 263 264 /** 265 * This class is only used internally so this method should never 266 * be called. 267 */ getFeature(String name)268 public boolean getFeature(String name) throws SAXNotRecognizedException, 269 SAXNotSupportedException 270 { 271 return false; 272 } 273 274 /** 275 * This class is only used internally so this method should never 276 * be called. 277 */ setFeature(String name, boolean value)278 public void setFeature(String name, boolean value) throws 279 SAXNotRecognizedException, SAXNotSupportedException 280 { 281 } 282 283 /** 284 * This class is only used internally so this method should never 285 * be called. 286 */ parse(String sysId)287 public void parse(String sysId) throws IOException, SAXException { 288 throw new IOException("This method is not yet implemented."); 289 } 290 291 /** 292 * This class is only used internally so this method should never 293 * be called. 294 */ setDTDHandler(DTDHandler handler)295 public void setDTDHandler(DTDHandler handler) throws NullPointerException { 296 } 297 298 /** 299 * This class is only used internally so this method should never 300 * be called. 301 */ setEntityResolver(EntityResolver resolver)302 public void setEntityResolver(EntityResolver resolver) throws 303 NullPointerException 304 { 305 } 306 307 /** 308 * This class is only used internally so this method should never 309 * be called. 310 */ getEntityResolver()311 public EntityResolver getEntityResolver() { 312 return null; 313 } 314 315 /** 316 * This class is only used internally so this method should never 317 * be called. 318 */ setErrorHandler(ErrorHandler handler)319 public void setErrorHandler(ErrorHandler handler) throws 320 NullPointerException 321 { 322 } 323 324 /** 325 * This class is only used internally so this method should never 326 * be called. 327 */ setProperty(String name, Object value)328 public void setProperty(String name, Object value) throws 329 SAXNotRecognizedException, SAXNotSupportedException { 330 } 331 332 /** 333 * This class is only used internally so this method should never 334 * be called. 335 */ getProperty(String name)336 public Object getProperty(String name) throws SAXNotRecognizedException, 337 SAXNotSupportedException 338 { 339 return null; 340 } 341 342 /** 343 * This class is only used internally so this method should never 344 * be called. 345 */ getColumnNumber()346 public int getColumnNumber() { 347 return 0; 348 } 349 350 /** 351 * This class is only used internally so this method should never 352 * be called. 353 */ getLineNumber()354 public int getLineNumber() { 355 return 0; 356 } 357 358 /** 359 * This class is only used internally so this method should never 360 * be called. 361 */ getPublicId()362 public String getPublicId() { 363 return null; 364 } 365 366 /** 367 * This class is only used internally so this method should never 368 * be called. 369 */ getSystemId()370 public String getSystemId() { 371 return null; 372 } 373 374 setDocumentInfo(Document document)375 private void setDocumentInfo(Document document) { 376 if (!document.getXmlStandalone()) 377 _handler.setStandalone(Boolean.toString(document.getXmlStandalone())); 378 setXMLVersion(document.getXmlVersion()); 379 setEncoding(document.getXmlEncoding()); 380 } 381 getXMLVersion()382 public String getXMLVersion() { 383 return xmlVersion; 384 } 385 setXMLVersion(String version)386 private void setXMLVersion(String version) { 387 if (version != null) { 388 xmlVersion = version; 389 _handler.setVersion(xmlVersion); 390 } 391 } 392 getEncoding()393 public String getEncoding() { 394 return xmlEncoding; 395 } 396 setEncoding(String encoding)397 private void setEncoding(String encoding) { 398 if (encoding != null) { 399 xmlEncoding = encoding; 400 _handler.setEncoding(encoding); 401 } 402 } 403 404 // Debugging getNodeTypeFromCode(short code)405 private String getNodeTypeFromCode(short code) { 406 String retval = null; 407 switch (code) { 408 case Node.ATTRIBUTE_NODE : 409 retval = "ATTRIBUTE_NODE"; break; 410 case Node.CDATA_SECTION_NODE : 411 retval = "CDATA_SECTION_NODE"; break; 412 case Node.COMMENT_NODE : 413 retval = "COMMENT_NODE"; break; 414 case Node.DOCUMENT_FRAGMENT_NODE : 415 retval = "DOCUMENT_FRAGMENT_NODE"; break; 416 case Node.DOCUMENT_NODE : 417 retval = "DOCUMENT_NODE"; break; 418 case Node.DOCUMENT_TYPE_NODE : 419 retval = "DOCUMENT_TYPE_NODE"; break; 420 case Node.ELEMENT_NODE : 421 retval = "ELEMENT_NODE"; break; 422 case Node.ENTITY_NODE : 423 retval = "ENTITY_NODE"; break; 424 case Node.ENTITY_REFERENCE_NODE : 425 retval = "ENTITY_REFERENCE_NODE"; break; 426 case Node.NOTATION_NODE : 427 retval = "NOTATION_NODE"; break; 428 case Node.PROCESSING_INSTRUCTION_NODE : 429 retval = "PROCESSING_INSTRUCTION_NODE"; break; 430 case Node.TEXT_NODE: 431 retval = "TEXT_NODE"; break; 432 } 433 return retval; 434 } 435 } 436