1 /* 2 * Copyright (c) 2015, 2016, 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.dom; 22 23 import com.sun.org.apache.xalan.internal.xsltc.DOM; 24 import com.sun.org.apache.xalan.internal.xsltc.DOMEnhancedForDTM; 25 import com.sun.org.apache.xalan.internal.xsltc.StripFilter; 26 import com.sun.org.apache.xalan.internal.xsltc.TransletException; 27 import com.sun.org.apache.xalan.internal.xsltc.runtime.BasisLibrary; 28 import com.sun.org.apache.xml.internal.dtm.Axis; 29 import com.sun.org.apache.xml.internal.dtm.DTM; 30 import com.sun.org.apache.xml.internal.dtm.DTMAxisIterator; 31 import com.sun.org.apache.xml.internal.dtm.DTMManager; 32 import com.sun.org.apache.xml.internal.dtm.DTMWSFilter; 33 import com.sun.org.apache.xml.internal.dtm.ref.DTMAxisIterNodeList; 34 import com.sun.org.apache.xml.internal.dtm.ref.DTMDefaultBase; 35 import com.sun.org.apache.xml.internal.dtm.ref.DTMNodeProxy; 36 import com.sun.org.apache.xml.internal.dtm.ref.EmptyIterator; 37 import com.sun.org.apache.xml.internal.dtm.ref.sax2dtm.SAX2DTM2; 38 import com.sun.org.apache.xml.internal.serializer.SerializationHandler; 39 import com.sun.org.apache.xml.internal.serializer.ToXMLSAXHandler; 40 import com.sun.org.apache.xml.internal.utils.SystemIDResolver; 41 import com.sun.org.apache.xml.internal.utils.XMLStringFactory; 42 import java.util.HashMap; 43 import java.util.Map; 44 import javax.xml.transform.Source; 45 import javax.xml.transform.dom.DOMSource; 46 import org.w3c.dom.Document; 47 import org.w3c.dom.DocumentType; 48 import org.w3c.dom.Entity; 49 import org.w3c.dom.NamedNodeMap; 50 import org.w3c.dom.Node; 51 import org.w3c.dom.NodeList; 52 import org.xml.sax.Attributes; 53 import org.xml.sax.SAXException; 54 55 56 /** 57 * SAXImpl is the core model for SAX input source. SAXImpl objects are 58 * usually created from an XSLTCDTMManager. 59 * 60 * <p>DOMSource inputs are handled using DOM2SAX + SAXImpl. SAXImpl has a 61 * few specific fields (e.g. _node2Ids, _document) to keep DOM-related 62 * information. They are used when the processing behavior between DOM and 63 * SAX has to be different. Examples of these include id function and 64 * unparsed entity. 65 * 66 * <p>SAXImpl extends SAX2DTM2 instead of SAX2DTM for better performance. 67 * @author Jacek Ambroziak 68 * @author Santiago Pericas-Geertsen 69 * @author Morten Jorgensen 70 * @author Douglas Sellers <douglasjsellers@hotmail.com> 71 */ 72 public final class SAXImpl extends SAX2DTM2 73 implements DOMEnhancedForDTM, DOMBuilder 74 { 75 76 /* ------------------------------------------------------------------- */ 77 /* DOMBuilder fields BEGIN */ 78 /* ------------------------------------------------------------------- */ 79 80 // Namespace prefix-to-uri mapping stuff 81 private int _uriCount = 0; 82 // private int _prefixCount = 0; 83 84 // Stack used to keep track of what whitespace text nodes are protected 85 // by xml:space="preserve" attributes and which nodes that are not. 86 private int[] _xmlSpaceStack; 87 private int _idx = 1; 88 private boolean _preserve = false; 89 90 // private static final String XML_STRING = "xml:"; 91 private static final String XML_PREFIX = "xml"; 92 private static final String XMLSPACE_STRING = "xml:space"; 93 private static final String PRESERVE_STRING = "preserve"; 94 // private static final String XMLNS_PREFIX = "xmlns"; 95 private static final String XML_URI = "http://www.w3.org/XML/1998/namespace"; 96 97 private boolean _escaping = true; 98 private boolean _disableEscaping = false; 99 private int _textNodeToProcess = DTM.NULL; 100 101 /* ------------------------------------------------------------------- */ 102 /* DOMBuilder fields END */ 103 /* ------------------------------------------------------------------- */ 104 105 // empty String for null attribute values 106 private final static String EMPTYSTRING = ""; 107 108 // empty iterator to be returned when there are no children 109 private final static DTMAxisIterator EMPTYITERATOR = EmptyIterator.getInstance(); 110 // The number of expanded names 111 private int _namesSize = -1; 112 113 // Namespace related stuff 114 private Map<Integer, Integer> _nsIndex = new HashMap<>(); 115 116 // The initial size of the text buffer 117 private int _size = 0; 118 119 // Tracks which textnodes are not escaped 120 private BitArray _dontEscape = null; 121 122 // The URI to this document 123 // private String _documentURI = null; 124 static private int _documentURIIndex = 0; 125 126 // The owner Document when the input source is DOMSource. 127 private Document _document; 128 129 // The Map for org.w3c.dom.Node to node id mapping. 130 // This is only used when the input is a DOMSource and the 131 // buildIdIndex flag is true. 132 private Map<Node, Integer> _node2Ids = null; 133 134 // True if the input source is a DOMSource. 135 private boolean _hasDOMSource = false; 136 137 // The DTMManager 138 private XSLTCDTMManager _dtmManager; 139 140 // Support for access/navigation through org.w3c.dom API 141 private Node[] _nodes; 142 private NodeList[] _nodeLists; 143 // private final static String XML_LANG_ATTRIBUTE = "http://www.w3.org/XML/1998/namespace:@lang"; 144 145 /** 146 * Define the origin of the document from which the tree was built 147 */ 148 public void setDocumentURI(String uri) { 149 if (uri != null) { 150 setDocumentBaseURI(SystemIDResolver.getAbsoluteURI(uri)); 151 } 152 } 153 154 /** 155 * Returns the origin of the document from which the tree was built 156 */ 157 public String getDocumentURI() { 158 String baseURI = getDocumentBaseURI(); 159 return (baseURI != null) ? baseURI : "rtf" + _documentURIIndex++; 160 } 161 162 public String getDocumentURI(int node) { 163 return getDocumentURI(); 164 } 165 166 public void setupMapping(String[] names, String[] urisArray, 167 int[] typesArray, String[] namespaces) { 168 // This method only has a function in DOM adapters 169 } 170 171 /** 172 * Lookup a namespace URI from a prefix starting at node. This method 173 * is used in the execution of xsl:element when the prefix is not known 174 * at compile time. 175 */ 176 public String lookupNamespace(int node, String prefix) 177 throws TransletException 178 { 179 int anode, nsnode; 180 final AncestorIterator ancestors = new AncestorIterator(); 181 182 if (isElement(node)) { 183 ancestors.includeSelf(); 184 } 185 186 ancestors.setStartNode(node); 187 while ((anode = ancestors.next()) != DTM.NULL) { 188 final NamespaceIterator namespaces = new NamespaceIterator(); 189 190 namespaces.setStartNode(anode); 191 while ((nsnode = namespaces.next()) != DTM.NULL) { 192 if (getLocalName(nsnode).equals(prefix)) { 193 return getNodeValue(nsnode); 194 } 195 } 196 } 197 198 BasisLibrary.runTimeError(BasisLibrary.NAMESPACE_PREFIX_ERR, prefix); 199 return null; 200 } 201 202 /** 203 * Returns 'true' if a specific node is an element (of any type) 204 */ 205 public boolean isElement(final int node) { 206 return getNodeType(node) == DTM.ELEMENT_NODE; 207 } 208 209 /** 210 * Returns 'true' if a specific node is an attribute (of any type) 211 */ 212 public boolean isAttribute(final int node) { 213 return getNodeType(node) == DTM.ATTRIBUTE_NODE; 214 } 215 216 /** 217 * Returns the number of nodes in the tree (used for indexing) 218 */ 219 public int getSize() { 220 return getNumberOfNodes(); 221 } 222 223 /** 224 * Part of the DOM interface - no function here. 225 */ 226 public void setFilter(StripFilter filter) { 227 } 228 229 230 /** 231 * Returns true if node1 comes before node2 in document order 232 */ 233 public boolean lessThan(int node1, int node2) { 234 if (node1 == DTM.NULL) { 235 return false; 236 } 237 238 if (node2 == DTM.NULL) { 239 return true; 240 } 241 242 return (node1 < node2); 243 } 244 245 /** 246 * Create an org.w3c.dom.Node from a node in the tree 247 */ 248 public Node makeNode(int index) { 249 if (_nodes == null) { 250 _nodes = new Node[_namesSize]; 251 } 252 253 int nodeID = makeNodeIdentity(index); 254 if (nodeID < 0) { 255 return null; 256 } 257 else if (nodeID < _nodes.length) { 258 return (_nodes[nodeID] != null) ? _nodes[nodeID] 259 : (_nodes[nodeID] = new DTMNodeProxy((DTM)this, index)); 260 } 261 else { 262 return new DTMNodeProxy((DTM)this, index); 263 } 264 } 265 266 /** 267 * Create an org.w3c.dom.Node from a node in an iterator 268 * The iterator most be started before this method is called 269 */ 270 public Node makeNode(DTMAxisIterator iter) { 271 return makeNode(iter.next()); 272 } 273 274 /** 275 * Create an org.w3c.dom.NodeList from a node in the tree 276 */ 277 public NodeList makeNodeList(int index) { 278 if (_nodeLists == null) { 279 _nodeLists = new NodeList[_namesSize]; 280 } 281 282 int nodeID = makeNodeIdentity(index); 283 if (nodeID < 0) { 284 return null; 285 } 286 else if (nodeID < _nodeLists.length) { 287 return (_nodeLists[nodeID] != null) ? _nodeLists[nodeID] 288 : (_nodeLists[nodeID] = new DTMAxisIterNodeList(this, 289 new SingletonIterator(index))); 290 } 291 else { 292 return new DTMAxisIterNodeList(this, new SingletonIterator(index)); 293 } 294 } 295 296 /** 297 * Create an org.w3c.dom.NodeList from a node iterator 298 * The iterator most be started before this method is called 299 */ 300 public NodeList makeNodeList(DTMAxisIterator iter) { 301 return new DTMAxisIterNodeList(this, iter); 302 } 303 304 /** 305 * Iterator that returns the namespace nodes as defined by the XPath data 306 * model for a given node, filtered by extended type ID. 307 */ 308 public class TypedNamespaceIterator extends NamespaceIterator { 309 310 private String _nsPrefix; 311 312 /** 313 * Constructor TypedChildrenIterator 314 * 315 * 316 * @param nodeType The extended type ID being requested. 317 */ 318 public TypedNamespaceIterator(int nodeType) { 319 super(); 320 if(m_expandedNameTable != null){ 321 _nsPrefix = m_expandedNameTable.getLocalName(nodeType); 322 } 323 } 324 325 /** 326 * Get the next node in the iteration. 327 * 328 * @return The next node handle in the iteration, or END. 329 */ 330 public int next() { 331 if ((_nsPrefix == null) ||(_nsPrefix.length() == 0) ){ 332 return (END); 333 } 334 int node = END; 335 for (node = super.next(); node != END; node = super.next()) { 336 if (_nsPrefix.compareTo(getLocalName(node))== 0) { 337 return returnNode(node); 338 } 339 } 340 return (END); 341 } 342 } // end of TypedNamespaceIterator 343 344 345 346 /************************************************************** 347 * This is a specialised iterator for predicates comparing node or 348 * attribute values to variable or parameter values. 349 */ 350 private final class NodeValueIterator extends InternalAxisIteratorBase 351 { 352 353 private DTMAxisIterator _source; 354 private String _value; 355 private boolean _op; 356 private final boolean _isReverse; 357 private int _returnType = RETURN_PARENT; 358 359 public NodeValueIterator(DTMAxisIterator source, int returnType, 360 String value, boolean op) 361 { 362 _source = source; 363 _returnType = returnType; 364 _value = value; 365 _op = op; 366 _isReverse = source.isReverse(); 367 } 368 369 public boolean isReverse() 370 { 371 return _isReverse; 372 } 373 374 public DTMAxisIterator cloneIterator() 375 { 376 try { 377 NodeValueIterator clone = (NodeValueIterator)super.clone(); 378 clone._isRestartable = false; 379 clone._source = _source.cloneIterator(); 380 clone._value = _value; 381 clone._op = _op; 382 return clone.reset(); 383 } 384 catch (CloneNotSupportedException e) { 385 BasisLibrary.runTimeError(BasisLibrary.ITERATOR_CLONE_ERR, 386 e.toString()); 387 return null; 388 } 389 } 390 391 public void setRestartable(boolean isRestartable) 392 { 393 _isRestartable = isRestartable; 394 _source.setRestartable(isRestartable); 395 } 396 397 public DTMAxisIterator reset() 398 { 399 _source.reset(); 400 return resetPosition(); 401 } 402 403 public int next() 404 { 405 int node; 406 while ((node = _source.next()) != END) { 407 String val = getStringValueX(node); 408 if (_value.equals(val) == _op) { 409 if (_returnType == RETURN_CURRENT) { 410 return returnNode(node); 411 } 412 else { 413 return returnNode(getParent(node)); 414 } 415 } 416 } 417 return END; 418 } 419 420 public DTMAxisIterator setStartNode(int node) 421 { 422 if (_isRestartable) { 423 _source.setStartNode(_startNode = node); 424 return resetPosition(); 425 } 426 return this; 427 } 428 429 public void setMark() 430 { 431 _source.setMark(); 432 } 433 434 public void gotoMark() 435 { 436 _source.gotoMark(); 437 } 438 } // end NodeValueIterator 439 440 public DTMAxisIterator getNodeValueIterator(DTMAxisIterator iterator, int type, 441 String value, boolean op) 442 { 443 return(DTMAxisIterator)(new NodeValueIterator(iterator, type, value, op)); 444 } 445 446 /** 447 * Encapsulates an iterator in an OrderedIterator to ensure node order 448 */ 449 public DTMAxisIterator orderNodes(DTMAxisIterator source, int node) 450 { 451 return new DupFilterIterator(source); 452 } 453 454 /** 455 * Returns singleton iterator containg the document root 456 * Works for them main document (mark == 0). It cannot be made 457 * to point to any other node through setStartNode(). 458 */ 459 public DTMAxisIterator getIterator() 460 { 461 return new SingletonIterator(getDocument(), true); 462 } 463 464 /** 465 * Get mapping from DOM namespace types to external namespace types 466 */ 467 public int getNSType(int node) 468 { 469 String s = getNamespaceURI(node); 470 if (s == null) { 471 return 0; 472 } 473 int eType = getIdForNamespace(s); 474 return _nsIndex.get(new Integer(eType)); 475 } 476 477 478 479 /** 480 * Returns the namespace type of a specific node 481 */ 482 public int getNamespaceType(final int node) 483 { 484 return super.getNamespaceType(node); 485 } 486 487 /** 488 * Sets up a translet-to-dom type mapping table 489 */ 490 /* 491 private int[] setupMapping(String[] names, String[] uris, int[] types, int nNames) { 492 // Padding with number of names, because they 493 // may need to be added, i.e for RTFs. See copy03 494 final int[] result = new int[m_expandedNameTable.getSize()]; 495 for (int i = 0; i < nNames; i++) { 496 //int type = getGeneralizedType(namesArray[i]); 497 int type = m_expandedNameTable.getExpandedTypeID(uris[i], names[i], types[i], false); 498 result[type] = type; 499 } 500 return result; 501 } 502 */ 503 504 /** 505 * Returns the internal type associated with an expanded QName 506 */ 507 public int getGeneralizedType(final String name) { 508 return getGeneralizedType(name, true); 509 } 510 511 /** 512 * Returns the internal type associated with an expanded QName 513 */ 514 public int getGeneralizedType(final String name, boolean searchOnly) { 515 String lName, ns = null; 516 int index = -1; 517 int code; 518 519 // Is there a prefix? 520 if ((index = name.lastIndexOf(":"))> -1) { 521 ns = name.substring(0, index); 522 } 523 524 // Local part of name is after colon. lastIndexOf returns -1 if 525 // there is no colon, so lNameStartIdx will be zero in that case. 526 int lNameStartIdx = index+1; 527 528 // Distinguish attribute and element names. Attribute has @ before 529 // local part of name. 530 if (name.charAt(lNameStartIdx) == '@') { 531 code = DTM.ATTRIBUTE_NODE; 532 lNameStartIdx++; 533 } 534 else { 535 code = DTM.ELEMENT_NODE; 536 } 537 538 // Extract local name 539 lName = (lNameStartIdx == 0) ? name : name.substring(lNameStartIdx); 540 541 return m_expandedNameTable.getExpandedTypeID(ns, lName, code, searchOnly); 542 } 543 544 /** 545 * Get mapping from DOM element/attribute types to external types 546 */ 547 public short[] getMapping(String[] names, String[] uris, int[] types) 548 { 549 // Delegate the work to getMapping2 if the document is not fully built. 550 // Some of the processing has to be different in this case. 551 if (_namesSize < 0) { 552 return getMapping2(names, uris, types); 553 } 554 555 int i; 556 final int namesLength = names.length; 557 final int exLength = m_expandedNameTable.getSize(); 558 559 final short[] result = new short[exLength]; 560 561 // primitive types map to themselves 562 for (i = 0; i < DTM.NTYPES; i++) { 563 result[i] = (short)i; 564 } 565 566 for (i = NTYPES; i < exLength; i++) { 567 result[i] = m_expandedNameTable.getType(i); 568 } 569 570 // actual mapping of caller requested names 571 for (i = 0; i < namesLength; i++) { 572 int genType = m_expandedNameTable.getExpandedTypeID(uris[i], 573 names[i], 574 types[i], 575 true); 576 if (genType >= 0 && genType < exLength) { 577 result[genType] = (short)(i + DTM.NTYPES); 578 } 579 } 580 581 return result; 582 } 583 584 /** 585 * Get mapping from external element/attribute types to DOM types 586 */ 587 public int[] getReverseMapping(String[] names, String[] uris, int[] types) 588 { 589 int i; 590 final int[] result = new int[names.length + DTM.NTYPES]; 591 592 // primitive types map to themselves 593 for (i = 0; i < DTM.NTYPES; i++) { 594 result[i] = i; 595 } 596 597 // caller's types map into appropriate dom types 598 for (i = 0; i < names.length; i++) { 599 int type = m_expandedNameTable.getExpandedTypeID(uris[i], names[i], types[i], true); 600 result[i+DTM.NTYPES] = type; 601 } 602 return(result); 603 } 604 605 /** 606 * Get mapping from DOM element/attribute types to external types. 607 * This method is used when the document is not fully built. 608 */ 609 private short[] getMapping2(String[] names, String[] uris, int[] types) 610 { 611 int i; 612 final int namesLength = names.length; 613 final int exLength = m_expandedNameTable.getSize(); 614 int[] generalizedTypes = null; 615 if (namesLength > 0) { 616 generalizedTypes = new int[namesLength]; 617 } 618 619 int resultLength = exLength; 620 621 for (i = 0; i < namesLength; i++) { 622 // When the document is not fully built, the searchOnly 623 // flag should be set to false. That means we should add 624 // the type if it is not already in the expanded name table. 625 //generalizedTypes[i] = getGeneralizedType(names[i], false); 626 generalizedTypes[i] = 627 m_expandedNameTable.getExpandedTypeID(uris[i], 628 names[i], 629 types[i], 630 false); 631 if (_namesSize < 0 && generalizedTypes[i] >= resultLength) { 632 resultLength = generalizedTypes[i] + 1; 633 } 634 } 635 636 final short[] result = new short[resultLength]; 637 638 // primitive types map to themselves 639 for (i = 0; i < DTM.NTYPES; i++) { 640 result[i] = (short)i; 641 } 642 643 for (i = NTYPES; i < exLength; i++) { 644 result[i] = m_expandedNameTable.getType(i); 645 } 646 647 // actual mapping of caller requested names 648 for (i = 0; i < namesLength; i++) { 649 int genType = generalizedTypes[i]; 650 if (genType >= 0 && genType < resultLength) { 651 result[genType] = (short)(i + DTM.NTYPES); 652 } 653 } 654 655 return(result); 656 } 657 /** 658 * Get mapping from DOM namespace types to external namespace types 659 */ 660 public short[] getNamespaceMapping(String[] namespaces) 661 { 662 int i; 663 final int nsLength = namespaces.length; 664 final int mappingLength = _uriCount; 665 666 final short[] result = new short[mappingLength]; 667 668 // Initialize all entries to -1 669 for (i=0; i<mappingLength; i++) { 670 result[i] = (short)(-1); 671 } 672 673 for (i=0; i<nsLength; i++) { 674 int eType = getIdForNamespace(namespaces[i]); 675 Integer type = _nsIndex.get(new Integer(eType)); 676 if (type != null) { 677 result[type] = (short)i; 678 } 679 } 680 681 return(result); 682 } 683 684 /** 685 * Get mapping from external namespace types to DOM namespace types 686 */ 687 public short[] getReverseNamespaceMapping(String[] namespaces) 688 { 689 int i; 690 final int length = namespaces.length; 691 final short[] result = new short[length]; 692 693 for (i = 0; i < length; i++) { 694 int eType = getIdForNamespace(namespaces[i]); 695 Integer type = _nsIndex.get(new Integer(eType)); 696 result[i] = (type == null) ? -1 : type.shortValue(); 697 } 698 699 return result; 700 } 701 702 /** 703 * Construct a SAXImpl object using the default block size. 704 */ 705 public SAXImpl(XSLTCDTMManager mgr, Source source, 706 int dtmIdentity, DTMWSFilter whiteSpaceFilter, 707 XMLStringFactory xstringfactory, 708 boolean doIndexing, boolean buildIdIndex) 709 { 710 this(mgr, source, dtmIdentity, whiteSpaceFilter, xstringfactory, 711 doIndexing, DEFAULT_BLOCKSIZE, buildIdIndex, false); 712 } 713 714 /** 715 * Construct a SAXImpl object using the given block size. 716 */ 717 public SAXImpl(XSLTCDTMManager mgr, Source source, 718 int dtmIdentity, DTMWSFilter whiteSpaceFilter, 719 XMLStringFactory xstringfactory, 720 boolean doIndexing, int blocksize, 721 boolean buildIdIndex, 722 boolean newNameTable) 723 { 724 super(mgr, source, dtmIdentity, whiteSpaceFilter, xstringfactory, 725 doIndexing, blocksize, false, buildIdIndex, newNameTable); 726 727 _dtmManager = mgr; 728 _size = blocksize; 729 730 // Use a smaller size for the space stack if the blocksize is small 731 _xmlSpaceStack = new int[blocksize <= 64 ? 4 : 64]; 732 733 /* From DOMBuilder */ 734 _xmlSpaceStack[0] = DTMDefaultBase.ROOTNODE; 735 736 // If the input source is DOMSource, set the _document field and 737 // create the node2Ids table. 738 if (source instanceof DOMSource) { 739 _hasDOMSource = true; 740 DOMSource domsrc = (DOMSource)source; 741 Node node = domsrc.getNode(); 742 if (node instanceof Document) { 743 _document = (Document)node; 744 } 745 else { 746 _document = node.getOwnerDocument(); 747 } 748 _node2Ids = new HashMap<>(); 749 } 750 } 751 752 /** 753 * Migrate a DTM built with an old DTMManager to a new DTMManager. 754 * After the migration, the new DTMManager will treat the DTM as 755 * one that is built by itself. 756 * This is used to support DTM sharing between multiple transformations. 757 * @param manager the DTMManager 758 */ 759 public void migrateTo(DTMManager manager) { 760 super.migrateTo(manager); 761 if (manager instanceof XSLTCDTMManager) { 762 _dtmManager = (XSLTCDTMManager)manager; 763 } 764 } 765 766 /** 767 * Return the node identity for a given id String 768 * 769 * @param idString The id String 770 * @return The identity of the node whose id is the given String. 771 */ 772 public int getElementById(String idString) 773 { 774 Node node = _document.getElementById(idString); 775 if (node != null) { 776 Integer id = _node2Ids.get(node); 777 return (id != null) ? id : DTM.NULL; 778 } 779 else { 780 return DTM.NULL; 781 } 782 } 783 784 /** 785 * Return true if the input source is DOMSource. 786 */ 787 public boolean hasDOMSource() 788 { 789 return _hasDOMSource; 790 } 791 792 /*---------------------------------------------------------------------------*/ 793 /* DOMBuilder methods begin */ 794 /*---------------------------------------------------------------------------*/ 795 796 /** 797 * Call this when an xml:space attribute is encountered to 798 * define the whitespace strip/preserve settings. 799 */ 800 private void xmlSpaceDefine(String val, final int node) 801 { 802 final boolean setting = val.equals(PRESERVE_STRING); 803 if (setting != _preserve) { 804 _xmlSpaceStack[_idx++] = node; 805 _preserve = setting; 806 } 807 } 808 809 /** 810 * Call this from endElement() to revert strip/preserve setting 811 * to whatever it was before the corresponding startElement(). 812 */ 813 private void xmlSpaceRevert(final int node) 814 { 815 if (node == _xmlSpaceStack[_idx - 1]) { 816 _idx--; 817 _preserve = !_preserve; 818 } 819 } 820 821 /** 822 * Find out whether or not to strip whitespace nodes. 823 * 824 * 825 * @return whether or not to strip whitespace nodes. 826 */ 827 protected boolean getShouldStripWhitespace() 828 { 829 return _preserve ? false : super.getShouldStripWhitespace(); 830 } 831 832 /** 833 * Creates a text-node and checks if it is a whitespace node. 834 */ 835 private void handleTextEscaping() { 836 if (_disableEscaping && _textNodeToProcess != DTM.NULL 837 && _type(_textNodeToProcess) == DTM.TEXT_NODE) { 838 if (_dontEscape == null) { 839 _dontEscape = new BitArray(_size); 840 } 841 842 // Resize the _dontEscape BitArray if necessary. 843 if (_textNodeToProcess >= _dontEscape.size()) { 844 _dontEscape.resize(_dontEscape.size() * 2); 845 } 846 847 _dontEscape.setBit(_textNodeToProcess); 848 _disableEscaping = false; 849 } 850 _textNodeToProcess = DTM.NULL; 851 } 852 853 854 /****************************************************************/ 855 /* SAX Interface Starts Here */ 856 /****************************************************************/ 857 858 /** 859 * SAX2: Receive notification of character data. 860 */ 861 public void characters(char[] ch, int start, int length) throws SAXException 862 { 863 super.characters(ch, start, length); 864 865 _disableEscaping = !_escaping; 866 _textNodeToProcess = getNumberOfNodes(); 867 } 868 869 /** 870 * SAX2: Receive notification of the beginning of a document. 871 */ 872 public void startDocument() throws SAXException 873 { 874 super.startDocument(); 875 876 _nsIndex.put(0, _uriCount++); 877 definePrefixAndUri(XML_PREFIX, XML_URI); 878 } 879 880 /** 881 * SAX2: Receive notification of the end of a document. 882 */ 883 public void endDocument() throws SAXException 884 { 885 super.endDocument(); 886 887 handleTextEscaping(); 888 _namesSize = m_expandedNameTable.getSize(); 889 } 890 891 /** 892 * Specialized interface used by DOM2SAX. This one has an extra Node 893 * parameter to build the Node -> id map. 894 */ 895 public void startElement(String uri, String localName, 896 String qname, Attributes attributes, 897 Node node) 898 throws SAXException 899 { 900 this.startElement(uri, localName, qname, attributes); 901 902 if (m_buildIdIndex) { 903 _node2Ids.put(node, new Integer(m_parents.peek())); 904 } 905 } 906 907 /** 908 * SAX2: Receive notification of the beginning of an element. 909 */ 910 public void startElement(String uri, String localName, 911 String qname, Attributes attributes) 912 throws SAXException 913 { 914 super.startElement(uri, localName, qname, attributes); 915 916 handleTextEscaping(); 917 918 if (m_wsfilter != null) { 919 // Look for any xml:space attributes 920 // Depending on the implementation of attributes, this 921 // might be faster than looping through all attributes. ILENE 922 final int index = attributes.getIndex(XMLSPACE_STRING); 923 if (index >= 0) { 924 xmlSpaceDefine(attributes.getValue(index), m_parents.peek()); 925 } 926 } 927 } 928 929 /** 930 * SAX2: Receive notification of the end of an element. 931 */ 932 public void endElement(String namespaceURI, String localName, String qname) 933 throws SAXException 934 { 935 super.endElement(namespaceURI, localName, qname); 936 937 handleTextEscaping(); 938 939 // Revert to strip/preserve-space setting from before this element 940 if (m_wsfilter != null) { 941 xmlSpaceRevert(m_previous); 942 } 943 } 944 945 /** 946 * SAX2: Receive notification of a processing instruction. 947 */ 948 public void processingInstruction(String target, String data) 949 throws SAXException 950 { 951 super.processingInstruction(target, data); 952 handleTextEscaping(); 953 } 954 955 /** 956 * SAX2: Receive notification of ignorable whitespace in element 957 * content. Similar to characters(char[], int, int). 958 */ 959 public void ignorableWhitespace(char[] ch, int start, int length) 960 throws SAXException 961 { 962 super.ignorableWhitespace(ch, start, length); 963 _textNodeToProcess = getNumberOfNodes(); 964 } 965 966 /** 967 * SAX2: Begin the scope of a prefix-URI Namespace mapping. 968 */ 969 public void startPrefixMapping(String prefix, String uri) 970 throws SAXException 971 { 972 super.startPrefixMapping(prefix, uri); 973 handleTextEscaping(); 974 975 definePrefixAndUri(prefix, uri); 976 } 977 978 private void definePrefixAndUri(String prefix, String uri) 979 throws SAXException 980 { 981 // Check if the URI already exists before pushing on stack 982 Integer eType = new Integer(getIdForNamespace(uri)); 983 if (_nsIndex.get(eType) == null) { 984 _nsIndex.put(eType, _uriCount++); 985 } 986 } 987 988 /** 989 * SAX2: Report an XML comment anywhere in the document. 990 */ 991 public void comment(char[] ch, int start, int length) 992 throws SAXException 993 { 994 super.comment(ch, start, length); 995 handleTextEscaping(); 996 } 997 998 public boolean setEscaping(boolean value) { 999 final boolean temp = _escaping; 1000 _escaping = value; 1001 return temp; 1002 } 1003 1004 /*---------------------------------------------------------------------------*/ 1005 /* DOMBuilder methods end */ 1006 /*---------------------------------------------------------------------------*/ 1007 1008 /** 1009 * Prints the whole tree to standard output 1010 */ 1011 public void print(int node, int level) 1012 { 1013 switch(getNodeType(node)) 1014 { 1015 case DTM.ROOT_NODE: 1016 case DTM.DOCUMENT_NODE: 1017 print(getFirstChild(node), level); 1018 break; 1019 case DTM.TEXT_NODE: 1020 case DTM.COMMENT_NODE: 1021 case DTM.PROCESSING_INSTRUCTION_NODE: 1022 System.out.print(getStringValueX(node)); 1023 break; 1024 default: 1025 final String name = getNodeName(node); 1026 System.out.print("<" + name); 1027 for (int a = getFirstAttribute(node); a != DTM.NULL; a = getNextAttribute(a)) 1028 { 1029 System.out.print("\n" + getNodeName(a) + "=\"" + getStringValueX(a) + "\""); 1030 } 1031 System.out.print('>'); 1032 for (int child = getFirstChild(node); child != DTM.NULL; 1033 child = getNextSibling(child)) { 1034 print(child, level + 1); 1035 } 1036 System.out.println("</" + name + '>'); 1037 break; 1038 } 1039 } 1040 1041 /** 1042 * Returns the name of a node (attribute or element). 1043 */ 1044 public String getNodeName(final int node) 1045 { 1046 // Get the node type and make sure that it is within limits 1047 int nodeh = node; 1048 final short type = getNodeType(nodeh); 1049 switch(type) 1050 { 1051 case DTM.ROOT_NODE: 1052 case DTM.DOCUMENT_NODE: 1053 case DTM.TEXT_NODE: 1054 case DTM.COMMENT_NODE: 1055 return EMPTYSTRING; 1056 case DTM.NAMESPACE_NODE: 1057 return this.getLocalName(nodeh); 1058 default: 1059 return super.getNodeName(nodeh); 1060 } 1061 } 1062 1063 /** 1064 * Returns the namespace URI to which a node belongs 1065 */ 1066 public String getNamespaceName(final int node) 1067 { 1068 if (node == DTM.NULL) { 1069 return ""; 1070 } 1071 1072 String s; 1073 return (s = getNamespaceURI(node)) == null ? EMPTYSTRING : s; 1074 } 1075 1076 1077 /** 1078 * Returns the attribute node of a given type (if any) for an element 1079 */ 1080 public int getAttributeNode(final int type, final int element) 1081 { 1082 for (int attr = getFirstAttribute(element); 1083 attr != DTM.NULL; 1084 attr = getNextAttribute(attr)) 1085 { 1086 if (getExpandedTypeID(attr) == type) return attr; 1087 } 1088 return DTM.NULL; 1089 } 1090 1091 /** 1092 * Returns the value of a given attribute type of a given element 1093 */ 1094 public String getAttributeValue(final int type, final int element) 1095 { 1096 final int attr = getAttributeNode(type, element); 1097 return (attr != DTM.NULL) ? getStringValueX(attr) : EMPTYSTRING; 1098 } 1099 1100 /** 1101 * This method is for testing/debugging only 1102 */ 1103 public String getAttributeValue(final String name, final int element) 1104 { 1105 return getAttributeValue(getGeneralizedType(name), element); 1106 } 1107 1108 /** 1109 * Returns an iterator with all the children of a given node 1110 */ 1111 public DTMAxisIterator getChildren(final int node) 1112 { 1113 return (new ChildrenIterator()).setStartNode(node); 1114 } 1115 1116 /** 1117 * Returns an iterator with all children of a specific type 1118 * for a given node (element) 1119 */ 1120 public DTMAxisIterator getTypedChildren(final int type) 1121 { 1122 return(new TypedChildrenIterator(type)); 1123 } 1124 1125 /** 1126 * This is a shortcut to the iterators that implement the 1127 * supported XPath axes (only namespace::) is not supported. 1128 * Returns a bare-bones iterator that must be initialized 1129 * with a start node (using iterator.setStartNode()). 1130 */ 1131 public DTMAxisIterator getAxisIterator(final int axis) 1132 { 1133 switch (axis) 1134 { 1135 case Axis.SELF: 1136 return new SingletonIterator(); 1137 case Axis.CHILD: 1138 return new ChildrenIterator(); 1139 case Axis.PARENT: 1140 return new ParentIterator(); 1141 case Axis.ANCESTOR: 1142 return new AncestorIterator(); 1143 case Axis.ANCESTORORSELF: 1144 return (new AncestorIterator()).includeSelf(); 1145 case Axis.ATTRIBUTE: 1146 return new AttributeIterator(); 1147 case Axis.DESCENDANT: 1148 return new DescendantIterator(); 1149 case Axis.DESCENDANTORSELF: 1150 return (new DescendantIterator()).includeSelf(); 1151 case Axis.FOLLOWING: 1152 return new FollowingIterator(); 1153 case Axis.PRECEDING: 1154 return new PrecedingIterator(); 1155 case Axis.FOLLOWINGSIBLING: 1156 return new FollowingSiblingIterator(); 1157 case Axis.PRECEDINGSIBLING: 1158 return new PrecedingSiblingIterator(); 1159 case Axis.NAMESPACE: 1160 return new NamespaceIterator(); 1161 case Axis.ROOT: 1162 return new RootIterator(); 1163 default: 1164 BasisLibrary.runTimeError(BasisLibrary.AXIS_SUPPORT_ERR, 1165 Axis.getNames(axis)); 1166 } 1167 return null; 1168 } 1169 1170 /** 1171 * Similar to getAxisIterator, but this one returns an iterator 1172 * containing nodes of a typed axis (ex.: child::foo) 1173 */ 1174 public DTMAxisIterator getTypedAxisIterator(int axis, int type) 1175 { 1176 // Most common case handled first 1177 if (axis == Axis.CHILD) { 1178 return new TypedChildrenIterator(type); 1179 } 1180 1181 if (type == NO_TYPE) { 1182 return(EMPTYITERATOR); 1183 } 1184 1185 switch (axis) 1186 { 1187 case Axis.SELF: 1188 return new TypedSingletonIterator(type); 1189 case Axis.CHILD: 1190 return new TypedChildrenIterator(type); 1191 case Axis.PARENT: 1192 return new ParentIterator().setNodeType(type); 1193 case Axis.ANCESTOR: 1194 return new TypedAncestorIterator(type); 1195 case Axis.ANCESTORORSELF: 1196 return (new TypedAncestorIterator(type)).includeSelf(); 1197 case Axis.ATTRIBUTE: 1198 return new TypedAttributeIterator(type); 1199 case Axis.DESCENDANT: 1200 return new TypedDescendantIterator(type); 1201 case Axis.DESCENDANTORSELF: 1202 return (new TypedDescendantIterator(type)).includeSelf(); 1203 case Axis.FOLLOWING: 1204 return new TypedFollowingIterator(type); 1205 case Axis.PRECEDING: 1206 return new TypedPrecedingIterator(type); 1207 case Axis.FOLLOWINGSIBLING: 1208 return new TypedFollowingSiblingIterator(type); 1209 case Axis.PRECEDINGSIBLING: 1210 return new TypedPrecedingSiblingIterator(type); 1211 case Axis.NAMESPACE: 1212 return new TypedNamespaceIterator(type); 1213 case Axis.ROOT: 1214 return new TypedRootIterator(type); 1215 default: 1216 BasisLibrary.runTimeError(BasisLibrary.TYPED_AXIS_SUPPORT_ERR, 1217 Axis.getNames(axis)); 1218 } 1219 return null; 1220 } 1221 1222 /** 1223 * Do not think that this returns an iterator for the namespace axis. 1224 * It returns an iterator with nodes that belong in a certain namespace, 1225 * such as with <xsl:apply-templates select="blob/foo:*"/> 1226 * The 'axis' specifies the axis for the base iterator from which the 1227 * nodes are taken, while 'ns' specifies the namespace URI type. 1228 */ 1229 public DTMAxisIterator getNamespaceAxisIterator(int axis, int ns) 1230 { 1231 if (ns == NO_TYPE) { 1232 return EMPTYITERATOR; 1233 } 1234 else { 1235 switch (axis) { 1236 case Axis.CHILD: 1237 return new NamespaceChildrenIterator(ns); 1238 case Axis.ATTRIBUTE: 1239 return new NamespaceAttributeIterator(ns); 1240 default: 1241 return new NamespaceWildcardIterator(axis, ns); 1242 } 1243 } 1244 } 1245 1246 /** 1247 * Iterator that handles node tests that test for a namespace, but have 1248 * a wild card for the local name of the node, i.e., node tests of the 1249 * form <axis>::<prefix>:* 1250 */ 1251 public final class NamespaceWildcardIterator 1252 extends InternalAxisIteratorBase 1253 { 1254 /** 1255 * The namespace type index. 1256 */ 1257 protected int m_nsType; 1258 1259 /** 1260 * A nested typed axis iterator that retrieves nodes of the principal 1261 * node kind for that axis. 1262 */ 1263 protected DTMAxisIterator m_baseIterator; 1264 1265 /** 1266 * Constructor NamespaceWildcard 1267 * 1268 * @param axis The axis that this iterator will traverse 1269 * @param nsType The namespace type index 1270 */ 1271 public NamespaceWildcardIterator(int axis, int nsType) { 1272 m_nsType = nsType; 1273 1274 // Create a nested iterator that will select nodes of 1275 // the principal node kind for the selected axis. 1276 switch (axis) { 1277 case Axis.ATTRIBUTE: { 1278 // For "attribute::p:*", the principal node kind is 1279 // attribute 1280 m_baseIterator = getAxisIterator(axis); 1281 } 1282 case Axis.NAMESPACE: { 1283 // This covers "namespace::p:*". It is syntactically 1284 // correct, though it doesn't make much sense. 1285 m_baseIterator = getAxisIterator(axis); 1286 } 1287 default: { 1288 // In all other cases, the principal node kind is 1289 // element 1290 m_baseIterator = getTypedAxisIterator(axis, 1291 DTM.ELEMENT_NODE); 1292 } 1293 } 1294 } 1295 1296 /** 1297 * Set start to END should 'close' the iterator, 1298 * i.e. subsequent call to next() should return END. 1299 * 1300 * @param node Sets the root of the iteration. 1301 * 1302 * @return A DTMAxisIterator set to the start of the iteration. 1303 */ 1304 public DTMAxisIterator setStartNode(int node) { 1305 if (_isRestartable) { 1306 _startNode = node; 1307 m_baseIterator.setStartNode(node); 1308 resetPosition(); 1309 } 1310 return this; 1311 } 1312 1313 /** 1314 * Get the next node in the iteration. 1315 * 1316 * @return The next node handle in the iteration, or END. 1317 */ 1318 public int next() { 1319 int node; 1320 1321 while ((node = m_baseIterator.next()) != END) { 1322 // Return only nodes that are in the selected namespace 1323 if (getNSType(node) == m_nsType) { 1324 return returnNode(node); 1325 } 1326 } 1327 1328 return END; 1329 } 1330 1331 /** 1332 * Returns a deep copy of this iterator. The cloned iterator is not 1333 * reset. 1334 * 1335 * @return a deep copy of this iterator. 1336 */ 1337 public DTMAxisIterator cloneIterator() { 1338 try { 1339 DTMAxisIterator nestedClone = m_baseIterator.cloneIterator(); 1340 NamespaceWildcardIterator clone = 1341 (NamespaceWildcardIterator) super.clone(); 1342 1343 clone.m_baseIterator = nestedClone; 1344 clone.m_nsType = m_nsType; 1345 clone._isRestartable = false; 1346 1347 return clone; 1348 } catch (CloneNotSupportedException e) { 1349 BasisLibrary.runTimeError(BasisLibrary.ITERATOR_CLONE_ERR, 1350 e.toString()); 1351 return null; 1352 } 1353 } 1354 1355 /** 1356 * True if this iterator has a reversed axis. 1357 * 1358 * @return <code>true</code> if this iterator is a reversed axis. 1359 */ 1360 public boolean isReverse() { 1361 return m_baseIterator.isReverse(); 1362 } 1363 1364 public void setMark() { 1365 m_baseIterator.setMark(); 1366 } 1367 1368 public void gotoMark() { 1369 m_baseIterator.gotoMark(); 1370 } 1371 } 1372 1373 /** 1374 * Iterator that returns children within a given namespace for a 1375 * given node. The functionality chould be achieved by putting a 1376 * filter on top of a basic child iterator, but a specialised 1377 * iterator is used for efficiency (both speed and size of translet). 1378 */ 1379 public final class NamespaceChildrenIterator 1380 extends InternalAxisIteratorBase 1381 { 1382 1383 /** The extended type ID being requested. */ 1384 private final int _nsType; 1385 1386 /** 1387 * Constructor NamespaceChildrenIterator 1388 * 1389 * 1390 * @param type The extended type ID being requested. 1391 */ 1392 public NamespaceChildrenIterator(final int type) { 1393 _nsType = type; 1394 } 1395 1396 /** 1397 * Set start to END should 'close' the iterator, 1398 * i.e. subsequent call to next() should return END. 1399 * 1400 * @param node Sets the root of the iteration. 1401 * 1402 * @return A DTMAxisIterator set to the start of the iteration. 1403 */ 1404 public DTMAxisIterator setStartNode(int node) { 1405 //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily 1406 if (node == DTMDefaultBase.ROOTNODE) { 1407 node = getDocument(); 1408 } 1409 1410 if (_isRestartable) { 1411 _startNode = node; 1412 _currentNode = (node == DTM.NULL) ? DTM.NULL : NOTPROCESSED; 1413 1414 return resetPosition(); 1415 } 1416 1417 return this; 1418 } 1419 1420 /** 1421 * Get the next node in the iteration. 1422 * 1423 * @return The next node handle in the iteration, or END. 1424 */ 1425 public int next() { 1426 if (_currentNode != DTM.NULL) { 1427 for (int node = (NOTPROCESSED == _currentNode) 1428 ? _firstch(makeNodeIdentity(_startNode)) 1429 : _nextsib(_currentNode); 1430 node != END; 1431 node = _nextsib(node)) { 1432 int nodeHandle = makeNodeHandle(node); 1433 1434 if (getNSType(nodeHandle) == _nsType) { 1435 _currentNode = node; 1436 1437 return returnNode(nodeHandle); 1438 } 1439 } 1440 } 1441 1442 return END; 1443 } 1444 } // end of NamespaceChildrenIterator 1445 1446 /** 1447 * Iterator that returns attributes within a given namespace for a node. 1448 */ 1449 public final class NamespaceAttributeIterator 1450 extends InternalAxisIteratorBase 1451 { 1452 1453 /** The extended type ID being requested. */ 1454 private final int _nsType; 1455 1456 /** 1457 * Constructor NamespaceAttributeIterator 1458 * 1459 * 1460 * @param nsType The extended type ID being requested. 1461 */ 1462 public NamespaceAttributeIterator(int nsType) { 1463 super(); 1464 1465 _nsType = nsType; 1466 } 1467 1468 /** 1469 * Set start to END should 'close' the iterator, 1470 * i.e. subsequent call to next() should return END. 1471 * 1472 * @param node Sets the root of the iteration. 1473 * 1474 * @return A DTMAxisIterator set to the start of the iteration. 1475 */ 1476 public DTMAxisIterator setStartNode(int node) { 1477 //%HZ%: Added reference to DTMDefaultBase.ROOTNODE back in, temporarily 1478 if (node == DTMDefaultBase.ROOTNODE) { 1479 node = getDocument(); 1480 } 1481 1482 if (_isRestartable) { 1483 int nsType = _nsType; 1484 1485 _startNode = node; 1486 1487 for (node = getFirstAttribute(node); 1488 node != END; 1489 node = getNextAttribute(node)) { 1490 if (getNSType(node) == nsType) { 1491 break; 1492 } 1493 } 1494 1495 _currentNode = node; 1496 return resetPosition(); 1497 } 1498 1499 return this; 1500 } 1501 1502 /** 1503 * Get the next node in the iteration. 1504 * 1505 * @return The next node handle in the iteration, or END. 1506 */ 1507 public int next() { 1508 int node = _currentNode; 1509 int nsType = _nsType; 1510 int nextNode; 1511 1512 if (node == END) { 1513 return END; 1514 } 1515 1516 for (nextNode = getNextAttribute(node); 1517 nextNode != END; 1518 nextNode = getNextAttribute(nextNode)) { 1519 if (getNSType(nextNode) == nsType) { 1520 break; 1521 } 1522 } 1523 1524 _currentNode = nextNode; 1525 1526 return returnNode(node); 1527 } 1528 } // end of NamespaceAttributeIterator 1529 1530 /** 1531 * Returns an iterator with all descendants of a node that are of 1532 * a given type. 1533 */ 1534 public DTMAxisIterator getTypedDescendantIterator(int type) 1535 { 1536 return new TypedDescendantIterator(type); 1537 } 1538 1539 /** 1540 * Returns the nth descendant of a node 1541 */ 1542 public DTMAxisIterator getNthDescendant(int type, int n, boolean includeself) 1543 { 1544 return new NthDescendantIterator(n); 1545 } 1546 1547 /** 1548 * Copy the string value of a node directly to an output handler 1549 */ 1550 public void characters(final int node, SerializationHandler handler) 1551 throws TransletException 1552 { 1553 if (node != DTM.NULL) { 1554 try { 1555 dispatchCharactersEvents(node, handler, false); 1556 } catch (SAXException e) { 1557 throw new TransletException(e); 1558 } 1559 } 1560 } 1561 1562 /** 1563 * Copy a node-set to an output handler 1564 */ 1565 public void copy(DTMAxisIterator nodes, SerializationHandler handler) 1566 throws TransletException 1567 { 1568 int node; 1569 while ((node = nodes.next()) != DTM.NULL) { 1570 copy(node, handler); 1571 } 1572 } 1573 1574 /** 1575 * Copy the whole tree to an output handler 1576 */ 1577 public void copy(SerializationHandler handler) throws TransletException 1578 { 1579 copy(getDocument(), handler); 1580 } 1581 1582 /** 1583 * Performs a deep copy (ref. XSLs copy-of()) 1584 * 1585 * TODO: Copy namespace declarations. Can't be done until we 1586 * add namespace nodes and keep track of NS prefixes 1587 * TODO: Copy comment nodes 1588 */ 1589 public void copy(final int node, SerializationHandler handler) 1590 throws TransletException 1591 { 1592 copy(node, handler, false ); 1593 } 1594 1595 1596 private final void copy(final int node, SerializationHandler handler, boolean isChild) 1597 throws TransletException 1598 { 1599 int nodeID = makeNodeIdentity(node); 1600 int eType = _exptype2(nodeID); 1601 int type = _exptype2Type(eType); 1602 1603 try { 1604 switch(type) 1605 { 1606 case DTM.ROOT_NODE: 1607 case DTM.DOCUMENT_NODE: 1608 for(int c = _firstch2(nodeID); c != DTM.NULL; c = _nextsib2(c)) { 1609 copy(makeNodeHandle(c), handler, true); 1610 } 1611 break; 1612 case DTM.PROCESSING_INSTRUCTION_NODE: 1613 copyPI(node, handler); 1614 break; 1615 case DTM.COMMENT_NODE: 1616 handler.comment(getStringValueX(node)); 1617 break; 1618 case DTM.TEXT_NODE: 1619 boolean oldEscapeSetting = false; 1620 boolean escapeBit = false; 1621 1622 if (_dontEscape != null) { 1623 escapeBit = _dontEscape.getBit(getNodeIdent(node)); 1624 if (escapeBit) { 1625 oldEscapeSetting = handler.setEscaping(false); 1626 } 1627 } 1628 1629 copyTextNode(nodeID, handler); 1630 1631 if (escapeBit) { 1632 handler.setEscaping(oldEscapeSetting); 1633 } 1634 break; 1635 case DTM.ATTRIBUTE_NODE: 1636 copyAttribute(nodeID, eType, handler); 1637 break; 1638 case DTM.NAMESPACE_NODE: 1639 handler.namespaceAfterStartElement(getNodeNameX(node), getNodeValue(node)); 1640 break; 1641 default: 1642 if (type == DTM.ELEMENT_NODE) 1643 { 1644 // Start element definition 1645 final String name = copyElement(nodeID, eType, handler); 1646 //if(isChild) => not to copy any namespaces from parents 1647 // else copy all namespaces in scope 1648 copyNS(nodeID, handler,!isChild); 1649 copyAttributes(nodeID, handler); 1650 // Copy element children 1651 for (int c = _firstch2(nodeID); c != DTM.NULL; c = _nextsib2(c)) { 1652 copy(makeNodeHandle(c), handler, true); 1653 } 1654 1655 // Close element definition 1656 handler.endElement(name); 1657 } 1658 // Shallow copy of attribute to output handler 1659 else { 1660 final String uri = getNamespaceName(node); 1661 if (uri.length() != 0) { 1662 final String prefix = getPrefix(node); 1663 handler.namespaceAfterStartElement(prefix, uri); 1664 } 1665 handler.addAttribute(getNodeName(node), getNodeValue(node)); 1666 } 1667 break; 1668 } 1669 } 1670 catch (Exception e) { 1671 throw new TransletException(e); 1672 } 1673 1674 } 1675 /** 1676 * Copies a processing instruction node to an output handler 1677 */ 1678 private void copyPI(final int node, SerializationHandler handler) 1679 throws TransletException 1680 { 1681 final String target = getNodeName(node); 1682 final String value = getStringValueX(node); 1683 1684 try { 1685 handler.processingInstruction(target, value); 1686 } catch (Exception e) { 1687 throw new TransletException(e); 1688 } 1689 } 1690 1691 /** 1692 * Performs a shallow copy (ref. XSLs copy()) 1693 */ 1694 public String shallowCopy(final int node, SerializationHandler handler) 1695 throws TransletException 1696 { 1697 int nodeID = makeNodeIdentity(node); 1698 int exptype = _exptype2(nodeID); 1699 int type = _exptype2Type(exptype); 1700 1701 try { 1702 switch(type) 1703 { 1704 case DTM.ELEMENT_NODE: 1705 final String name = copyElement(nodeID, exptype, handler); 1706 copyNS(nodeID, handler, true); 1707 return name; 1708 case DTM.ROOT_NODE: 1709 case DTM.DOCUMENT_NODE: 1710 return EMPTYSTRING; 1711 case DTM.TEXT_NODE: 1712 copyTextNode(nodeID, handler); 1713 return null; 1714 case DTM.PROCESSING_INSTRUCTION_NODE: 1715 copyPI(node, handler); 1716 return null; 1717 case DTM.COMMENT_NODE: 1718 handler.comment(getStringValueX(node)); 1719 return null; 1720 case DTM.NAMESPACE_NODE: 1721 handler.namespaceAfterStartElement(getNodeNameX(node), getNodeValue(node)); 1722 return null; 1723 case DTM.ATTRIBUTE_NODE: 1724 copyAttribute(nodeID, exptype, handler); 1725 return null; 1726 default: 1727 final String uri1 = getNamespaceName(node); 1728 if (uri1.length() != 0) { 1729 final String prefix = getPrefix(node); 1730 handler.namespaceAfterStartElement(prefix, uri1); 1731 } 1732 handler.addAttribute(getNodeName(node), getNodeValue(node)); 1733 return null; 1734 } 1735 } catch (Exception e) { 1736 throw new TransletException(e); 1737 } 1738 } 1739 1740 /** 1741 * Returns a node' defined language for a node (if any) 1742 */ 1743 public String getLanguage(int node) 1744 { 1745 int parent = node; 1746 while (DTM.NULL != parent) { 1747 if (DTM.ELEMENT_NODE == getNodeType(parent)) { 1748 int langAttr = getAttributeNode(parent, "http://www.w3.org/XML/1998/namespace", "lang"); 1749 1750 if (DTM.NULL != langAttr) { 1751 return getNodeValue(langAttr); 1752 } 1753 } 1754 1755 parent = getParent(parent); 1756 } 1757 return(null); 1758 } 1759 1760 /** 1761 * Returns an instance of the DOMBuilder inner class 1762 * This class will consume the input document through a SAX2 1763 * interface and populate the tree. 1764 */ 1765 public DOMBuilder getBuilder() 1766 { 1767 return this; 1768 } 1769 1770 /** 1771 * Return a SerializationHandler for output handling. 1772 * This method is used by Result Tree Fragments. 1773 */ 1774 public SerializationHandler getOutputDomBuilder() 1775 { 1776 return new ToXMLSAXHandler(this, "UTF-8"); 1777 } 1778 1779 /** 1780 * Return a instance of a DOM class to be used as an RTF 1781 */ 1782 public DOM getResultTreeFrag(int initSize, int rtfType) 1783 { 1784 return getResultTreeFrag(initSize, rtfType, true); 1785 } 1786 1787 /** 1788 * Return a instance of a DOM class to be used as an RTF 1789 * 1790 * @param initSize The initial size of the DOM. 1791 * @param rtfType The type of the RTF 1792 * @param addToManager true if the RTF should be registered with the DTMManager. 1793 * @return The DOM object which represents the RTF. 1794 */ 1795 public DOM getResultTreeFrag(int initSize, int rtfType, boolean addToManager) 1796 { 1797 if (rtfType == DOM.SIMPLE_RTF) { 1798 if (addToManager) { 1799 int dtmPos = _dtmManager.getFirstFreeDTMID(); 1800 SimpleResultTreeImpl rtf = new SimpleResultTreeImpl(_dtmManager, 1801 dtmPos << DTMManager.IDENT_DTM_NODE_BITS); 1802 _dtmManager.addDTM(rtf, dtmPos, 0); 1803 return rtf; 1804 } 1805 else { 1806 return new SimpleResultTreeImpl(_dtmManager, 0); 1807 } 1808 } 1809 else if (rtfType == DOM.ADAPTIVE_RTF) { 1810 if (addToManager) { 1811 int dtmPos = _dtmManager.getFirstFreeDTMID(); 1812 AdaptiveResultTreeImpl rtf = new AdaptiveResultTreeImpl(_dtmManager, 1813 dtmPos << DTMManager.IDENT_DTM_NODE_BITS, 1814 m_wsfilter, initSize, m_buildIdIndex); 1815 _dtmManager.addDTM(rtf, dtmPos, 0); 1816 return rtf; 1817 1818 } 1819 else { 1820 return new AdaptiveResultTreeImpl(_dtmManager, 0, 1821 m_wsfilter, initSize, m_buildIdIndex); 1822 } 1823 } 1824 else { 1825 return (DOM) _dtmManager.getDTM(null, true, m_wsfilter, 1826 true, false, false, 1827 initSize, m_buildIdIndex); 1828 } 1829 } 1830 1831 /** 1832 * Return the attributes map. 1833 * @return the attributes map. 1834 */ 1835 public Map<String, Integer> getElementsWithIDs() { 1836 return m_idAttributes; 1837 } 1838 1839 /** 1840 * The getUnparsedEntityURI function returns the URI of the unparsed 1841 * entity with the specified name in the same document as the context 1842 * node (see [3.3 Unparsed Entities]). It returns the empty string if 1843 * there is no such entity. 1844 */ 1845 public String getUnparsedEntityURI(String name) 1846 { 1847 // Special handling for DOM input 1848 if (_document != null) { 1849 String uri = ""; 1850 DocumentType doctype = _document.getDoctype(); 1851 if (doctype != null) { 1852 NamedNodeMap entities = doctype.getEntities(); 1853 1854 if (entities == null) { 1855 return uri; 1856 } 1857 1858 Entity entity = (Entity) entities.getNamedItem(name); 1859 1860 if (entity == null) { 1861 return uri; 1862 } 1863 1864 String notationName = entity.getNotationName(); 1865 if (notationName != null) { 1866 uri = entity.getSystemId(); 1867 if (uri == null) { 1868 uri = entity.getPublicId(); 1869 } 1870 } 1871 } 1872 return uri; 1873 } 1874 else { 1875 return super.getUnparsedEntityURI(name); 1876 } 1877 } 1878 1879 public void release() { 1880 _dtmManager.release(this, true); 1881 } 1882 }