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