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.xml.internal.dtm.ref; 23 24import com.sun.org.apache.xml.internal.dtm.DTM; 25import com.sun.org.apache.xml.internal.utils.NodeConsumer; 26import com.sun.org.apache.xml.internal.utils.XMLString; 27 28import org.xml.sax.ContentHandler; 29import org.xml.sax.ext.LexicalHandler; 30 31/** 32 * This class does a pre-order walk of the DTM tree, calling a ContentHandler 33 * interface as it goes. As such, it's more like the Visitor design pattern 34 * than like the DOM's TreeWalker. 35 * 36 * I think normally this class should not be needed, because 37 * of DTM#dispatchToEvents. 38 * @xsl.usage advanced 39 */ 40public class DTMTreeWalker 41{ 42 43 /** Local reference to a ContentHandler */ 44 private ContentHandler m_contentHandler = null; 45 46 /** DomHelper for this TreeWalker */ 47 protected DTM m_dtm; 48 49 /** 50 * Set the DTM to be traversed. 51 * 52 * @param dtm The Document Table Model to be used. 53 */ 54 public void setDTM(DTM dtm) 55 { 56 m_dtm = dtm; 57 } 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 * Set the ContentHandler used for the tree walk. 71 * 72 * @param ch the ContentHandler to be the result of the tree walk. 73 */ 74 public void setcontentHandler(ContentHandler ch) 75 { 76 m_contentHandler = ch; 77 } 78 79 80 /** 81 * Constructor. 82 */ 83 public DTMTreeWalker() 84 { 85 } 86 87 /** 88 * Constructor. 89 * @param contentHandler The implemention of the 90 * contentHandler operation (toXMLString, digest, ...) 91 */ 92 public DTMTreeWalker(ContentHandler contentHandler, DTM dtm) 93 { 94 this.m_contentHandler = contentHandler; 95 m_dtm = dtm; 96 } 97 98 /** Perform a non-recursive pre-order/post-order traversal, 99 * operating as a Visitor. startNode (preorder) and endNode 100 * (postorder) are invoked for each node as we traverse over them, 101 * with the result that the node is written out to m_contentHandler. 102 * 103 * @param pos Node in the tree at which to start (and end) traversal -- 104 * in other words, the root of the subtree to traverse over. 105 * 106 * @throws TransformerException */ 107 public void traverse(int pos) throws org.xml.sax.SAXException 108 { 109 // %REVIEW% Why isn't this just traverse(pos,pos)? 110 111 int top = pos; // Remember the root of this subtree 112 113 while (DTM.NULL != pos) 114 { 115 startNode(pos); 116 int nextNode = m_dtm.getFirstChild(pos); 117 while (DTM.NULL == nextNode) 118 { 119 endNode(pos); 120 121 if (top == pos) 122 break; 123 124 nextNode = m_dtm.getNextSibling(pos); 125 126 if (DTM.NULL == nextNode) 127 { 128 pos = m_dtm.getParent(pos); 129 130 if ((DTM.NULL == pos) || (top == pos)) 131 { 132 // %REVIEW% This condition isn't tested in traverse(pos,top) 133 // -- bug? 134 if (DTM.NULL != pos) 135 endNode(pos); 136 137 nextNode = DTM.NULL; 138 139 break; 140 } 141 } 142 } 143 144 pos = nextNode; 145 } 146 } 147 148 /** Perform a non-recursive pre-order/post-order traversal, 149 * operating as a Visitor. startNode (preorder) and endNode 150 * (postorder) are invoked for each node as we traverse over them, 151 * with the result that the node is written out to m_contentHandler. 152 * 153 * @param pos Node in the tree where to start traversal 154 * @param top Node in the tree where to end traversal. 155 * If top==DTM.NULL, run through end of document. 156 * 157 * @throws TransformerException 158 */ 159 public void traverse(int pos, int top) throws org.xml.sax.SAXException 160 { 161 // %OPT% Can we simplify the loop conditionals by adding: 162 // if(top==DTM.NULL) top=0 163 // -- or by simply ignoring this case and relying on the fact that 164 // pos will never equal DTM.NULL until we're ready to exit? 165 166 while (DTM.NULL != pos) 167 { 168 startNode(pos); 169 int nextNode = m_dtm.getFirstChild(pos); 170 while (DTM.NULL == nextNode) 171 { 172 endNode(pos); 173 174 if ((DTM.NULL != top) && top == pos) 175 break; 176 177 nextNode = m_dtm.getNextSibling(pos); 178 179 if (DTM.NULL == nextNode) 180 { 181 pos = m_dtm.getParent(pos); 182 183 if ((DTM.NULL == pos) || ((DTM.NULL != top) && (top == pos))) 184 { 185 nextNode = DTM.NULL; 186 187 break; 188 } 189 } 190 } 191 192 pos = nextNode; 193 } 194 } 195 196 /** Flag indicating whether following text to be processed is raw text */ 197 boolean nextIsRaw = false; 198 199 /** 200 * Optimized dispatch of characters. 201 */ 202 private final void dispatachChars(int node) 203 throws org.xml.sax.SAXException 204 { 205 m_dtm.dispatchCharactersEvents(node, m_contentHandler, false); 206 } 207 208 /** 209 * Start processing given node 210 * 211 * 212 * @param node Node to process 213 * 214 * @throws org.xml.sax.SAXException 215 */ 216 protected void startNode(int node) throws org.xml.sax.SAXException 217 { 218 219 if (m_contentHandler instanceof NodeConsumer) 220 { 221 // %TBD% 222// ((NodeConsumer) m_contentHandler).setOriginatingNode(node); 223 } 224 225 switch (m_dtm.getNodeType(node)) 226 { 227 case DTM.COMMENT_NODE : 228 { 229 XMLString data = m_dtm.getStringValue(node); 230 231 if (m_contentHandler instanceof LexicalHandler) 232 { 233 LexicalHandler lh = ((LexicalHandler) this.m_contentHandler); 234 data.dispatchAsComment(lh); 235 } 236 } 237 break; 238 case DTM.DOCUMENT_FRAGMENT_NODE : 239 240 // ??; 241 break; 242 case DTM.DOCUMENT_NODE : 243 this.m_contentHandler.startDocument(); 244 break; 245 case DTM.ELEMENT_NODE : 246 DTM dtm = m_dtm; 247 248 for (int nsn = dtm.getFirstNamespaceNode(node, true); DTM.NULL != nsn; 249 nsn = dtm.getNextNamespaceNode(node, nsn, true)) 250 { 251 // String prefix = dtm.getPrefix(nsn); 252 String prefix = dtm.getNodeNameX(nsn); 253 254 this.m_contentHandler.startPrefixMapping(prefix, dtm.getNodeValue(nsn)); 255 256 } 257 258 // System.out.println("m_dh.getNamespaceOfNode(node): "+m_dh.getNamespaceOfNode(node)); 259 // System.out.println("m_dh.getLocalNameOfNode(node): "+m_dh.getLocalNameOfNode(node)); 260 String ns = dtm.getNamespaceURI(node); 261 if(null == ns) 262 ns = ""; 263 264 // %OPT% !! 265 org.xml.sax.helpers.AttributesImpl attrs = 266 new org.xml.sax.helpers.AttributesImpl(); 267 268 for (int i = dtm.getFirstAttribute(node); 269 i != DTM.NULL; 270 i = dtm.getNextAttribute(i)) 271 { 272 attrs.addAttribute(dtm.getNamespaceURI(i), 273 dtm.getLocalName(i), 274 dtm.getNodeName(i), 275 "CDATA", 276 dtm.getNodeValue(i)); 277 } 278 279 280 this.m_contentHandler.startElement(ns, 281 m_dtm.getLocalName(node), 282 m_dtm.getNodeName(node), 283 attrs); 284 break; 285 case DTM.PROCESSING_INSTRUCTION_NODE : 286 { 287 String name = m_dtm.getNodeName(node); 288 289 // String data = pi.getData(); 290 if (name.equals("xslt-next-is-raw")) 291 { 292 nextIsRaw = true; 293 } 294 else 295 { 296 this.m_contentHandler.processingInstruction(name, 297 m_dtm.getNodeValue(node)); 298 } 299 } 300 break; 301 case DTM.CDATA_SECTION_NODE : 302 { 303 boolean isLexH = (m_contentHandler instanceof LexicalHandler); 304 LexicalHandler lh = isLexH 305 ? ((LexicalHandler) this.m_contentHandler) : null; 306 307 if (isLexH) 308 { 309 lh.startCDATA(); 310 } 311 312 dispatachChars(node); 313 314 { 315 if (isLexH) 316 { 317 lh.endCDATA(); 318 } 319 } 320 } 321 break; 322 case DTM.TEXT_NODE : 323 { 324 if (nextIsRaw) 325 { 326 nextIsRaw = false; 327 328 m_contentHandler.processingInstruction(javax.xml.transform.Result.PI_DISABLE_OUTPUT_ESCAPING, ""); 329 dispatachChars(node); 330 m_contentHandler.processingInstruction(javax.xml.transform.Result.PI_ENABLE_OUTPUT_ESCAPING, ""); 331 } 332 else 333 { 334 dispatachChars(node); 335 } 336 } 337 break; 338 case DTM.ENTITY_REFERENCE_NODE : 339 { 340 if (m_contentHandler instanceof LexicalHandler) 341 { 342 ((LexicalHandler) this.m_contentHandler).startEntity( 343 m_dtm.getNodeName(node)); 344 } 345 else 346 { 347 348 // warning("Can not output entity to a pure SAX ContentHandler"); 349 } 350 } 351 break; 352 default : 353 } 354 } 355 356 /** 357 * End processing of given node 358 * 359 * 360 * @param node Node we just finished processing 361 * 362 * @throws org.xml.sax.SAXException 363 */ 364 protected void endNode(int node) throws org.xml.sax.SAXException 365 { 366 367 switch (m_dtm.getNodeType(node)) 368 { 369 case DTM.DOCUMENT_NODE : 370 this.m_contentHandler.endDocument(); 371 break; 372 case DTM.ELEMENT_NODE : 373 String ns = m_dtm.getNamespaceURI(node); 374 if(null == ns) 375 ns = ""; 376 this.m_contentHandler.endElement(ns, 377 m_dtm.getLocalName(node), 378 m_dtm.getNodeName(node)); 379 380 for (int nsn = m_dtm.getFirstNamespaceNode(node, true); DTM.NULL != nsn; 381 nsn = m_dtm.getNextNamespaceNode(node, nsn, true)) 382 { 383 // String prefix = m_dtm.getPrefix(nsn); 384 String prefix = m_dtm.getNodeNameX(nsn); 385 386 this.m_contentHandler.endPrefixMapping(prefix); 387 } 388 break; 389 case DTM.CDATA_SECTION_NODE : 390 break; 391 case DTM.ENTITY_REFERENCE_NODE : 392 { 393 if (m_contentHandler instanceof LexicalHandler) 394 { 395 LexicalHandler lh = ((LexicalHandler) this.m_contentHandler); 396 397 lh.endEntity(m_dtm.getNodeName(node)); 398 } 399 } 400 break; 401 default : 402 } 403 } 404} //TreeWalker 405