1 /* 2 * Copyright (c) 2015, 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 package com.sun.org.apache.xml.internal.utils; 21 22 import com.sun.org.apache.xalan.internal.utils.SecuritySupport; 23 import java.io.File; 24 25 import org.w3c.dom.Comment; 26 import org.w3c.dom.Element; 27 import org.w3c.dom.EntityReference; 28 import org.w3c.dom.NamedNodeMap; 29 import org.w3c.dom.Node; 30 import org.w3c.dom.ProcessingInstruction; 31 import org.w3c.dom.Text; 32 33 import org.xml.sax.ContentHandler; 34 import org.xml.sax.Locator; 35 import org.xml.sax.ext.LexicalHandler; 36 import org.xml.sax.helpers.LocatorImpl; 37 38 /** 39 * This class does a pre-order walk of the DOM tree, calling a ContentHandler 40 * interface as it goes. 41 * @xsl.usage advanced 42 */ 43 44 public class TreeWalker 45 { 46 47 /** Local reference to a ContentHandler */ 48 private ContentHandler m_contentHandler = null; 49 50 // ARGHH!! JAXP Uses Xerces without setting the namespace processing to ON! 51 // DOM2Helper m_dh = new DOM2Helper(); 52 53 /** DomHelper for this TreeWalker */ 54 protected DOMHelper m_dh; 55 56 /** Locator object for this TreeWalker */ 57 private LocatorImpl m_locator = new LocatorImpl(); 58 59 /** 60 * Get the ContentHandler used for the tree walk. 61 * 62 * @return the ContentHandler used for the tree walk 63 */ 64 public ContentHandler getContentHandler() 65 { 66 return m_contentHandler; 67 } 68 69 /** 70 * Get the ContentHandler used for the tree walk. 71 * 72 * @return the ContentHandler used for the tree walk 73 */ 74 public void setContentHandler(ContentHandler ch) 75 { 76 m_contentHandler = ch; 77 } 78 79 /** 80 * Constructor. 81 * @param contentHandler The implementation of the 82 * @param systemId System identifier for the document. 83 * contentHandler operation (toXMLString, digest, ...) 84 */ 85 public TreeWalker(ContentHandler contentHandler, DOMHelper dh, String systemId) 86 { 87 this.m_contentHandler = contentHandler; 88 m_contentHandler.setDocumentLocator(m_locator); 89 if (systemId != null) { 90 m_locator.setSystemId(systemId); 91 } 92 m_dh = dh; 93 } 94 95 /** 96 * Constructor. 97 * @param contentHandler The implementation of the 98 * contentHandler operation (toXMLString, digest, ...) 99 */ 100 public TreeWalker(ContentHandler contentHandler, DOMHelper dh) 101 { 102 this.m_contentHandler = contentHandler; 103 m_contentHandler.setDocumentLocator(m_locator); 104 m_dh = dh; 105 } 106 107 /** 108 * Constructor. 109 * @param contentHandler The implementation of the 110 * contentHandler operation (toXMLString, digest, ...) 111 */ 112 public TreeWalker(ContentHandler contentHandler) 113 { 114 this.m_contentHandler = contentHandler; 115 if (m_contentHandler != null) { 116 m_contentHandler.setDocumentLocator(m_locator); 117 } 118 m_dh = new DOM2Helper(); 119 } 120 121 /** 122 * Perform a pre-order traversal non-recursive style. 123 * 124 * Note that TreeWalker assumes that the subtree is intended to represent 125 * a complete (though not necessarily well-formed) document and, during a 126 * traversal, startDocument and endDocument will always be issued to the 127 * SAX listener. 128 * 129 * @param pos Node in the tree where to start traversal 130 * 131 * @throws TransformerException 132 */ 133 public void traverse(Node pos) throws org.xml.sax.SAXException 134 { 135 this.m_contentHandler.startDocument(); 136 137 traverseFragment(pos); 138 222 nextNode = pos.getNextSibling(); 223 224 if (null == nextNode) 225 { 226 pos = pos.getParentNode(); 227 228 if ((null == pos) || ((null != top) && top.equals(pos))) 229 { 230 nextNode = null; 231 232 break; 233 } 234 } 235 } 236 237 pos = nextNode; 238 } 239 this.m_contentHandler.endDocument(); 240 } 241 242 /** Flag indicating whether following text to be processed is raw text */ 243 boolean nextIsRaw = false; 244 245 /** 246 * Optimized dispatch of characters. 247 */ 248 private final void dispatachChars(Node node) 249 throws org.xml.sax.SAXException 250 { 251 if(m_contentHandler instanceof com.sun.org.apache.xml.internal.dtm.ref.dom2dtm.DOM2DTM.CharacterNodeHandler) 252 { 253 ((com.sun.org.apache.xml.internal.dtm.ref.dom2dtm.DOM2DTM.CharacterNodeHandler)m_contentHandler).characters(node); 254 } 255 else 256 { 257 String data = ((Text) node).getData(); 258 this.m_contentHandler.characters(data.toCharArray(), 0, data.length()); 259 } 260 } 261 262 /** 263 * Start processing given node 264 * 265 * 266 * @param node Node to process 267 * 268 * @throws org.xml.sax.SAXException 269 */ 270 protected void startNode(Node node) throws org.xml.sax.SAXException 271 { 272 273 if (m_contentHandler instanceof NodeConsumer) 296 String data = ((Comment) node).getData(); 297 298 if (m_contentHandler instanceof LexicalHandler) 299 { 300 LexicalHandler lh = ((LexicalHandler) this.m_contentHandler); 301 302 lh.comment(data.toCharArray(), 0, data.length()); 303 } 304 } 305 break; 306 case Node.DOCUMENT_FRAGMENT_NODE : 307 308 // ??; 309 break; 310 case Node.DOCUMENT_NODE : 311 312 break; 313 case Node.ELEMENT_NODE : 314 NamedNodeMap atts = ((Element) node).getAttributes(); 315 int nAttrs = atts.getLength(); 316 // System.out.println("TreeWalker#startNode: "+node.getNodeName()); 317 318 for (int i = 0; i < nAttrs; i++) 319 { 320 Node attr = atts.item(i); 321 String attrName = attr.getNodeName(); 322 323 // System.out.println("TreeWalker#startNode: attr["+i+"] = "+attrName+", "+attr.getNodeValue()); 324 if (attrName.equals("xmlns") || attrName.startsWith("xmlns:")) 325 { 326 // System.out.println("TreeWalker#startNode: attr["+i+"] = "+attrName+", "+attr.getNodeValue()); 327 int index; 328 // Use "" instead of null, as Xerces likes "" for the 329 // name of the default namespace. Fix attributed 330 // to "Steven Murray" <smurray@ebt.com>. 331 String prefix = (index = attrName.indexOf(":")) < 0 332 ? "" : attrName.substring(index + 1); 333 334 this.m_contentHandler.startPrefixMapping(prefix, 335 attr.getNodeValue()); 336 } 337 338 } 339 340 // System.out.println("m_dh.getNamespaceOfNode(node): "+m_dh.getNamespaceOfNode(node)); 341 // System.out.println("m_dh.getLocalNameOfNode(node): "+m_dh.getLocalNameOfNode(node)); 342 String ns = m_dh.getNamespaceOfNode(node); 343 if(null == ns) 344 ns = ""; 345 this.m_contentHandler.startElement(ns, 346 m_dh.getLocalNameOfNode(node), 347 node.getNodeName(), 348 new AttList(atts, m_dh)); 349 break; 350 case Node.PROCESSING_INSTRUCTION_NODE : 351 { 352 ProcessingInstruction pi = (ProcessingInstruction) node; 353 String name = pi.getNodeName(); 354 355 // String data = pi.getData(); 356 if (name.equals("xslt-next-is-raw")) 357 { 358 nextIsRaw = true; 359 } 360 else 361 { 362 this.m_contentHandler.processingInstruction(pi.getNodeName(), 363 pi.getData()); 364 } 365 } 366 break; 367 case Node.CDATA_SECTION_NODE : 368 { 376 } 377 378 dispatachChars(node); 379 380 { 381 if (isLexH) 382 { 383 lh.endCDATA(); 384 } 385 } 386 } 387 break; 388 case Node.TEXT_NODE : 389 { 390 //String data = ((Text) node).getData(); 391 392 if (nextIsRaw) 393 { 394 nextIsRaw = false; 395 396 m_contentHandler.processingInstruction(javax.xml.transform.Result.PI_DISABLE_OUTPUT_ESCAPING, ""); 397 dispatachChars(node); 398 m_contentHandler.processingInstruction(javax.xml.transform.Result.PI_ENABLE_OUTPUT_ESCAPING, ""); 399 } 400 else 401 { 402 dispatachChars(node); 403 } 404 } 405 break; 406 case Node.ENTITY_REFERENCE_NODE : 407 { 408 EntityReference eref = (EntityReference) node; 409 410 if (m_contentHandler instanceof LexicalHandler) 411 { 412 ((LexicalHandler) this.m_contentHandler).startEntity( 413 eref.getNodeName()); 414 } 415 else 416 { 417 418 // warning("Can not output entity to a pure SAX ContentHandler"); 423 } 424 } 425 426 /** 427 * End processing of given node 428 * 429 * 430 * @param node Node we just finished processing 431 * 432 * @throws org.xml.sax.SAXException 433 */ 434 protected void endNode(Node node) throws org.xml.sax.SAXException 435 { 436 437 switch (node.getNodeType()) 438 { 439 case Node.DOCUMENT_NODE : 440 break; 441 442 case Node.ELEMENT_NODE : 443 String ns = m_dh.getNamespaceOfNode(node); 444 if(null == ns) 445 ns = ""; 446 this.m_contentHandler.endElement(ns, 447 m_dh.getLocalNameOfNode(node), 448 node.getNodeName()); 449 450 NamedNodeMap atts = ((Element) node).getAttributes(); 451 int nAttrs = atts.getLength(); 452 453 for (int i = 0; i < nAttrs; i++) 454 { 455 Node attr = atts.item(i); 456 String attrName = attr.getNodeName(); 457 458 if (attrName.equals("xmlns") || attrName.startsWith("xmlns:")) 459 { 460 int index; 461 // Use "" instead of null, as Xerces likes "" for the 462 // name of the default namespace. Fix attributed 463 // to "Steven Murray" <smurray@ebt.com>. 464 String prefix = (index = attrName.indexOf(":")) < 0 465 ? "" : attrName.substring(index + 1); 466 467 this.m_contentHandler.endPrefixMapping(prefix); | 1 /* 2 * Copyright (c) 2015, 2017, 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.xml.internal.utils; 22 23 import com.sun.org.apache.xml.internal.dtm.ref.dom2dtm.DOM2DTM.CharacterNodeHandler; 24 import javax.xml.transform.Result; 25 import org.w3c.dom.Comment; 26 import org.w3c.dom.Element; 27 import org.w3c.dom.EntityReference; 28 import org.w3c.dom.NamedNodeMap; 29 import org.w3c.dom.Node; 30 import org.w3c.dom.ProcessingInstruction; 31 import org.w3c.dom.Text; 32 33 import org.xml.sax.ContentHandler; 34 import org.xml.sax.Locator; 35 import org.xml.sax.ext.LexicalHandler; 36 import org.xml.sax.helpers.LocatorImpl; 37 38 /** 39 * This class does a pre-order walk of the DOM tree, calling a ContentHandler 40 * interface as it goes. 41 * @xsl.usage advanced 42 */ 43 44 public class TreeWalker 45 { 46 47 /** Local reference to a ContentHandler */ 48 private ContentHandler m_contentHandler = null; 49 50 /** Locator object for this TreeWalker */ 51 private LocatorImpl m_locator = new LocatorImpl(); 52 53 /** 54 * Get the ContentHandler used for the tree walk. 55 * 56 * @return the ContentHandler used for the tree walk 57 */ 58 public ContentHandler getContentHandler() 59 { 60 return m_contentHandler; 61 } 62 63 /** 64 * Get the ContentHandler used for the tree walk. 65 * 66 * @return the ContentHandler used for the tree walk 67 */ 68 public void setContentHandler(ContentHandler ch) 69 { 70 m_contentHandler = ch; 71 } 72 73 /** 74 * Constructor. 75 * @param contentHandler The implementation of the 76 * @param systemId System identifier for the document. 77 * contentHandler operation (toXMLString, digest, ...) 78 */ 79 public TreeWalker(ContentHandler contentHandler, String systemId) 80 { 81 this.m_contentHandler = contentHandler; 82 if (m_contentHandler != null) { 83 m_contentHandler.setDocumentLocator(m_locator); 84 } 85 if (systemId != null) { 86 m_locator.setSystemId(systemId); 87 } 88 } 89 90 /** 91 * Constructor. 92 * @param contentHandler The implementation of the 93 * contentHandler operation (toXMLString, digest, ...) 94 */ 95 public TreeWalker(ContentHandler contentHandler) 96 { 97 this(contentHandler, null); 98 } 99 100 /** 101 * Perform a pre-order traversal non-recursive style. 102 * 103 * Note that TreeWalker assumes that the subtree is intended to represent 104 * a complete (though not necessarily well-formed) document and, during a 105 * traversal, startDocument and endDocument will always be issued to the 106 * SAX listener. 107 * 108 * @param pos Node in the tree where to start traversal 109 * 110 * @throws TransformerException 111 */ 112 public void traverse(Node pos) throws org.xml.sax.SAXException 113 { 114 this.m_contentHandler.startDocument(); 115 116 traverseFragment(pos); 117 201 nextNode = pos.getNextSibling(); 202 203 if (null == nextNode) 204 { 205 pos = pos.getParentNode(); 206 207 if ((null == pos) || ((null != top) && top.equals(pos))) 208 { 209 nextNode = null; 210 211 break; 212 } 213 } 214 } 215 216 pos = nextNode; 217 } 218 this.m_contentHandler.endDocument(); 219 } 220 221 // Flag indicating whether following text to be processed is raw text 222 boolean nextIsRaw = false; 223 224 /** 225 * Optimized dispatch of characters. 226 */ 227 private final void dispatachChars(Node node) 228 throws org.xml.sax.SAXException 229 { 230 if(m_contentHandler instanceof CharacterNodeHandler) 231 { 232 ((CharacterNodeHandler)m_contentHandler).characters(node); 233 } 234 else 235 { 236 String data = ((Text) node).getData(); 237 this.m_contentHandler.characters(data.toCharArray(), 0, data.length()); 238 } 239 } 240 241 /** 242 * Start processing given node 243 * 244 * 245 * @param node Node to process 246 * 247 * @throws org.xml.sax.SAXException 248 */ 249 protected void startNode(Node node) throws org.xml.sax.SAXException 250 { 251 252 if (m_contentHandler instanceof NodeConsumer) 275 String data = ((Comment) node).getData(); 276 277 if (m_contentHandler instanceof LexicalHandler) 278 { 279 LexicalHandler lh = ((LexicalHandler) this.m_contentHandler); 280 281 lh.comment(data.toCharArray(), 0, data.length()); 282 } 283 } 284 break; 285 case Node.DOCUMENT_FRAGMENT_NODE : 286 287 // ??; 288 break; 289 case Node.DOCUMENT_NODE : 290 291 break; 292 case Node.ELEMENT_NODE : 293 NamedNodeMap atts = ((Element) node).getAttributes(); 294 int nAttrs = atts.getLength(); 295 296 for (int i = 0; i < nAttrs; i++) 297 { 298 Node attr = atts.item(i); 299 String attrName = attr.getNodeName(); 300 301 if (attrName.equals("xmlns") || attrName.startsWith("xmlns:")) 302 { 303 int index; 304 // Use "" instead of null, as Xerces likes "" for the 305 // name of the default namespace. Fix attributed 306 // to "Steven Murray" <smurray@ebt.com>. 307 String prefix = (index = attrName.indexOf(":")) < 0 308 ? "" : attrName.substring(index + 1); 309 310 this.m_contentHandler.startPrefixMapping(prefix, 311 attr.getNodeValue()); 312 } 313 314 } 315 316 String ns = DOM2Helper.getNamespaceOfNode(node); 317 if(null == ns) 318 ns = ""; 319 this.m_contentHandler.startElement(ns, 320 DOM2Helper.getLocalNameOfNode(node), 321 node.getNodeName(), 322 new AttList(atts)); 323 break; 324 case Node.PROCESSING_INSTRUCTION_NODE : 325 { 326 ProcessingInstruction pi = (ProcessingInstruction) node; 327 String name = pi.getNodeName(); 328 329 // String data = pi.getData(); 330 if (name.equals("xslt-next-is-raw")) 331 { 332 nextIsRaw = true; 333 } 334 else 335 { 336 this.m_contentHandler.processingInstruction(pi.getNodeName(), 337 pi.getData()); 338 } 339 } 340 break; 341 case Node.CDATA_SECTION_NODE : 342 { 350 } 351 352 dispatachChars(node); 353 354 { 355 if (isLexH) 356 { 357 lh.endCDATA(); 358 } 359 } 360 } 361 break; 362 case Node.TEXT_NODE : 363 { 364 //String data = ((Text) node).getData(); 365 366 if (nextIsRaw) 367 { 368 nextIsRaw = false; 369 370 m_contentHandler.processingInstruction(Result.PI_DISABLE_OUTPUT_ESCAPING, ""); 371 dispatachChars(node); 372 m_contentHandler.processingInstruction(Result.PI_ENABLE_OUTPUT_ESCAPING, ""); 373 } 374 else 375 { 376 dispatachChars(node); 377 } 378 } 379 break; 380 case Node.ENTITY_REFERENCE_NODE : 381 { 382 EntityReference eref = (EntityReference) node; 383 384 if (m_contentHandler instanceof LexicalHandler) 385 { 386 ((LexicalHandler) this.m_contentHandler).startEntity( 387 eref.getNodeName()); 388 } 389 else 390 { 391 392 // warning("Can not output entity to a pure SAX ContentHandler"); 397 } 398 } 399 400 /** 401 * End processing of given node 402 * 403 * 404 * @param node Node we just finished processing 405 * 406 * @throws org.xml.sax.SAXException 407 */ 408 protected void endNode(Node node) throws org.xml.sax.SAXException 409 { 410 411 switch (node.getNodeType()) 412 { 413 case Node.DOCUMENT_NODE : 414 break; 415 416 case Node.ELEMENT_NODE : 417 String ns = DOM2Helper.getNamespaceOfNode(node); 418 if(null == ns) 419 ns = ""; 420 this.m_contentHandler.endElement(ns, 421 DOM2Helper.getLocalNameOfNode(node), 422 node.getNodeName()); 423 424 NamedNodeMap atts = ((Element) node).getAttributes(); 425 int nAttrs = atts.getLength(); 426 427 for (int i = 0; i < nAttrs; i++) 428 { 429 Node attr = atts.item(i); 430 String attrName = attr.getNodeName(); 431 432 if (attrName.equals("xmlns") || attrName.startsWith("xmlns:")) 433 { 434 int index; 435 // Use "" instead of null, as Xerces likes "" for the 436 // name of the default namespace. Fix attributed 437 // to "Steven Murray" <smurray@ebt.com>. 438 String prefix = (index = attrName.indexOf(":")) < 0 439 ? "" : attrName.substring(index + 1); 440 441 this.m_contentHandler.endPrefixMapping(prefix); |