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