001 /* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the "License"); 007 * you may not use this file except in compliance with the License. 008 * You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, software 013 * distributed under the License is distributed on an "AS IS" BASIS, 014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 015 * See the License for the specific language governing permissions and 016 * limitations under the License. 017 */ 018 /* 019 * $Id: MultiDOM.java 468651 2006-10-28 07:04:25Z minchau $ 020 */ 021 022 package org.apache.xalan.xsltc.dom; 023 024 import org.apache.xalan.xsltc.DOM; 025 import org.apache.xalan.xsltc.StripFilter; 026 import org.apache.xml.serializer.SerializationHandler; 027 import org.apache.xalan.xsltc.TransletException; 028 import org.apache.xalan.xsltc.runtime.BasisLibrary; 029 import org.apache.xalan.xsltc.runtime.Hashtable; 030 import org.apache.xml.dtm.DTM; 031 import org.apache.xml.dtm.Axis; 032 import org.apache.xml.dtm.DTMAxisIterator; 033 import org.apache.xml.dtm.DTMManager; 034 import org.apache.xml.dtm.ref.DTMAxisIteratorBase; 035 import org.apache.xml.dtm.ref.DTMDefaultBase; 036 import org.apache.xml.utils.SuballocatedIntVector; 037 038 import org.w3c.dom.Node; 039 import org.w3c.dom.NodeList; 040 041 /** 042 * @author Jacek Ambroziak 043 * @author Morten Jorgensen 044 * @author Erwin Bolwidt <ejb@klomp.org> 045 */ 046 public final class MultiDOM implements DOM { 047 048 private static final int NO_TYPE = DOM.FIRST_TYPE - 2; 049 private static final int INITIAL_SIZE = 4; 050 051 private DOM[] _adapters; 052 private DOMAdapter _main; 053 private DTMManager _dtmManager; 054 private int _free; 055 private int _size; 056 057 private Hashtable _documents = new Hashtable(); 058 059 private final class AxisIterator extends DTMAxisIteratorBase { 060 // constitutive data 061 private final int _axis; 062 private final int _type; 063 // implementation mechanism 064 private DTMAxisIterator _source; 065 private int _dtmId = -1; 066 067 public AxisIterator(final int axis, final int type) { 068 _axis = axis; 069 _type = type; 070 } 071 072 public int next() { 073 if (_source == null) { 074 return(END); 075 } 076 return _source.next(); 077 } 078 079 080 public void setRestartable(boolean flag) { 081 if (_source != null) { 082 _source.setRestartable(flag); 083 } 084 } 085 086 public DTMAxisIterator setStartNode(final int node) { 087 if (node == DTM.NULL) { 088 return this; 089 } 090 091 int dom = node >>> DTMManager.IDENT_DTM_NODE_BITS; 092 093 // Get a new source first time and when mask changes 094 if (_source == null || _dtmId != dom) { 095 if (_type == NO_TYPE) { 096 _source = _adapters[dom].getAxisIterator(_axis); 097 } else if (_axis == Axis.CHILD) { 098 _source = _adapters[dom].getTypedChildren(_type); 099 } else { 100 _source = _adapters[dom].getTypedAxisIterator(_axis, _type); 101 } 102 } 103 104 _dtmId = dom; 105 _source.setStartNode(node); 106 return this; 107 } 108 109 public DTMAxisIterator reset() { 110 if (_source != null) { 111 _source.reset(); 112 } 113 return this; 114 } 115 116 public int getLast() { 117 if (_source != null) { 118 return _source.getLast(); 119 } 120 else { 121 return END; 122 } 123 } 124 125 public int getPosition() { 126 if (_source != null) { 127 return _source.getPosition(); 128 } 129 else { 130 return END; 131 } 132 } 133 134 public boolean isReverse() { 135 return Axis.isReverse(_axis); 136 } 137 138 public void setMark() { 139 if (_source != null) { 140 _source.setMark(); 141 } 142 } 143 144 public void gotoMark() { 145 if (_source != null) { 146 _source.gotoMark(); 147 } 148 } 149 150 public DTMAxisIterator cloneIterator() { 151 final AxisIterator clone = new AxisIterator(_axis, _type); 152 if (_source != null) { 153 clone._source = _source.cloneIterator(); 154 } 155 clone._dtmId = _dtmId; 156 return clone; 157 } 158 } // end of AxisIterator 159 160 161 /************************************************************** 162 * This is a specialised iterator for predicates comparing node or 163 * attribute values to variable or parameter values. 164 */ 165 private final class NodeValueIterator extends DTMAxisIteratorBase { 166 167 private DTMAxisIterator _source; 168 private String _value; 169 private boolean _op; 170 private final boolean _isReverse; 171 private int _returnType = RETURN_PARENT; 172 173 public NodeValueIterator(DTMAxisIterator source, int returnType, 174 String value, boolean op) { 175 _source = source; 176 _returnType = returnType; 177 _value = value; 178 _op = op; 179 _isReverse = source.isReverse(); 180 } 181 182 public boolean isReverse() { 183 return _isReverse; 184 } 185 186 public DTMAxisIterator cloneIterator() { 187 try { 188 NodeValueIterator clone = (NodeValueIterator)super.clone(); 189 clone._source = _source.cloneIterator(); 190 clone.setRestartable(false); 191 return clone.reset(); 192 } 193 catch (CloneNotSupportedException e) { 194 BasisLibrary.runTimeError(BasisLibrary.ITERATOR_CLONE_ERR, 195 e.toString()); 196 return null; 197 } 198 } 199 200 201 public void setRestartable(boolean isRestartable) { 202 _isRestartable = isRestartable; 203 _source.setRestartable(isRestartable); 204 } 205 206 public DTMAxisIterator reset() { 207 _source.reset(); 208 return resetPosition(); 209 } 210 211 public int next() { 212 213 int node; 214 while ((node = _source.next()) != END) { 215 String val = getStringValueX(node); 216 if (_value.equals(val) == _op) { 217 if (_returnType == RETURN_CURRENT) 218 return returnNode(node); 219 else 220 return returnNode(getParent(node)); 221 } 222 } 223 return END; 224 } 225 226 public DTMAxisIterator setStartNode(int node) { 227 if (_isRestartable) { 228 _source.setStartNode(_startNode = node); 229 return resetPosition(); 230 } 231 return this; 232 } 233 234 public void setMark() { 235 _source.setMark(); 236 } 237 238 public void gotoMark() { 239 _source.gotoMark(); 240 } 241 } 242 243 public MultiDOM(DOM main) { 244 _size = INITIAL_SIZE; 245 _free = 1; 246 _adapters = new DOM[INITIAL_SIZE]; 247 DOMAdapter adapter = (DOMAdapter)main; 248 _adapters[0] = adapter; 249 _main = adapter; 250 DOM dom = adapter.getDOMImpl(); 251 if (dom instanceof DTMDefaultBase) { 252 _dtmManager = ((DTMDefaultBase)dom).getManager(); 253 } 254 255 // %HZ% %REVISIT% Is this the right thing to do here? In the old 256 // %HZ% %REVISIT% version, the main document did not get added through 257 // %HZ% %REVISIT% a call to addDOMAdapter, which meant it couldn't be 258 // %HZ% %REVISIT% found by a call to getDocumentMask. The problem is 259 // %HZ% %REVISIT% TransformerHandler is typically constructed with a 260 // %HZ% %REVISIT% system ID equal to the stylesheet's URI; with SAX 261 // %HZ% %REVISIT% input, it ends up giving that URI to the document. 262 // %HZ% %REVISIT% Then, any references to document('') are resolved 263 // %HZ% %REVISIT% using the stylesheet's URI. 264 // %HZ% %REVISIT% MultiDOM.getDocumentMask is called to verify that 265 // %HZ% %REVISIT% a document associated with that URI has not been 266 // %HZ% %REVISIT% encountered, and that method ends up returning the 267 // %HZ% %REVISIT% mask of the main document, when what we really what 268 // %HZ% %REVISIT% is to read the stylesheet itself! 269 addDOMAdapter(adapter, false); 270 } 271 272 public int nextMask() { 273 return _free; 274 } 275 276 public void setupMapping(String[] names, String[] uris, int[] types, String[] namespaces) { 277 // This method only has a function in DOM adapters 278 } 279 280 public int addDOMAdapter(DOMAdapter adapter) { 281 return addDOMAdapter(adapter, true); 282 } 283 284 private int addDOMAdapter(DOMAdapter adapter, boolean indexByURI) { 285 // Add the DOM adapter to the array of DOMs 286 DOM dom = adapter.getDOMImpl(); 287 288 int domNo = 1; 289 int dtmSize = 1; 290 SuballocatedIntVector dtmIds = null; 291 if (dom instanceof DTMDefaultBase) { 292 DTMDefaultBase dtmdb = (DTMDefaultBase)dom; 293 dtmIds = dtmdb.getDTMIDs(); 294 dtmSize = dtmIds.size(); 295 domNo = dtmIds.elementAt(dtmSize-1) >>> DTMManager.IDENT_DTM_NODE_BITS; 296 } 297 else if (dom instanceof SimpleResultTreeImpl) { 298 SimpleResultTreeImpl simpleRTF = (SimpleResultTreeImpl)dom; 299 domNo = simpleRTF.getDocument() >>> DTMManager.IDENT_DTM_NODE_BITS; 300 } 301 302 if (domNo >= _size) { 303 int oldSize = _size; 304 do { 305 _size *= 2; 306 } while (_size <= domNo); 307 308 final DOMAdapter[] newArray = new DOMAdapter[_size]; 309 System.arraycopy(_adapters, 0, newArray, 0, oldSize); 310 _adapters = newArray; 311 } 312 313 _free = domNo + 1; 314 315 if (dtmSize == 1) { 316 _adapters[domNo] = adapter; 317 } 318 else if (dtmIds != null) { 319 int domPos = 0; 320 for (int i = dtmSize - 1; i >= 0; i--) { 321 domPos = dtmIds.elementAt(i) >>> DTMManager.IDENT_DTM_NODE_BITS; 322 _adapters[domPos] = adapter; 323 } 324 domNo = domPos; 325 } 326 327 // Store reference to document (URI) in hashtable 328 if (indexByURI) { 329 String uri = adapter.getDocumentURI(0); 330 _documents.put(uri, new Integer(domNo)); 331 } 332 333 // If the dom is an AdaptiveResultTreeImpl, we need to create a 334 // DOMAdapter around its nested dom object (if it is non-null) and 335 // add the DOMAdapter to the list. 336 if (dom instanceof AdaptiveResultTreeImpl) { 337 AdaptiveResultTreeImpl adaptiveRTF = (AdaptiveResultTreeImpl)dom; 338 DOM nestedDom = adaptiveRTF.getNestedDOM(); 339 if (nestedDom != null) { 340 DOMAdapter newAdapter = new DOMAdapter(nestedDom, 341 adapter.getNamesArray(), 342 adapter.getUrisArray(), 343 adapter.getTypesArray(), 344 adapter.getNamespaceArray()); 345 addDOMAdapter(newAdapter); 346 } 347 } 348 349 return domNo; 350 } 351 352 public int getDocumentMask(String uri) { 353 Integer domIdx = (Integer)_documents.get(uri); 354 if (domIdx == null) { 355 return(-1); 356 } else { 357 return domIdx.intValue(); 358 } 359 } 360 361 public DOM getDOMAdapter(String uri) { 362 Integer domIdx = (Integer)_documents.get(uri); 363 if (domIdx == null) { 364 return(null); 365 } else { 366 return(_adapters[domIdx.intValue()]); 367 } 368 } 369 370 public int getDocument() 371 { 372 return _main.getDocument(); 373 } 374 375 public DTMManager getDTMManager() { 376 return _dtmManager; 377 } 378 379 /** 380 * Returns singleton iterator containing the document root 381 */ 382 public DTMAxisIterator getIterator() { 383 // main source document @ 0 384 return _main.getIterator(); 385 } 386 387 public String getStringValue() { 388 return _main.getStringValue(); 389 } 390 391 public DTMAxisIterator getChildren(final int node) { 392 return _adapters[getDTMId(node)].getChildren(node); 393 } 394 395 public DTMAxisIterator getTypedChildren(final int type) { 396 return new AxisIterator(Axis.CHILD, type); 397 } 398 399 public DTMAxisIterator getAxisIterator(final int axis) { 400 return new AxisIterator(axis, NO_TYPE); 401 } 402 403 public DTMAxisIterator getTypedAxisIterator(final int axis, final int type) 404 { 405 return new AxisIterator(axis, type); 406 } 407 408 public DTMAxisIterator getNthDescendant(int node, int n, 409 boolean includeself) 410 { 411 return _adapters[getDTMId(node)].getNthDescendant(node, n, includeself); 412 } 413 414 public DTMAxisIterator getNodeValueIterator(DTMAxisIterator iterator, 415 int type, String value, 416 boolean op) 417 { 418 return(new NodeValueIterator(iterator, type, value, op)); 419 } 420 421 public DTMAxisIterator getNamespaceAxisIterator(final int axis, 422 final int ns) 423 { 424 DTMAxisIterator iterator = _main.getNamespaceAxisIterator(axis, ns); 425 return(iterator); 426 } 427 428 public DTMAxisIterator orderNodes(DTMAxisIterator source, int node) { 429 return _adapters[getDTMId(node)].orderNodes(source, node); 430 } 431 432 public int getExpandedTypeID(final int node) { 433 if (node != DTM.NULL) { 434 return _adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].getExpandedTypeID(node); 435 } 436 else { 437 return DTM.NULL; 438 } 439 } 440 441 public int getNamespaceType(final int node) { 442 return _adapters[getDTMId(node)].getNamespaceType(node); 443 } 444 445 public int getNSType(int node) 446 { 447 return _adapters[getDTMId(node)].getNSType(node); 448 } 449 450 public int getParent(final int node) { 451 if (node == DTM.NULL) { 452 return DTM.NULL; 453 } 454 return _adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].getParent(node); 455 } 456 457 public int getAttributeNode(final int type, final int el) { 458 if (el == DTM.NULL) { 459 return DTM.NULL; 460 } 461 return _adapters[el >>> DTMManager.IDENT_DTM_NODE_BITS].getAttributeNode(type, el); 462 } 463 464 public String getNodeName(final int node) { 465 if (node == DTM.NULL) { 466 return ""; 467 } 468 return _adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].getNodeName(node); 469 } 470 471 public String getNodeNameX(final int node) { 472 if (node == DTM.NULL) { 473 return ""; 474 } 475 return _adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].getNodeNameX(node); 476 } 477 478 public String getNamespaceName(final int node) { 479 if (node == DTM.NULL) { 480 return ""; 481 } 482 return _adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].getNamespaceName(node); 483 } 484 485 public String getStringValueX(final int node) { 486 if (node == DTM.NULL) { 487 return ""; 488 } 489 return _adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].getStringValueX(node); 490 } 491 492 public void copy(final int node, SerializationHandler handler) 493 throws TransletException 494 { 495 if (node != DTM.NULL) { 496 _adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].copy(node, handler); 497 } 498 } 499 500 public void copy(DTMAxisIterator nodes, SerializationHandler handler) 501 throws TransletException 502 { 503 int node; 504 while ((node = nodes.next()) != DTM.NULL) { 505 _adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].copy(node, handler); 506 } 507 } 508 509 510 public String shallowCopy(final int node, SerializationHandler handler) 511 throws TransletException 512 { 513 if (node == DTM.NULL) { 514 return ""; 515 } 516 return _adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].shallowCopy(node, handler); 517 } 518 519 public boolean lessThan(final int node1, final int node2) { 520 if (node1 == DTM.NULL) { 521 return true; 522 } 523 if (node2 == DTM.NULL) { 524 return false; 525 } 526 final int dom1 = getDTMId(node1); 527 final int dom2 = getDTMId(node2); 528 return dom1 == dom2 ? _adapters[dom1].lessThan(node1, node2) 529 : dom1 < dom2; 530 } 531 532 public void characters(final int textNode, SerializationHandler handler) 533 throws TransletException 534 { 535 if (textNode != DTM.NULL) { 536 _adapters[textNode >>> DTMManager.IDENT_DTM_NODE_BITS].characters(textNode, handler); 537 } 538 } 539 540 public void setFilter(StripFilter filter) { 541 for (int dom=0; dom<_free; dom++) { 542 if (_adapters[dom] != null) { 543 _adapters[dom].setFilter(filter); 544 } 545 } 546 } 547 548 public Node makeNode(int index) { 549 if (index == DTM.NULL) { 550 return null; 551 } 552 return _adapters[getDTMId(index)].makeNode(index); 553 } 554 555 public Node makeNode(DTMAxisIterator iter) { 556 // TODO: gather nodes from all DOMs ? 557 return _main.makeNode(iter); 558 } 559 560 public NodeList makeNodeList(int index) { 561 if (index == DTM.NULL) { 562 return null; 563 } 564 return _adapters[getDTMId(index)].makeNodeList(index); 565 } 566 567 public NodeList makeNodeList(DTMAxisIterator iter) { 568 // TODO: gather nodes from all DOMs ? 569 return _main.makeNodeList(iter); 570 } 571 572 public String getLanguage(int node) { 573 return _adapters[getDTMId(node)].getLanguage(node); 574 } 575 576 public int getSize() { 577 int size = 0; 578 for (int i=0; i<_size; i++) { 579 size += _adapters[i].getSize(); 580 } 581 return(size); 582 } 583 584 public String getDocumentURI(int node) { 585 if (node == DTM.NULL) { 586 node = DOM.NULL; 587 } 588 return _adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].getDocumentURI(0); 589 } 590 591 public boolean isElement(final int node) { 592 if (node == DTM.NULL) { 593 return false; 594 } 595 return(_adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].isElement(node)); 596 } 597 598 public boolean isAttribute(final int node) { 599 if (node == DTM.NULL) { 600 return false; 601 } 602 return(_adapters[node >>> DTMManager.IDENT_DTM_NODE_BITS].isAttribute(node)); 603 } 604 605 public int getDTMId(int nodeHandle) 606 { 607 if (nodeHandle == DTM.NULL) 608 return 0; 609 610 int id = nodeHandle >>> DTMManager.IDENT_DTM_NODE_BITS; 611 while (id >= 2 && _adapters[id] == _adapters[id-1]) { 612 id--; 613 } 614 return id; 615 } 616 617 public int getNodeIdent(int nodeHandle) 618 { 619 return _adapters[nodeHandle >>> DTMManager.IDENT_DTM_NODE_BITS].getNodeIdent(nodeHandle); 620 } 621 622 public int getNodeHandle(int nodeId) 623 { 624 return _main.getNodeHandle(nodeId); 625 } 626 627 public DOM getResultTreeFrag(int initSize, int rtfType) 628 { 629 return _main.getResultTreeFrag(initSize, rtfType); 630 } 631 632 public DOM getResultTreeFrag(int initSize, int rtfType, boolean addToManager) 633 { 634 return _main.getResultTreeFrag(initSize, rtfType, addToManager); 635 } 636 637 public DOM getMain() 638 { 639 return _main; 640 } 641 642 /** 643 * Returns a DOMBuilder class wrapped in a SAX adapter. 644 */ 645 public SerializationHandler getOutputDomBuilder() 646 { 647 return _main.getOutputDomBuilder(); 648 } 649 650 public String lookupNamespace(int node, String prefix) 651 throws TransletException 652 { 653 return _main.lookupNamespace(node, prefix); 654 } 655 656 // %HZ% Does this method make any sense here??? 657 public String getUnparsedEntityURI(String entity) { 658 return _main.getUnparsedEntityURI(entity); 659 } 660 661 // %HZ% Does this method make any sense here??? 662 public Hashtable getElementsWithIDs() { 663 return _main.getElementsWithIDs(); 664 } 665 }