1 /* 2 * Licensed to the Apache Software Foundation (ASF) under one 3 * or more contributor license agreements. See the NOTICE file 4 * distributed with this work for additional information 5 * regarding copyright ownership. The ASF licenses this file 6 * to you under the Apache License, Version 2.0 (the "License"); 7 * you may not use this file except in compliance with the License. 8 * You may obtain a copy of the License at 9 * 10 * http://www.apache.org/licenses/LICENSE-2.0 11 * 12 * Unless required by applicable law or agreed to in writing, software 13 * distributed under the License is distributed on an "AS IS" BASIS, 14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 * See the License for the specific language governing permissions and 16 * limitations under the License. 17 */ 18 /* 19 * $Id: SAX2DTM.java 468653 2006-10-28 07:07:05Z minchau $ 20 */ 21 package org.apache.xml.dtm.ref.sax2dtm; 22 23 import java.util.Hashtable; 24 import java.util.Vector; 25 import javax.xml.transform.Source; 26 import javax.xml.transform.SourceLocator; 27 28 import org.apache.xml.dtm.*; 29 import org.apache.xml.dtm.ref.*; 30 import org.apache.xml.utils.StringVector; 31 import org.apache.xml.utils.IntVector; 32 import org.apache.xml.utils.FastStringBuffer; 33 import org.apache.xml.utils.IntStack; 34 import org.apache.xml.utils.SuballocatedIntVector; 35 import org.apache.xml.utils.SystemIDResolver; 36 import org.apache.xml.utils.WrappedRuntimeException; 37 import org.apache.xml.utils.XMLString; 38 import org.apache.xml.utils.XMLStringFactory; 39 import org.apache.xml.res.XMLErrorResources; 40 import org.apache.xml.res.XMLMessages; 41 import org.xml.sax.*; 42 import org.xml.sax.ext.*; 43 44 /** 45 * This class implements a DTM that tends to be optimized more for speed than 46 * for compactness, that is constructed via SAX2 ContentHandler events. 47 */ 48 public class SAX2DTM extends DTMDefaultBaseIterators 49 implements EntityResolver, DTDHandler, ContentHandler, ErrorHandler, 50 DeclHandler, LexicalHandler 51 { 52 /** Set true to monitor SAX events and similar diagnostic info. */ 53 private static final boolean DEBUG = false; 54 55 /** 56 * If we're building the model incrementally on demand, we need to 57 * be able to tell the source when to send us more data. 58 * 59 * Note that if this has not been set, and you attempt to read ahead 60 * of the current build point, we'll probably throw a null-pointer 61 * exception. We could try to wait-and-retry instead, as a very poor 62 * fallback, but that has all the known problems with multithreading 63 * on multiprocessors and we Don't Want to Go There. 64 * 65 * @see setIncrementalSAXSource 66 */ 67 private IncrementalSAXSource m_incrementalSAXSource = null; 68 69 /** 70 * All the character content, including attribute values, are stored in 71 * this buffer. 72 * 73 * %REVIEW% Should this have an option of being shared across DTMs? 74 * Sequentially only; not threadsafe... Currently, I think not. 75 * 76 * %REVIEW% Initial size was pushed way down to reduce weight of RTFs. 77 * pending reduction in number of RTF DTMs. Now that we're sharing a DTM 78 * between RTFs, and tail-pruning... consider going back to the larger/faster. 79 * 80 * Made protected rather than private so SAX2RTFDTM can access it. 81 */ 82 //private FastStringBuffer m_chars = new FastStringBuffer(13, 13); 83 protected FastStringBuffer m_chars; 84 85 /** This vector holds offset and length data. 86 */ 87 protected SuballocatedIntVector m_data; 88 89 /** The parent stack, needed only for construction. 90 * Made protected rather than private so SAX2RTFDTM can access it. 91 */ 92 transient protected IntStack m_parents; 93 94 /** The current previous node, needed only for construction time. 95 * Made protected rather than private so SAX2RTFDTM can access it. 96 */ 97 transient protected int m_previous = 0; 98 99 /** Namespace support, only relevent at construction time. 100 * Made protected rather than private so SAX2RTFDTM can access it. 101 */ 102 transient protected java.util.Vector m_prefixMappings = 103 new java.util.Vector(); 104 105 /** Namespace support, only relevent at construction time. 106 * Made protected rather than private so SAX2RTFDTM can access it. 107 */ 108 transient protected IntStack m_contextIndexes; 109 110 /** Type of next characters() event within text block in prgress. */ 111 transient protected int m_textType = DTM.TEXT_NODE; 112 113 /** 114 * Type of coalesced text block. See logic in the characters() 115 * method. 116 */ 117 transient protected int m_coalescedTextType = DTM.TEXT_NODE; 118 119 /** The SAX Document locator */ 120 transient protected Locator m_locator = null; 121 122 /** The SAX Document system-id */ 123 transient private String m_systemId = null; 124 125 /** We are inside the DTD. This is used for ignoring comments. */ 126 transient protected boolean m_insideDTD = false; 127 128 /** Tree Walker for dispatchToEvents. */ 129 protected DTMTreeWalker m_walker = new DTMTreeWalker(); 130 131 /** pool of string values that come as strings. */ 132 protected DTMStringPool m_valuesOrPrefixes; 133 134 /** End document has been reached. 135 * Made protected rather than private so SAX2RTFDTM can access it. 136 */ 137 protected boolean m_endDocumentOccured = false; 138 139 /** Data or qualified name values, one array element for each node. */ 140 protected SuballocatedIntVector m_dataOrQName; 141 142 /** 143 * This table holds the ID string to node associations, for 144 * XML IDs. 145 */ 146 protected Hashtable m_idAttributes = new Hashtable(); 147 148 /** 149 * fixed dom-style names. 150 */ 151 private static final String[] m_fixednames = { null, 152 null, // nothing, Element 153 null, "#text", // Attr, Text 154 "#cdata_section", null, // CDATA, EntityReference 155 null, null, // Entity, PI 156 "#comment", "#document", // Comment, Document 157 null, "#document-fragment", // Doctype, DocumentFragment 158 null }; // Notation 159 160 /** 161 * Vector of entities. Each record is composed of four Strings: 162 * publicId, systemID, notationName, and name. 163 */ 164 private Vector m_entities = null; 165 166 /** m_entities public ID offset. */ 167 private static final int ENTITY_FIELD_PUBLICID = 0; 168 169 /** m_entities system ID offset. */ 170 private static final int ENTITY_FIELD_SYSTEMID = 1; 171 172 /** m_entities notation name offset. */ 173 private static final int ENTITY_FIELD_NOTATIONNAME = 2; 174 175 /** m_entities name offset. */ 176 private static final int ENTITY_FIELD_NAME = 3; 177 178 /** Number of entries per record for m_entities. */ 179 private static final int ENTITY_FIELDS_PER = 4; 180 181 /** 182 * The starting offset within m_chars for the text or 183 * CDATA_SECTION node currently being acumulated, 184 * or -1 if there is no text node in progress 185 */ 186 protected int m_textPendingStart = -1; 187 188 /** 189 * Describes whether information about document source location 190 * should be maintained or not. 191 * 192 * Made protected for access by SAX2RTFDTM. 193 */ 194 protected boolean m_useSourceLocationProperty = false; 195 196 /** Made protected for access by SAX2RTFDTM. 197 */ 198 protected StringVector m_sourceSystemId; 199 /** Made protected for access by SAX2RTFDTM. 200 */ 201 protected IntVector m_sourceLine; 202 /** Made protected for access by SAX2RTFDTM. 203 */ 204 protected IntVector m_sourceColumn; 205 206 /** 207 * Construct a SAX2DTM object using the default block size. 208 * 209 * @param mgr The DTMManager who owns this DTM. 210 * @param source the JAXP 1.1 Source object for this DTM. 211 * @param dtmIdentity The DTM identity ID for this DTM. 212 * @param whiteSpaceFilter The white space filter for this DTM, which may 213 * be null. 214 * @param xstringfactory XMLString factory for creating character content. 215 * @param doIndexing true if the caller considers it worth it to use 216 * indexing schemes. 217 */ 218 public SAX2DTM(DTMManager mgr, Source source, int dtmIdentity, 219 DTMWSFilter whiteSpaceFilter, 220 XMLStringFactory xstringfactory, 221 boolean doIndexing) 222 { 223 224 this(mgr, source, dtmIdentity, whiteSpaceFilter, 225 xstringfactory, doIndexing, DEFAULT_BLOCKSIZE, true, false); 226 } 227 228 /** 229 * Construct a SAX2DTM object ready to be constructed from SAX2 230 * ContentHandler events. 231 * 232 * @param mgr The DTMManager who owns this DTM. 233 * @param source the JAXP 1.1 Source object for this DTM. 234 * @param dtmIdentity The DTM identity ID for this DTM. 235 * @param whiteSpaceFilter The white space filter for this DTM, which may 236 * be null. 237 * @param xstringfactory XMLString factory for creating character content. 238 * @param doIndexing true if the caller considers it worth it to use 239 * indexing schemes. 240 * @param blocksize The block size of the DTM. 241 * @param usePrevsib true if we want to build the previous sibling node array. 242 * @param newNameTable true if we want to use a new ExpandedNameTable for this DTM. 243 */ 244 public SAX2DTM(DTMManager mgr, Source source, int dtmIdentity, 245 DTMWSFilter whiteSpaceFilter, 246 XMLStringFactory xstringfactory, 247 boolean doIndexing, 248 int blocksize, 249 boolean usePrevsib, 250 boolean newNameTable) 251 { 252 253 super(mgr, source, dtmIdentity, whiteSpaceFilter, 254 xstringfactory, doIndexing, blocksize, usePrevsib, newNameTable); 255 256 // %OPT% Use smaller sizes for all internal storage units when 257 // the blocksize is small. This reduces the cost of creating an RTF. 258 if (blocksize <= 64) 259 { 260 m_data = new SuballocatedIntVector(blocksize, DEFAULT_NUMBLOCKS_SMALL); 261 m_dataOrQName = new SuballocatedIntVector(blocksize, DEFAULT_NUMBLOCKS_SMALL); 262 m_valuesOrPrefixes = new DTMStringPool(16); 263 m_chars = new FastStringBuffer(7, 10); 264 m_contextIndexes = new IntStack(4); 265 m_parents = new IntStack(4); 266 } 267 else 268 { 269 m_data = new SuballocatedIntVector(blocksize, DEFAULT_NUMBLOCKS); 270 m_dataOrQName = new SuballocatedIntVector(blocksize, DEFAULT_NUMBLOCKS); 271 m_valuesOrPrefixes = new DTMStringPool(); 272 m_chars = new FastStringBuffer(10, 13); 273 m_contextIndexes = new IntStack(); 274 m_parents = new IntStack(); 275 } 276 277 // %REVIEW% Initial size pushed way down to reduce weight of RTFs 278 // (I'm not entirely sure 0 would work, so I'm playing it safe for now.) 279 //m_data = new SuballocatedIntVector(doIndexing ? (1024*2) : 512, 1024); 280 //m_data = new SuballocatedIntVector(blocksize); 281 282 m_data.addElement(0); // Need placeholder in case index into here must be <0. 283 284 //m_dataOrQName = new SuballocatedIntVector(blocksize); 285 286 // m_useSourceLocationProperty=org.apache.xalan.processor.TransformerFactoryImpl.m_source_location; 287 m_useSourceLocationProperty = mgr.getSource_location(); 288 m_sourceSystemId = (m_useSourceLocationProperty) ? new StringVector() : null; 289 m_sourceLine = (m_useSourceLocationProperty) ? new IntVector() : null; 290 m_sourceColumn = (m_useSourceLocationProperty) ? new IntVector() : null; 291 } 292 293 /** 294 * Set whether information about document source location 295 * should be maintained or not. 296 */ 297 public void setUseSourceLocation(boolean useSourceLocation) 298 { 299 m_useSourceLocationProperty = useSourceLocation; 300 } 301 302 /** 303 * Get the data or qualified name for the given node identity. 304 * 305 * @param identity The node identity. 306 * 307 * @return The data or qualified name, or DTM.NULL. 308 */ 309 protected int _dataOrQName(int identity) 310 { 311 312 if (identity < m_size) 313 return m_dataOrQName.elementAt(identity); 314 315 // Check to see if the information requested has been processed, and, 316 // if not, advance the iterator until we the information has been 317 // processed. 318 while (true) 319 { 320 boolean isMore = nextNode(); 321 322 if (!isMore) 323 return NULL; 324 else if (identity < m_size) 325 return m_dataOrQName.elementAt(identity); 326 } 327 } 328 329 /** 330 * Ask the CoRoutine parser to doTerminate and clear the reference. 331 */ 332 public void clearCoRoutine() 333 { 334 clearCoRoutine(true); 335 } 336 337 /** 338 * Ask the CoRoutine parser to doTerminate and clear the reference. If 339 * the CoRoutine parser has already been cleared, this will have no effect. 340 * 341 * @param callDoTerminate true of doTerminate should be called on the 342 * coRoutine parser. 343 */ 344 public void clearCoRoutine(boolean callDoTerminate) 345 { 346 347 if (null != m_incrementalSAXSource) 348 { 349 if (callDoTerminate) 350 m_incrementalSAXSource.deliverMoreNodes(false); 351 352 m_incrementalSAXSource = null; 353 } 354 } 355 356 /** 357 * Bind a IncrementalSAXSource to this DTM. If we discover we need nodes 358 * that have not yet been built, we will ask this object to send us more 359 * events, and it will manage interactions with its data sources. 360 * 361 * Note that we do not actually build the IncrementalSAXSource, since we don't 362 * know what source it's reading from, what thread that source will run in, 363 * or when it will run. 364 * 365 * @param incrementalSAXSource The parser that we want to recieve events from 366 * on demand. 367 */ 368 public void setIncrementalSAXSource(IncrementalSAXSource incrementalSAXSource) 369 { 370 371 // Establish coroutine link so we can request more data 372 // 373 // Note: It's possible that some versions of IncrementalSAXSource may 374 // not actually use a CoroutineManager, and hence may not require 375 // that we obtain an Application Coroutine ID. (This relies on the 376 // coroutine transaction details having been encapsulated in the 377 // IncrementalSAXSource.do...() methods.) 378 m_incrementalSAXSource = incrementalSAXSource; 379 380 // Establish SAX-stream link so we can receive the requested data 381 incrementalSAXSource.setContentHandler(this); 382 incrementalSAXSource.setLexicalHandler(this); 383 incrementalSAXSource.setDTDHandler(this); 384 385 // Are the following really needed? incrementalSAXSource doesn't yet 386 // support them, and they're mostly no-ops here... 387 //incrementalSAXSource.setErrorHandler(this); 388 //incrementalSAXSource.setDeclHandler(this); 389 } 390 391 /** 392 * getContentHandler returns "our SAX builder" -- the thing that 393 * someone else should send SAX events to in order to extend this 394 * DTM model. 395 * 396 * %REVIEW% Should this return null if constrution already done/begun? 397 * 398 * @return null if this model doesn't respond to SAX events, 399 * "this" if the DTM object has a built-in SAX ContentHandler, 400 * the IncrementalSAXSource if we're bound to one and should receive 401 * the SAX stream via it for incremental build purposes... 402 */ 403 public ContentHandler getContentHandler() 404 { 405 406 if (m_incrementalSAXSource instanceof IncrementalSAXSource_Filter) 407 return (ContentHandler) m_incrementalSAXSource; 408 else 409 return this; 410 } 411 412 /** 413 * Return this DTM's lexical handler. 414 * 415 * %REVIEW% Should this return null if constrution already done/begun? 416 * 417 * @return null if this model doesn't respond to lexical SAX events, 418 * "this" if the DTM object has a built-in SAX ContentHandler, 419 * the IncrementalSAXSource if we're bound to one and should receive 420 * the SAX stream via it for incremental build purposes... 421 */ 422 public LexicalHandler getLexicalHandler() 423 { 424 425 if (m_incrementalSAXSource instanceof IncrementalSAXSource_Filter) 426 return (LexicalHandler) m_incrementalSAXSource; 427 else 428 return this; 429 } 430 431 /** 432 * Return this DTM's EntityResolver. 433 * 434 * @return null if this model doesn't respond to SAX entity ref events. 435 */ 436 public EntityResolver getEntityResolver() 437 { 438 return this; 439 } 440 441 /** 442 * Return this DTM's DTDHandler. 443 * 444 * @return null if this model doesn't respond to SAX dtd events. 445 */ 446 public DTDHandler getDTDHandler() 447 { 448 return this; 449 } 450 451 /** 452 * Return this DTM's ErrorHandler. 453 * 454 * @return null if this model doesn't respond to SAX error events. 455 */ 456 public ErrorHandler getErrorHandler() 457 { 458 return this; 459 } 460 461 /** 462 * Return this DTM's DeclHandler. 463 * 464 * @return null if this model doesn't respond to SAX Decl events. 465 */ 466 public DeclHandler getDeclHandler() 467 { 468 return this; 469 } 470 471 /** 472 * @return true iff we're building this model incrementally (eg 473 * we're partnered with a IncrementalSAXSource) and thus require that the 474 * transformation and the parse run simultaneously. Guidance to the 475 * DTMManager. 476 */ 477 public boolean needsTwoThreads() 478 { 479 return null != m_incrementalSAXSource; 480 } 481 482 /** 483 * Directly call the 484 * characters method on the passed ContentHandler for the 485 * string-value of the given node (see http://www.w3.org/TR/xpath#data-model 486 * for the definition of a node's string-value). Multiple calls to the 487 * ContentHandler's characters methods may well occur for a single call to 488 * this method. 489 * 490 * @param nodeHandle The node ID. 491 * @param ch A non-null reference to a ContentHandler. 492 * @param normalize true if the content should be normalized according to 493 * the rules for the XPath 494 * <a href="http://www.w3.org/TR/xpath#function-normalize-space">normalize-space</a> 495 * function. 496 * 497 * @throws SAXException 498 */ 499 public void dispatchCharactersEvents(int nodeHandle, ContentHandler ch, 500 boolean normalize) 501 throws SAXException 502 { 503 504 int identity = makeNodeIdentity(nodeHandle); 505 506 if (identity == DTM.NULL) 507 return; 508 509 int type = _type(identity); 510 511 if (isTextType(type)) 512 { 513 int dataIndex = m_dataOrQName.elementAt(identity); 514 int offset = m_data.elementAt(dataIndex); 515 int length = m_data.elementAt(dataIndex + 1); 516 517 if(normalize) 518 m_chars.sendNormalizedSAXcharacters(ch, offset, length); 519 else 520 m_chars.sendSAXcharacters(ch, offset, length); 521 } 522 else 523 { 524 int firstChild = _firstch(identity); 525 526 if (DTM.NULL != firstChild) 527 { 528 int offset = -1; 529 int length = 0; 530 int startNode = identity; 531 532 identity = firstChild; 533 534 do { 535 type = _type(identity); 536 537 if (isTextType(type)) 538 { 539 int dataIndex = _dataOrQName(identity); 540 541 if (-1 == offset) 542 { 543 offset = m_data.elementAt(dataIndex); 544 } 545 546 length += m_data.elementAt(dataIndex + 1); 547 } 548 549 identity = getNextNodeIdentity(identity); 550 } while (DTM.NULL != identity && (_parent(identity) >= startNode)); 551 552 if (length > 0) 553 { 554 if(normalize) 555 m_chars.sendNormalizedSAXcharacters(ch, offset, length); 556 else 557 m_chars.sendSAXcharacters(ch, offset, length); 558 } 559 } 560 else if(type != DTM.ELEMENT_NODE) 561 { 562 int dataIndex = _dataOrQName(identity); 563 564 if (dataIndex < 0) 565 { 566 dataIndex = -dataIndex; 567 dataIndex = m_data.elementAt(dataIndex + 1); 568 } 569 570 String str = m_valuesOrPrefixes.indexToString(dataIndex); 571 572 if(normalize) 573 FastStringBuffer.sendNormalizedSAXcharacters(str.toCharArray(), 574 0, str.length(), ch); 575 else 576 ch.characters(str.toCharArray(), 0, str.length()); 577 } 578 } 579 } 580 581 582 /** 583 * Given a node handle, return its DOM-style node name. This will 584 * include names such as #text or #document. 585 * 586 * @param nodeHandle the id of the node. 587 * @return String Name of this node, which may be an empty string. 588 * %REVIEW% Document when empty string is possible... 589 * %REVIEW-COMMENT% It should never be empty, should it? 590 */ 591 public String getNodeName(int nodeHandle) 592 { 593 594 int expandedTypeID = getExpandedTypeID(nodeHandle); 595 // If just testing nonzero, no need to shift... 596 int namespaceID = m_expandedNameTable.getNamespaceID(expandedTypeID); 597 598 if (0 == namespaceID) 599 { 600 // Don't retrieve name until/unless needed 601 // String name = m_expandedNameTable.getLocalName(expandedTypeID); 602 int type = getNodeType(nodeHandle); 603 604 if (type == DTM.NAMESPACE_NODE) 605 { 606 if (null == m_expandedNameTable.getLocalName(expandedTypeID)) 607 return "xmlns"; 608 else 609 return "xmlns:" + m_expandedNameTable.getLocalName(expandedTypeID); 610 } 611 else if (0 == m_expandedNameTable.getLocalNameID(expandedTypeID)) 612 { 613 return m_fixednames[type]; 614 } 615 else 616 return m_expandedNameTable.getLocalName(expandedTypeID); 617 } 618 else 619 { 620 int qnameIndex = m_dataOrQName.elementAt(makeNodeIdentity(nodeHandle)); 621 622 if (qnameIndex < 0) 623 { 624 qnameIndex = -qnameIndex; 625 qnameIndex = m_data.elementAt(qnameIndex); 626 } 627 628 return m_valuesOrPrefixes.indexToString(qnameIndex); 629 } 630 } 631 632 /** 633 * Given a node handle, return the XPath node name. This should be 634 * the name as described by the XPath data model, NOT the DOM-style 635 * name. 636 * 637 * @param nodeHandle the id of the node. 638 * @return String Name of this node, which may be an empty string. 639 */ 640 public String getNodeNameX(int nodeHandle) 641 { 642 643 int expandedTypeID = getExpandedTypeID(nodeHandle); 644 int namespaceID = m_expandedNameTable.getNamespaceID(expandedTypeID); 645 646 if (0 == namespaceID) 647 { 648 String name = m_expandedNameTable.getLocalName(expandedTypeID); 649 650 if (name == null) 651 return ""; 652 else 653 return name; 654 } 655 else 656 { 657 int qnameIndex = m_dataOrQName.elementAt(makeNodeIdentity(nodeHandle)); 658 659 if (qnameIndex < 0) 660 { 661 qnameIndex = -qnameIndex; 662 qnameIndex = m_data.elementAt(qnameIndex); 663 } 664 665 return m_valuesOrPrefixes.indexToString(qnameIndex); 666 } 667 } 668 669 /** 670 * 5. [specified] A flag indicating whether this attribute was actually 671 * specified in the start-tag of its element, or was defaulted from the 672 * DTD. 673 * 674 * @param attributeHandle Must be a valid handle to an attribute node. 675 * @return <code>true</code> if the attribute was specified; 676 * <code>false</code> if it was defaulted. 677 */ 678 public boolean isAttributeSpecified(int attributeHandle) 679 { 680 681 // I'm not sure if I want to do anything with this... 682 return true; // ?? 683 } 684 685 /** 686 * A document type declaration information item has the following properties: 687 * 688 * 1. [system identifier] The system identifier of the external subset, if 689 * it exists. Otherwise this property has no value. 690 * 691 * @return the system identifier String object, or null if there is none. 692 */ 693 public String getDocumentTypeDeclarationSystemIdentifier() 694 { 695 696 /** @todo: implement this org.apache.xml.dtm.DTMDefaultBase abstract method */ 697 error(XMLMessages.createXMLMessage(XMLErrorResources.ER_METHOD_NOT_SUPPORTED, null));//"Not yet supported!"); 698 699 return null; 700 } 701 702 /** 703 * Get the next node identity value in the list, and call the iterator 704 * if it hasn't been added yet. 705 * 706 * @param identity The node identity (index). 707 * @return identity+1, or DTM.NULL. 708 */ 709 protected int getNextNodeIdentity(int identity) 710 { 711 712 identity += 1; 713 714 while (identity >= m_size) 715 { 716 if (null == m_incrementalSAXSource) 717 return DTM.NULL; 718 719 nextNode(); 720 } 721 722 return identity; 723 } 724 725 /** 726 * Directly create SAX parser events from a subtree. 727 * 728 * @param nodeHandle The node ID. 729 * @param ch A non-null reference to a ContentHandler. 730 * 731 * @throws org.xml.sax.SAXException 732 */ 733 public void dispatchToEvents(int nodeHandle, org.xml.sax.ContentHandler ch) 734 throws org.xml.sax.SAXException 735 { 736 737 DTMTreeWalker treeWalker = m_walker; 738 ContentHandler prevCH = treeWalker.getcontentHandler(); 739 740 if (null != prevCH) 741 { 742 treeWalker = new DTMTreeWalker(); 743 } 744 745 treeWalker.setcontentHandler(ch); 746 treeWalker.setDTM(this); 747 748 try 749 { 750 treeWalker.traverse(nodeHandle); 751 } 752 finally 753 { 754 treeWalker.setcontentHandler(null); 755 } 756 } 757 758 /** 759 * Get the number of nodes that have been added. 760 * 761 * @return The number of that are currently in the tree. 762 */ 763 public int getNumberOfNodes() 764 { 765 return m_size; 766 } 767 768 /** 769 * This method should try and build one or more nodes in the table. 770 * 771 * @return The true if a next node is found or false if 772 * there are no more nodes. 773 */ 774 protected boolean nextNode() 775 { 776 777 if (null == m_incrementalSAXSource) 778 return false; 779 780 if (m_endDocumentOccured) 781 { 782 clearCoRoutine(); 783 784 return false; 785 } 786 787 Object gotMore = m_incrementalSAXSource.deliverMoreNodes(true); 788 789 // gotMore may be a Boolean (TRUE if still parsing, FALSE if 790 // EOF) or an exception if IncrementalSAXSource malfunctioned 791 // (code error rather than user error). 792 // 793 // %REVIEW% Currently the ErrorHandlers sketched herein are 794 // no-ops, so I'm going to initially leave this also as a 795 // no-op. 796 if (!(gotMore instanceof Boolean)) 797 { 798 if(gotMore instanceof RuntimeException) 799 { 800 throw (RuntimeException)gotMore; 801 } 802 else if(gotMore instanceof Exception) 803 { 804 throw new WrappedRuntimeException((Exception)gotMore); 805 } 806 // for now... 807 clearCoRoutine(); 808 809 return false; 810 811 // %TBD% 812 } 813 814 if (gotMore != Boolean.TRUE) 815 { 816 817 // EOF reached without satisfying the request 818 clearCoRoutine(); // Drop connection, stop trying 819 820 // %TBD% deregister as its listener? 821 } 822 823 return true; 824 } 825 826 /** 827 * Bottleneck determination of text type. 828 * 829 * @param type oneof DTM.XXX_NODE. 830 * 831 * @return true if this is a text or cdata section. 832 */ 833 private final boolean isTextType(int type) 834 { 835 return (DTM.TEXT_NODE == type || DTM.CDATA_SECTION_NODE == type); 836 } 837 838 // /** 839 // * Ensure that the size of the information arrays can hold another entry 840 // * at the given index. 841 // * 842 // * @param on exit from this function, the information arrays sizes must be 843 // * at least index+1. 844 // * 845 // * NEEDSDOC @param index 846 // */ 847 // protected void ensureSize(int index) 848 // { 849 // // dataOrQName is an SuballocatedIntVector and hence self-sizing. 850 // // But DTMDefaultBase may need fixup. 851 // super.ensureSize(index); 852 // } 853 854 /** 855 * Construct the node map from the node. 856 * 857 * @param type raw type ID, one of DTM.XXX_NODE. 858 * @param expandedTypeID The expended type ID. 859 * @param parentIndex The current parent index. 860 * @param previousSibling The previous sibling index. 861 * @param dataOrPrefix index into m_data table, or string handle. 862 * @param canHaveFirstChild true if the node can have a first child, false 863 * if it is atomic. 864 * 865 * @return The index identity of the node that was added. 866 */ 867 protected int addNode(int type, int expandedTypeID, 868 int parentIndex, int previousSibling, 869 int dataOrPrefix, boolean canHaveFirstChild) 870 { 871 // Common to all nodes: 872 int nodeIndex = m_size++; 873 874 // Have we overflowed a DTM Identity's addressing range? 875 if(m_dtmIdent.size() == (nodeIndex>>>DTMManager.IDENT_DTM_NODE_BITS)) 876 { 877 addNewDTMID(nodeIndex); 878 } 879 880 m_firstch.addElement(canHaveFirstChild ? NOTPROCESSED : DTM.NULL); 881 m_nextsib.addElement(NOTPROCESSED); 882 m_parent.addElement(parentIndex); 883 m_exptype.addElement(expandedTypeID); 884 m_dataOrQName.addElement(dataOrPrefix); 885 886 if (m_prevsib != null) { 887 m_prevsib.addElement(previousSibling); 888 } 889 890 if (DTM.NULL != previousSibling) { 891 m_nextsib.setElementAt(nodeIndex,previousSibling); 892 } 893 894 if (m_locator != null && m_useSourceLocationProperty) { 895 setSourceLocation(); 896 } 897 898 // Note that nextSibling is not processed until charactersFlush() 899 // is called, to handle successive characters() events. 900 901 // Special handling by type: Declare namespaces, attach first child 902 switch(type) 903 { 904 case DTM.NAMESPACE_NODE: 905 declareNamespaceInContext(parentIndex,nodeIndex); 906 break; 907 case DTM.ATTRIBUTE_NODE: 908 break; 909 default: 910 if (DTM.NULL == previousSibling && DTM.NULL != parentIndex) { 911 m_firstch.setElementAt(nodeIndex,parentIndex); 912 } 913 break; 914 } 915 916 return nodeIndex; 917 } 918 919 /** 920 * Get a new DTM ID beginning at the specified node index. 921 * @param nodeIndex The node identity at which the new DTM ID will begin 922 * addressing. 923 */ 924 protected void addNewDTMID(int nodeIndex) { 925 try 926 { 927 if(m_mgr==null) 928 throw new ClassCastException(); 929 930 // Handle as Extended Addressing 931 DTMManagerDefault mgrD=(DTMManagerDefault)m_mgr; 932 int id=mgrD.getFirstFreeDTMID(); 933 mgrD.addDTM(this,id,nodeIndex); 934 m_dtmIdent.addElement(id<<DTMManager.IDENT_DTM_NODE_BITS); 935 } 936 catch(ClassCastException e) 937 { 938 // %REVIEW% Wrong error message, but I've been told we're trying 939 // not to add messages right not for I18N reasons. 940 // %REVIEW% Should this be a Fatal Error? 941 error(XMLMessages.createXMLMessage(XMLErrorResources.ER_NO_DTMIDS_AVAIL, null));//"No more DTM IDs are available"; 942 } 943 } 944 945 /** 946 * Migrate a DTM built with an old DTMManager to a new DTMManager. 947 * After the migration, the new DTMManager will treat the DTM as 948 * one that is built by itself. 949 * This is used to support DTM sharing between multiple transformations. 950 * @param manager the DTMManager 951 */ 952 public void migrateTo(DTMManager manager) { 953 super.migrateTo(manager); 954 955 // We have to reset the information in m_dtmIdent and 956 // register the DTM with the new manager. 957 int numDTMs = m_dtmIdent.size(); 958 int dtmId = m_mgrDefault.getFirstFreeDTMID(); 959 int nodeIndex = 0; 960 for (int i = 0; i < numDTMs; i++) 961 { 962 m_dtmIdent.setElementAt(dtmId << DTMManager.IDENT_DTM_NODE_BITS, i); 963 m_mgrDefault.addDTM(this, dtmId, nodeIndex); 964 dtmId++; 965 nodeIndex += (1 << DTMManager.IDENT_DTM_NODE_BITS); 966 } 967 } 968 969 /** 970 * Store the source location of the current node. This method must be called 971 * as every node is added to the DTM or for no node. 972 */ 973 protected void setSourceLocation() { 974 m_sourceSystemId.addElement(m_locator.getSystemId()); 975 m_sourceLine.addElement(m_locator.getLineNumber()); 976 m_sourceColumn.addElement(m_locator.getColumnNumber()); 977 978 //%REVIEW% %BUG% Prevent this from arising in the first place 979 // by not allowing the enabling conditions to change after we start 980 // building the document. 981 if (m_sourceSystemId.size() != m_size) { 982 String msg = "CODING ERROR in Source Location: " + m_size + " != " 983 + m_sourceSystemId.size(); 984 System.err.println(msg); 985 throw new RuntimeException(msg); 986 } 987 } 988 989 /** 990 * Given a node handle, return its node value. This is mostly 991 * as defined by the DOM, but may ignore some conveniences. 992 * <p> 993 * 994 * @param nodeHandle The node id. 995 * @return String Value of this node, or null if not 996 * meaningful for this node type. 997 */ 998 public String getNodeValue(int nodeHandle) 999 { 1000 1001 int identity = makeNodeIdentity(nodeHandle); 1002 int type = _type(identity); 1003 1004 if (isTextType(type)) 1005 { 1006 int dataIndex = _dataOrQName(identity); 1007 int offset = m_data.elementAt(dataIndex); 1008 int length = m_data.elementAt(dataIndex + 1); 1009 1010 // %OPT% We should cache this, I guess. 1011 return m_chars.getString(offset, length); 1012 } 1013 else if (DTM.ELEMENT_NODE == type || DTM.DOCUMENT_FRAGMENT_NODE == type 1014 || DTM.DOCUMENT_NODE == type) 1015 { 1016 return null; 1017 } 1018 else 1019 { 1020 int dataIndex = _dataOrQName(identity); 1021 1022 if (dataIndex < 0) 1023 { 1024 dataIndex = -dataIndex; 1025 dataIndex = m_data.elementAt(dataIndex + 1); 1026 } 1027 1028 return m_valuesOrPrefixes.indexToString(dataIndex); 1029 } 1030 } 1031 1032 /** 1033 * Given a node handle, return its XPath-style localname. 1034 * (As defined in Namespaces, this is the portion of the name after any 1035 * colon character). 1036 * 1037 * @param nodeHandle the id of the node. 1038 * @return String Local name of this node. 1039 */ 1040 public String getLocalName(int nodeHandle) 1041 { 1042 return m_expandedNameTable.getLocalName(_exptype(makeNodeIdentity(nodeHandle))); 1043 } 1044 1045 /** 1046 * The getUnparsedEntityURI function returns the URI of the unparsed 1047 * entity with the specified name in the same document as the context 1048 * node (see [3.3 Unparsed Entities]). It returns the empty string if 1049 * there is no such entity. 1050 * <p> 1051 * XML processors may choose to use the System Identifier (if one 1052 * is provided) to resolve the entity, rather than the URI in the 1053 * Public Identifier. The details are dependent on the processor, and 1054 * we would have to support some form of plug-in resolver to handle 1055 * this properly. Currently, we simply return the System Identifier if 1056 * present, and hope that it a usable URI or that our caller can 1057 * map it to one. 1058 * TODO: Resolve Public Identifiers... or consider changing function name. 1059 * <p> 1060 * If we find a relative URI 1061 * reference, XML expects it to be resolved in terms of the base URI 1062 * of the document. The DOM doesn't do that for us, and it isn't 1063 * entirely clear whether that should be done here; currently that's 1064 * pushed up to a higher level of our application. (Note that DOM Level 1065 * 1 didn't store the document's base URI.) 1066 * TODO: Consider resolving Relative URIs. 1067 * <p> 1068 * (The DOM's statement that "An XML processor may choose to 1069 * completely expand entities before the structure model is passed 1070 * to the DOM" refers only to parsed entities, not unparsed, and hence 1071 * doesn't affect this function.) 1072 * 1073 * @param name A string containing the Entity Name of the unparsed 1074 * entity. 1075 * 1076 * @return String containing the URI of the Unparsed Entity, or an 1077 * empty string if no such entity exists. 1078 */ 1079 public String getUnparsedEntityURI(String name) 1080 { 1081 1082 String url = ""; 1083 1084 if (null == m_entities) 1085 return url; 1086 1087 int n = m_entities.size(); 1088 1089 for (int i = 0; i < n; i += ENTITY_FIELDS_PER) 1090 { 1091 String ename = (String) m_entities.elementAt(i + ENTITY_FIELD_NAME); 1092 1093 if (null != ename && ename.equals(name)) 1094 { 1095 String nname = (String) m_entities.elementAt(i 1096 + ENTITY_FIELD_NOTATIONNAME); 1097 1098 if (null != nname) 1099 { 1100 1101 // The draft says: "The XSLT processor may use the public 1102 // identifier to generate a URI for the entity instead of the URI 1103 // specified in the system identifier. If the XSLT processor does 1104 // not use the public identifier to generate the URI, it must use 1105 // the system identifier; if the system identifier is a relative 1106 // URI, it must be resolved into an absolute URI using the URI of 1107 // the resource containing the entity declaration as the base 1108 // URI [RFC2396]." 1109 // So I'm falling a bit short here. 1110 url = (String) m_entities.elementAt(i + ENTITY_FIELD_SYSTEMID); 1111 1112 if (null == url) 1113 { 1114 url = (String) m_entities.elementAt(i + ENTITY_FIELD_PUBLICID); 1115 } 1116 } 1117 1118 break; 1119 } 1120 } 1121 1122 return url; 1123 } 1124 1125 /** 1126 * Given a namespace handle, return the prefix that the namespace decl is 1127 * mapping. 1128 * Given a node handle, return the prefix used to map to the namespace. 1129 * 1130 * <p> %REVIEW% Are you sure you want "" for no prefix? </p> 1131 * <p> %REVIEW-COMMENT% I think so... not totally sure. -sb </p> 1132 * 1133 * @param nodeHandle the id of the node. 1134 * @return String prefix of this node's name, or "" if no explicit 1135 * namespace prefix was given. 1136 */ 1137 public String getPrefix(int nodeHandle) 1138 { 1139 1140 int identity = makeNodeIdentity(nodeHandle); 1141 int type = _type(identity); 1142 1143 if (DTM.ELEMENT_NODE == type) 1144 { 1145 int prefixIndex = _dataOrQName(identity); 1146 1147 if (0 == prefixIndex) 1148 return ""; 1149 else 1150 { 1151 String qname = m_valuesOrPrefixes.indexToString(prefixIndex); 1152 1153 return getPrefix(qname, null); 1154 } 1155 } 1156 else if (DTM.ATTRIBUTE_NODE == type) 1157 { 1158 int prefixIndex = _dataOrQName(identity); 1159 1160 if (prefixIndex < 0) 1161 { 1162 prefixIndex = m_data.elementAt(-prefixIndex); 1163 1164 String qname = m_valuesOrPrefixes.indexToString(prefixIndex); 1165 1166 return getPrefix(qname, null); 1167 } 1168 } 1169 1170 return ""; 1171 } 1172 1173 /** 1174 * Retrieves an attribute node by by qualified name and namespace URI. 1175 * 1176 * @param nodeHandle int Handle of the node upon which to look up this attribute.. 1177 * @param namespaceURI The namespace URI of the attribute to 1178 * retrieve, or null. 1179 * @param name The local name of the attribute to 1180 * retrieve. 1181 * @return The attribute node handle with the specified name ( 1182 * <code>nodeName</code>) or <code>DTM.NULL</code> if there is no such 1183 * attribute. 1184 */ 1185 public int getAttributeNode(int nodeHandle, String namespaceURI, 1186 String name) 1187 { 1188 1189 for (int attrH = getFirstAttribute(nodeHandle); DTM.NULL != attrH; 1190 attrH = getNextAttribute(attrH)) 1191 { 1192 String attrNS = getNamespaceURI(attrH); 1193 String attrName = getLocalName(attrH); 1194 boolean nsMatch = namespaceURI == attrNS 1195 || (namespaceURI != null 1196 && namespaceURI.equals(attrNS)); 1197 1198 if (nsMatch && name.equals(attrName)) 1199 return attrH; 1200 } 1201 1202 return DTM.NULL; 1203 } 1204 1205 /** 1206 * Return the public identifier of the external subset, 1207 * normalized as described in 4.2.2 External Entities [XML]. If there is 1208 * no external subset or if it has no public identifier, this property 1209 * has no value. 1210 * 1211 * @return the public identifier String object, or null if there is none. 1212 */ 1213 public String getDocumentTypeDeclarationPublicIdentifier() 1214 { 1215 1216 /** @todo: implement this org.apache.xml.dtm.DTMDefaultBase abstract method */ 1217 error(XMLMessages.createXMLMessage(XMLErrorResources.ER_METHOD_NOT_SUPPORTED, null));//"Not yet supported!"); 1218 1219 return null; 1220 } 1221 1222 /** 1223 * Given a node handle, return its DOM-style namespace URI 1224 * (As defined in Namespaces, this is the declared URI which this node's 1225 * prefix -- or default in lieu thereof -- was mapped to.) 1226 * 1227 * <p>%REVIEW% Null or ""? -sb</p> 1228 * 1229 * @param nodeHandle the id of the node. 1230 * @return String URI value of this node's namespace, or null if no 1231 * namespace was resolved. 1232 */ 1233 public String getNamespaceURI(int nodeHandle) 1234 { 1235 1236 return m_expandedNameTable.getNamespace(_exptype(makeNodeIdentity(nodeHandle))); 1237 } 1238 1239 /** 1240 * Get the string-value of a node as a String object 1241 * (see http://www.w3.org/TR/xpath#data-model 1242 * for the definition of a node's string-value). 1243 * 1244 * @param nodeHandle The node ID. 1245 * 1246 * @return A string object that represents the string-value of the given node. 1247 */ 1248 public XMLString getStringValue(int nodeHandle) 1249 { 1250 int identity = makeNodeIdentity(nodeHandle); 1251 int type; 1252 if(identity==DTM.NULL) // Separate lines because I wanted to breakpoint it 1253 type = DTM.NULL; 1254 else 1255 type= _type(identity); 1256 1257 if (isTextType(type)) 1258 { 1259 int dataIndex = _dataOrQName(identity); 1260 int offset = m_data.elementAt(dataIndex); 1261 int length = m_data.elementAt(dataIndex + 1); 1262 1263 return m_xstrf.newstr(m_chars, offset, length); 1264 } 1265 else 1266 { 1267 int firstChild = _firstch(identity); 1268 1269 if (DTM.NULL != firstChild) 1270 { 1271 int offset = -1; 1272 int length = 0; 1273 int startNode = identity; 1274 1275 identity = firstChild; 1276 1277 do { 1278 type = _type(identity); 1279 1280 if (isTextType(type)) 1281 { 1282 int dataIndex = _dataOrQName(identity); 1283 1284 if (-1 == offset) 1285 { 1286 offset = m_data.elementAt(dataIndex); 1287 } 1288 1289 length += m_data.elementAt(dataIndex + 1); 1290 } 1291 1292 identity = getNextNodeIdentity(identity); 1293 } while (DTM.NULL != identity && (_parent(identity) >= startNode)); 1294 1295 if (length > 0) 1296 { 1297 return m_xstrf.newstr(m_chars, offset, length); 1298 } 1299 } 1300 else if(type != DTM.ELEMENT_NODE) 1301 { 1302 int dataIndex = _dataOrQName(identity); 1303 1304 if (dataIndex < 0) 1305 { 1306 dataIndex = -dataIndex; 1307 dataIndex = m_data.elementAt(dataIndex + 1); 1308 } 1309 return m_xstrf.newstr(m_valuesOrPrefixes.indexToString(dataIndex)); 1310 } 1311 } 1312 1313 return m_xstrf.emptystr(); 1314 } 1315 1316 /** 1317 * Determine if the string-value of a node is whitespace 1318 * 1319 * @param nodeHandle The node Handle. 1320 * 1321 * @return Return true if the given node is whitespace. 1322 */ 1323 public boolean isWhitespace(int nodeHandle) 1324 { 1325 int identity = makeNodeIdentity(nodeHandle); 1326 int type; 1327 if(identity==DTM.NULL) // Separate lines because I wanted to breakpoint it 1328 type = DTM.NULL; 1329 else 1330 type= _type(identity); 1331 1332 if (isTextType(type)) 1333 { 1334 int dataIndex = _dataOrQName(identity); 1335 int offset = m_data.elementAt(dataIndex); 1336 int length = m_data.elementAt(dataIndex + 1); 1337 1338 return m_chars.isWhitespace(offset, length); 1339 } 1340 return false; 1341 } 1342 1343 /** 1344 * Returns the <code>Element</code> whose <code>ID</code> is given by 1345 * <code>elementId</code>. If no such element exists, returns 1346 * <code>DTM.NULL</code>. Behavior is not defined if more than one element 1347 * has this <code>ID</code>. Attributes (including those 1348 * with the name "ID") are not of type ID unless so defined by DTD/Schema 1349 * information available to the DTM implementation. 1350 * Implementations that do not know whether attributes are of type ID or 1351 * not are expected to return <code>DTM.NULL</code>. 1352 * 1353 * <p>%REVIEW% Presumably IDs are still scoped to a single document, 1354 * and this operation searches only within a single document, right? 1355 * Wouldn't want collisions between DTMs in the same process.</p> 1356 * 1357 * @param elementId The unique <code>id</code> value for an element. 1358 * @return The handle of the matching element. 1359 */ 1360 public int getElementById(String elementId) 1361 { 1362 1363 Integer intObj; 1364 boolean isMore = true; 1365 1366 do 1367 { 1368 intObj = (Integer) m_idAttributes.get(elementId); 1369 1370 if (null != intObj) 1371 return makeNodeHandle(intObj.intValue()); 1372 1373 if (!isMore || m_endDocumentOccured) 1374 break; 1375 1376 isMore = nextNode(); 1377 } 1378 while (null == intObj); 1379 1380 return DTM.NULL; 1381 } 1382 1383 /** 1384 * Get a prefix either from the qname or from the uri mapping, or just make 1385 * one up! 1386 * 1387 * @param qname The qualified name, which may be null. 1388 * @param uri The namespace URI, which may be null. 1389 * 1390 * @return The prefix if there is one, or null. 1391 */ 1392 public String getPrefix(String qname, String uri) 1393 { 1394 1395 String prefix; 1396 int uriIndex = -1; 1397 1398 if (null != uri && uri.length() > 0) 1399 { 1400 1401 do 1402 { 1403 uriIndex = m_prefixMappings.indexOf(uri, ++uriIndex); 1404 } while ( (uriIndex & 0x01) == 0); 1405 1406 if (uriIndex >= 0) 1407 { 1408 prefix = (String) m_prefixMappings.elementAt(uriIndex - 1); 1409 } 1410 else if (null != qname) 1411 { 1412 int indexOfNSSep = qname.indexOf(':'); 1413 1414 if (qname.equals("xmlns")) 1415 prefix = ""; 1416 else if (qname.startsWith("xmlns:")) 1417 prefix = qname.substring(indexOfNSSep + 1); 1418 else 1419 prefix = (indexOfNSSep > 0) 1420 ? qname.substring(0, indexOfNSSep) : null; 1421 } 1422 else 1423 { 1424 prefix = null; 1425 } 1426 } 1427 else if (null != qname) 1428 { 1429 int indexOfNSSep = qname.indexOf(':'); 1430 1431 if (indexOfNSSep > 0) 1432 { 1433 if (qname.startsWith("xmlns:")) 1434 prefix = qname.substring(indexOfNSSep + 1); 1435 else 1436 prefix = qname.substring(0, indexOfNSSep); 1437 } 1438 else 1439 { 1440 if (qname.equals("xmlns")) 1441 prefix = ""; 1442 else 1443 prefix = null; 1444 } 1445 } 1446 else 1447 { 1448 prefix = null; 1449 } 1450 1451 return prefix; 1452 } 1453 1454 /** 1455 * Get a prefix either from the uri mapping, or just make 1456 * one up! 1457 * 1458 * @param uri The namespace URI, which may be null. 1459 * 1460 * @return The prefix if there is one, or null. 1461 */ 1462 public int getIdForNamespace(String uri) 1463 { 1464 1465 return m_valuesOrPrefixes.stringToIndex(uri); 1466 1467 } 1468 1469 /** 1470 * Get a prefix either from the qname or from the uri mapping, or just make 1471 * one up! 1472 * 1473 * @return The prefix if there is one, or null. 1474 */ 1475 public String getNamespaceURI(String prefix) 1476 { 1477 1478 String uri = ""; 1479 int prefixIndex = m_contextIndexes.peek() - 1 ; 1480 1481 if(null == prefix) 1482 prefix = ""; 1483 1484 do 1485 { 1486 prefixIndex = m_prefixMappings.indexOf(prefix, ++prefixIndex); 1487 } while ( (prefixIndex >= 0) && (prefixIndex & 0x01) == 0x01); 1488 1489 if (prefixIndex > -1) 1490 { 1491 uri = (String) m_prefixMappings.elementAt(prefixIndex + 1); 1492 } 1493 1494 1495 return uri; 1496 } 1497 1498 /** 1499 * Set an ID string to node association in the ID table. 1500 * 1501 * @param id The ID string. 1502 * @param elem The associated element handle. 1503 */ 1504 public void setIDAttribute(String id, int elem) 1505 { 1506 m_idAttributes.put(id, new Integer(elem)); 1507 } 1508 1509 /** 1510 * Check whether accumulated text should be stripped; if not, 1511 * append the appropriate flavor of text/cdata node. 1512 */ 1513 protected void charactersFlush() 1514 { 1515 1516 if (m_textPendingStart >= 0) // -1 indicates no-text-in-progress 1517 { 1518 int length = m_chars.size() - m_textPendingStart; 1519 boolean doStrip = false; 1520 1521 if (getShouldStripWhitespace()) 1522 { 1523 doStrip = m_chars.isWhitespace(m_textPendingStart, length); 1524 } 1525 1526 if (doStrip) { 1527 m_chars.setLength(m_textPendingStart); // Discard accumulated text 1528 } else { 1529 // Guard against characters/ignorableWhitespace events that 1530 // contained no characters. They should not result in a node. 1531 if (length > 0) { 1532 int exName = m_expandedNameTable.getExpandedTypeID(DTM.TEXT_NODE); 1533 int dataIndex = m_data.size(); 1534 1535 m_previous = addNode(m_coalescedTextType, exName, 1536 m_parents.peek(), m_previous, dataIndex, false); 1537 1538 m_data.addElement(m_textPendingStart); 1539 m_data.addElement(length); 1540 } 1541 } 1542 1543 // Reset for next text block 1544 m_textPendingStart = -1; 1545 m_textType = m_coalescedTextType = DTM.TEXT_NODE; 1546 } 1547 } 1548 1549 //////////////////////////////////////////////////////////////////// 1550 // Implementation of the EntityResolver interface. 1551 //////////////////////////////////////////////////////////////////// 1552 1553 /** 1554 * Resolve an external entity. 1555 * 1556 * <p>Always return null, so that the parser will use the system 1557 * identifier provided in the XML document. This method implements 1558 * the SAX default behaviour: application writers can override it 1559 * in a subclass to do special translations such as catalog lookups 1560 * or URI redirection.</p> 1561 * 1562 * @param publicId The public identifer, or null if none is 1563 * available. 1564 * @param systemId The system identifier provided in the XML 1565 * document. 1566 * @return The new input source, or null to require the 1567 * default behaviour. 1568 * @throws SAXException Any SAX exception, possibly 1569 * wrapping another exception. 1570 * @see org.xml.sax.EntityResolver#resolveEntity 1571 * 1572 * @throws SAXException 1573 */ 1574 public InputSource resolveEntity(String publicId, String systemId) 1575 throws SAXException 1576 { 1577 return null; 1578 } 1579 1580 //////////////////////////////////////////////////////////////////// 1581 // Implementation of DTDHandler interface. 1582 //////////////////////////////////////////////////////////////////// 1583 1584 /** 1585 * Receive notification of a notation declaration. 1586 * 1587 * <p>By default, do nothing. Application writers may override this 1588 * method in a subclass if they wish to keep track of the notations 1589 * declared in a document.</p> 1590 * 1591 * @param name The notation name. 1592 * @param publicId The notation public identifier, or null if not 1593 * available. 1594 * @param systemId The notation system identifier. 1595 * @throws SAXException Any SAX exception, possibly 1596 * wrapping another exception. 1597 * @see org.xml.sax.DTDHandler#notationDecl 1598 * 1599 * @throws SAXException 1600 */ 1601 public void notationDecl(String name, String publicId, String systemId) 1602 throws SAXException 1603 { 1604 1605 // no op 1606 } 1607 1608 /** 1609 * Receive notification of an unparsed entity declaration. 1610 * 1611 * <p>By default, do nothing. Application writers may override this 1612 * method in a subclass to keep track of the unparsed entities 1613 * declared in a document.</p> 1614 * 1615 * @param name The entity name. 1616 * @param publicId The entity public identifier, or null if not 1617 * available. 1618 * @param systemId The entity system identifier. 1619 * @param notationName The name of the associated notation. 1620 * @throws SAXException Any SAX exception, possibly 1621 * wrapping another exception. 1622 * @see org.xml.sax.DTDHandler#unparsedEntityDecl 1623 * 1624 * @throws SAXException 1625 */ 1626 public void unparsedEntityDecl( 1627 String name, String publicId, String systemId, String notationName) 1628 throws SAXException 1629 { 1630 1631 if (null == m_entities) 1632 { 1633 m_entities = new Vector(); 1634 } 1635 1636 try 1637 { 1638 systemId = SystemIDResolver.getAbsoluteURI(systemId, 1639 getDocumentBaseURI()); 1640 } 1641 catch (Exception e) 1642 { 1643 throw new org.xml.sax.SAXException(e); 1644 } 1645 1646 // private static final int ENTITY_FIELD_PUBLICID = 0; 1647 m_entities.addElement(publicId); 1648 1649 // private static final int ENTITY_FIELD_SYSTEMID = 1; 1650 m_entities.addElement(systemId); 1651 1652 // private static final int ENTITY_FIELD_NOTATIONNAME = 2; 1653 m_entities.addElement(notationName); 1654 1655 // private static final int ENTITY_FIELD_NAME = 3; 1656 m_entities.addElement(name); 1657 } 1658 1659 //////////////////////////////////////////////////////////////////// 1660 // Implementation of ContentHandler interface. 1661 //////////////////////////////////////////////////////////////////// 1662 1663 /** 1664 * Receive a Locator object for document events. 1665 * 1666 * <p>By default, do nothing. Application writers may override this 1667 * method in a subclass if they wish to store the locator for use 1668 * with other document events.</p> 1669 * 1670 * @param locator A locator for all SAX document events. 1671 * @see org.xml.sax.ContentHandler#setDocumentLocator 1672 * @see org.xml.sax.Locator 1673 */ 1674 public void setDocumentLocator(Locator locator) 1675 { 1676 m_locator = locator; 1677 m_systemId = locator.getSystemId(); 1678 } 1679 1680 /** 1681 * Receive notification of the beginning of the document. 1682 * 1683 * @throws SAXException Any SAX exception, possibly 1684 * wrapping another exception. 1685 * @see org.xml.sax.ContentHandler#startDocument 1686 */ 1687 public void startDocument() throws SAXException 1688 { 1689 if (DEBUG) 1690 System.out.println("startDocument"); 1691 1692 1693 int doc = addNode(DTM.DOCUMENT_NODE, 1694 m_expandedNameTable.getExpandedTypeID(DTM.DOCUMENT_NODE), 1695 DTM.NULL, DTM.NULL, 0, true); 1696 1697 m_parents.push(doc); 1698 m_previous = DTM.NULL; 1699 1700 m_contextIndexes.push(m_prefixMappings.size()); // for the next element. 1701 } 1702 1703 /** 1704 * Receive notification of the end of the document. 1705 * 1706 * @throws SAXException Any SAX exception, possibly 1707 * wrapping another exception. 1708 * @see org.xml.sax.ContentHandler#endDocument 1709 */ 1710 public void endDocument() throws SAXException 1711 { 1712 if (DEBUG) 1713 System.out.println("endDocument"); 1714 1715 charactersFlush(); 1716 1717 m_nextsib.setElementAt(NULL,0); 1718 1719 if (m_firstch.elementAt(0) == NOTPROCESSED) 1720 m_firstch.setElementAt(NULL,0); 1721 1722 if (DTM.NULL != m_previous) 1723 m_nextsib.setElementAt(DTM.NULL,m_previous); 1724 1725 m_parents = null; 1726 m_prefixMappings = null; 1727 m_contextIndexes = null; 1728 1729 m_endDocumentOccured = true; 1730 1731 // Bugzilla 4858: throw away m_locator. we cache m_systemId 1732 m_locator = null; 1733 } 1734 1735 /** 1736 * Receive notification of the start of a Namespace mapping. 1737 * 1738 * <p>By default, do nothing. Application writers may override this 1739 * method in a subclass to take specific actions at the start of 1740 * each Namespace prefix scope (such as storing the prefix mapping).</p> 1741 * 1742 * @param prefix The Namespace prefix being declared. 1743 * @param uri The Namespace URI mapped to the prefix. 1744 * @throws SAXException Any SAX exception, possibly 1745 * wrapping another exception. 1746 * @see org.xml.sax.ContentHandler#startPrefixMapping 1747 */ 1748 public void startPrefixMapping(String prefix, String uri) 1749 throws SAXException 1750 { 1751 1752 if (DEBUG) 1753 System.out.println("startPrefixMapping: prefix: " + prefix + ", uri: " 1754 + uri); 1755 1756 if(null == prefix) 1757 prefix = ""; 1758 m_prefixMappings.addElement(prefix); // JDK 1.1.x compat -sc 1759 m_prefixMappings.addElement(uri); // JDK 1.1.x compat -sc 1760 } 1761 1762 /** 1763 * Receive notification of the end of a Namespace mapping. 1764 * 1765 * <p>By default, do nothing. Application writers may override this 1766 * method in a subclass to take specific actions at the end of 1767 * each prefix mapping.</p> 1768 * 1769 * @param prefix The Namespace prefix being declared. 1770 * @throws SAXException Any SAX exception, possibly 1771 * wrapping another exception. 1772 * @see org.xml.sax.ContentHandler#endPrefixMapping 1773 */ 1774 public void endPrefixMapping(String prefix) throws SAXException 1775 { 1776 if (DEBUG) 1777 System.out.println("endPrefixMapping: prefix: " + prefix); 1778 1779 if(null == prefix) 1780 prefix = ""; 1781 1782 int index = m_contextIndexes.peek() - 1; 1783 1784 do 1785 { 1786 index = m_prefixMappings.indexOf(prefix, ++index); 1787 } while ( (index >= 0) && ((index & 0x01) == 0x01) ); 1788 1789 1790 if (index > -1) 1791 { 1792 m_prefixMappings.setElementAt("%@$#^@#", index); 1793 m_prefixMappings.setElementAt("%@$#^@#", index + 1); 1794 } 1795 1796 // no op 1797 } 1798 1799 /** 1800 * Check if a declaration has already been made for a given prefix. 1801 * 1802 * @param prefix non-null prefix string. 1803 * 1804 * @return true if the declaration has already been declared in the 1805 * current context. 1806 */ 1807 protected boolean declAlreadyDeclared(String prefix) 1808 { 1809 1810 int startDecls = m_contextIndexes.peek(); 1811 java.util.Vector prefixMappings = m_prefixMappings; 1812 int nDecls = prefixMappings.size(); 1813 1814 for (int i = startDecls; i < nDecls; i += 2) 1815 { 1816 String prefixDecl = (String) prefixMappings.elementAt(i); 1817 1818 if (prefixDecl == null) 1819 continue; 1820 1821 if (prefixDecl.equals(prefix)) 1822 return true; 1823 } 1824 1825 return false; 1826 } 1827 1828 boolean m_pastFirstElement=false; 1829 1830 /** 1831 * Receive notification of the start of an element. 1832 * 1833 * <p>By default, do nothing. Application writers may override this 1834 * method in a subclass to take specific actions at the start of 1835 * each element (such as allocating a new tree node or writing 1836 * output to a file).</p> 1837 * 1838 * @param uri The Namespace URI, or the empty string if the 1839 * element has no Namespace URI or if Namespace 1840 * processing is not being performed. 1841 * @param localName The local name (without prefix), or the 1842 * empty string if Namespace processing is not being 1843 * performed. 1844 * @param qName The qualified name (with prefix), or the 1845 * empty string if qualified names are not available. 1846 * @param attributes The specified or defaulted attributes. 1847 * @throws SAXException Any SAX exception, possibly 1848 * wrapping another exception. 1849 * @see org.xml.sax.ContentHandler#startElement 1850 */ 1851 public void startElement( 1852 String uri, String localName, String qName, Attributes attributes) 1853 throws SAXException 1854 { 1855 if (DEBUG) 1856 { 1857 System.out.println("startElement: uri: " + uri + ", localname: " 1858 + localName + ", qname: "+qName+", atts: " + attributes); 1859 1860 boolean DEBUG_ATTRS=true; 1861 if(DEBUG_ATTRS & attributes!=null) 1862 { 1863 int n = attributes.getLength(); 1864 if(n==0) 1865 System.out.println("\tempty attribute list"); 1866 else for (int i = 0; i < n; i++) 1867 System.out.println("\t attr: uri: " + attributes.getURI(i) + 1868 ", localname: " + attributes.getLocalName(i) + 1869 ", qname: " + attributes.getQName(i) + 1870 ", type: " + attributes.getType(i) + 1871 ", value: " + attributes.getValue(i) 1872 ); 1873 } 1874 } 1875 1876 charactersFlush(); 1877 1878 int exName = m_expandedNameTable.getExpandedTypeID(uri, localName, DTM.ELEMENT_NODE); 1879 String prefix = getPrefix(qName, uri); 1880 int prefixIndex = (null != prefix) 1881 ? m_valuesOrPrefixes.stringToIndex(qName) : 0; 1882 1883 int elemNode = addNode(DTM.ELEMENT_NODE, exName, 1884 m_parents.peek(), m_previous, prefixIndex, true); 1885 1886 if(m_indexing) 1887 indexNode(exName, elemNode); 1888 1889 1890 m_parents.push(elemNode); 1891 1892 int startDecls = m_contextIndexes.peek(); 1893 int nDecls = m_prefixMappings.size(); 1894 int prev = DTM.NULL; 1895 1896 if(!m_pastFirstElement) 1897 { 1898 // SPECIAL CASE: Implied declaration at root element 1899 prefix="xml"; 1900 String declURL = "http://www.w3.org/XML/1998/namespace"; 1901 exName = m_expandedNameTable.getExpandedTypeID(null, prefix, DTM.NAMESPACE_NODE); 1902 int val = m_valuesOrPrefixes.stringToIndex(declURL); 1903 prev = addNode(DTM.NAMESPACE_NODE, exName, elemNode, 1904 prev, val, false); 1905 m_pastFirstElement=true; 1906 } 1907 1908 for (int i = startDecls; i < nDecls; i += 2) 1909 { 1910 prefix = (String) m_prefixMappings.elementAt(i); 1911 1912 if (prefix == null) 1913 continue; 1914 1915 String declURL = (String) m_prefixMappings.elementAt(i + 1); 1916 1917 exName = m_expandedNameTable.getExpandedTypeID(null, prefix, DTM.NAMESPACE_NODE); 1918 1919 int val = m_valuesOrPrefixes.stringToIndex(declURL); 1920 1921 prev = addNode(DTM.NAMESPACE_NODE, exName, elemNode, 1922 prev, val, false); 1923 } 1924 1925 int n = attributes.getLength(); 1926 1927 for (int i = 0; i < n; i++) 1928 { 1929 String attrUri = attributes.getURI(i); 1930 String attrQName = attributes.getQName(i); 1931 String valString = attributes.getValue(i); 1932 1933 prefix = getPrefix(attrQName, attrUri); 1934 1935 int nodeType; 1936 1937 String attrLocalName = attributes.getLocalName(i); 1938 1939 if ((null != attrQName) 1940 && (attrQName.equals("xmlns") 1941 || attrQName.startsWith("xmlns:"))) 1942 { 1943 if (declAlreadyDeclared(prefix)) 1944 continue; // go to the next attribute. 1945 1946 nodeType = DTM.NAMESPACE_NODE; 1947 } 1948 else 1949 { 1950 nodeType = DTM.ATTRIBUTE_NODE; 1951 1952 if (attributes.getType(i).equalsIgnoreCase("ID")) 1953 setIDAttribute(valString, elemNode); 1954 } 1955 1956 // Bit of a hack... if somehow valString is null, stringToIndex will 1957 // return -1, which will make things very unhappy. 1958 if(null == valString) 1959 valString = ""; 1960 1961 int val = m_valuesOrPrefixes.stringToIndex(valString); 1962 //String attrLocalName = attributes.getLocalName(i); 1963 1964 if (null != prefix) 1965 { 1966 1967 prefixIndex = m_valuesOrPrefixes.stringToIndex(attrQName); 1968 1969 int dataIndex = m_data.size(); 1970 1971 m_data.addElement(prefixIndex); 1972 m_data.addElement(val); 1973 1974 val = -dataIndex; 1975 } 1976 1977 exName = m_expandedNameTable.getExpandedTypeID(attrUri, attrLocalName, nodeType); 1978 prev = addNode(nodeType, exName, elemNode, prev, val, 1979 false); 1980 } 1981 1982 if (DTM.NULL != prev) 1983 m_nextsib.setElementAt(DTM.NULL,prev); 1984 1985 if (null != m_wsfilter) 1986 { 1987 short wsv = m_wsfilter.getShouldStripSpace(makeNodeHandle(elemNode), this); 1988 boolean shouldStrip = (DTMWSFilter.INHERIT == wsv) 1989 ? getShouldStripWhitespace() 1990 : (DTMWSFilter.STRIP == wsv); 1991 1992 pushShouldStripWhitespace(shouldStrip); 1993 } 1994 1995 m_previous = DTM.NULL; 1996 1997 m_contextIndexes.push(m_prefixMappings.size()); // for the children. 1998 } 1999 2000 /** 2001 * Receive notification of the end of an element. 2002 * 2003 * <p>By default, do nothing. Application writers may override this 2004 * method in a subclass to take specific actions at the end of 2005 * each element (such as finalising a tree node or writing 2006 * output to a file).</p> 2007 * 2008 * @param uri The Namespace URI, or the empty string if the 2009 * element has no Namespace URI or if Namespace 2010 * processing is not being performed. 2011 * @param localName The local name (without prefix), or the 2012 * empty string if Namespace processing is not being 2013 * performed. 2014 * @param qName The qualified XML 1.0 name (with prefix), or the 2015 * empty string if qualified names are not available. 2016 * @throws SAXException Any SAX exception, possibly 2017 * wrapping another exception. 2018 * @see org.xml.sax.ContentHandler#endElement 2019 */ 2020 public void endElement(String uri, String localName, String qName) 2021 throws SAXException 2022 { 2023 if (DEBUG) 2024 System.out.println("endElement: uri: " + uri + ", localname: " 2025 + localName + ", qname: "+qName); 2026 2027 charactersFlush(); 2028 2029 // If no one noticed, startPrefixMapping is a drag. 2030 // Pop the context for the last child (the one pushed by startElement) 2031 m_contextIndexes.quickPop(1); 2032 2033 // Do it again for this one (the one pushed by the last endElement). 2034 int topContextIndex = m_contextIndexes.peek(); 2035 if (topContextIndex != m_prefixMappings.size()) { 2036 m_prefixMappings.setSize(topContextIndex); 2037 } 2038 2039 int lastNode = m_previous; 2040 2041 m_previous = m_parents.pop(); 2042 2043 // If lastNode is still DTM.NULL, this element had no children 2044 if (DTM.NULL == lastNode) 2045 m_firstch.setElementAt(DTM.NULL,m_previous); 2046 else 2047 m_nextsib.setElementAt(DTM.NULL,lastNode); 2048 2049 popShouldStripWhitespace(); 2050 } 2051 2052 /** 2053 * Receive notification of character data inside an element. 2054 * 2055 * <p>By default, do nothing. Application writers may override this 2056 * method to take specific actions for each chunk of character data 2057 * (such as adding the data to a node or buffer, or printing it to 2058 * a file).</p> 2059 * 2060 * @param ch The characters. 2061 * @param start The start position in the character array. 2062 * @param length The number of characters to use from the 2063 * character array. 2064 * @throws SAXException Any SAX exception, possibly 2065 * wrapping another exception. 2066 * @see org.xml.sax.ContentHandler#characters 2067 */ 2068 public void characters(char ch[], int start, int length) throws SAXException 2069 { 2070 if (m_textPendingStart == -1) // First one in this block 2071 { 2072 m_textPendingStart = m_chars.size(); 2073 m_coalescedTextType = m_textType; 2074 } 2075 // Type logic: If all adjacent text is CDATASections, the 2076 // concatentated text is treated as a single CDATASection (see 2077 // initialization above). If any were ordinary Text, the whole 2078 // thing is treated as Text. This may be worth %REVIEW%ing. 2079 else if (m_textType == DTM.TEXT_NODE) 2080 { 2081 m_coalescedTextType = DTM.TEXT_NODE; 2082 } 2083 2084 m_chars.append(ch, start, length); 2085 } 2086 2087 /** 2088 * Receive notification of ignorable whitespace in element content. 2089 * 2090 * <p>By default, do nothing. Application writers may override this 2091 * method to take specific actions for each chunk of ignorable 2092 * whitespace (such as adding data to a node or buffer, or printing 2093 * it to a file).</p> 2094 * 2095 * @param ch The whitespace characters. 2096 * @param start The start position in the character array. 2097 * @param length The number of characters to use from the 2098 * character array. 2099 * @throws SAXException Any SAX exception, possibly 2100 * wrapping another exception. 2101 * @see org.xml.sax.ContentHandler#ignorableWhitespace 2102 */ 2103 public void ignorableWhitespace(char ch[], int start, int length) 2104 throws SAXException 2105 { 2106 2107 // %OPT% We can probably take advantage of the fact that we know this 2108 // is whitespace. 2109 characters(ch, start, length); 2110 } 2111 2112 /** 2113 * Receive notification of a processing instruction. 2114 * 2115 * <p>By default, do nothing. Application writers may override this 2116 * method in a subclass to take specific actions for each 2117 * processing instruction, such as setting status variables or 2118 * invoking other methods.</p> 2119 * 2120 * @param target The processing instruction target. 2121 * @param data The processing instruction data, or null if 2122 * none is supplied. 2123 * @throws SAXException Any SAX exception, possibly 2124 * wrapping another exception. 2125 * @see org.xml.sax.ContentHandler#processingInstruction 2126 */ 2127 public void processingInstruction(String target, String data) 2128 throws SAXException 2129 { 2130 if (DEBUG) 2131 System.out.println("processingInstruction: target: " + target +", data: "+data); 2132 2133 charactersFlush(); 2134 2135 int exName = m_expandedNameTable.getExpandedTypeID(null, target, 2136 DTM.PROCESSING_INSTRUCTION_NODE); 2137 int dataIndex = m_valuesOrPrefixes.stringToIndex(data); 2138 2139 m_previous = addNode(DTM.PROCESSING_INSTRUCTION_NODE, exName, 2140 m_parents.peek(), m_previous, 2141 dataIndex, false); 2142 } 2143 2144 /** 2145 * Receive notification of a skipped entity. 2146 * 2147 * <p>By default, do nothing. Application writers may override this 2148 * method in a subclass to take specific actions for each 2149 * processing instruction, such as setting status variables or 2150 * invoking other methods.</p> 2151 * 2152 * @param name The name of the skipped entity. 2153 * @throws SAXException Any SAX exception, possibly 2154 * wrapping another exception. 2155 * @see org.xml.sax.ContentHandler#processingInstruction 2156 */ 2157 public void skippedEntity(String name) throws SAXException 2158 { 2159 2160 // %REVIEW% What should be done here? 2161 // no op 2162 } 2163 2164 //////////////////////////////////////////////////////////////////// 2165 // Implementation of the ErrorHandler interface. 2166 //////////////////////////////////////////////////////////////////// 2167 2168 /** 2169 * Receive notification of a parser warning. 2170 * 2171 * <p>The default implementation does nothing. Application writers 2172 * may override this method in a subclass to take specific actions 2173 * for each warning, such as inserting the message in a log file or 2174 * printing it to the console.</p> 2175 * 2176 * @param e The warning information encoded as an exception. 2177 * @throws SAXException Any SAX exception, possibly 2178 * wrapping another exception. 2179 * @see org.xml.sax.ErrorHandler#warning 2180 * @see org.xml.sax.SAXParseException 2181 */ 2182 public void warning(SAXParseException e) throws SAXException 2183 { 2184 2185 // %REVIEW% Is there anyway to get the JAXP error listener here? 2186 System.err.println(e.getMessage()); 2187 } 2188 2189 /** 2190 * Receive notification of a recoverable parser error. 2191 * 2192 * <p>The default implementation does nothing. Application writers 2193 * may override this method in a subclass to take specific actions 2194 * for each error, such as inserting the message in a log file or 2195 * printing it to the console.</p> 2196 * 2197 * @param e The warning information encoded as an exception. 2198 * @throws SAXException Any SAX exception, possibly 2199 * wrapping another exception. 2200 * @see org.xml.sax.ErrorHandler#warning 2201 * @see org.xml.sax.SAXParseException 2202 */ 2203 public void error(SAXParseException e) throws SAXException 2204 { 2205 throw e; 2206 } 2207 2208 /** 2209 * Report a fatal XML parsing error. 2210 * 2211 * <p>The default implementation throws a SAXParseException. 2212 * Application writers may override this method in a subclass if 2213 * they need to take specific actions for each fatal error (such as 2214 * collecting all of the errors into a single report): in any case, 2215 * the application must stop all regular processing when this 2216 * method is invoked, since the document is no longer reliable, and 2217 * the parser may no longer report parsing events.</p> 2218 * 2219 * @param e The error information encoded as an exception. 2220 * @throws SAXException Any SAX exception, possibly 2221 * wrapping another exception. 2222 * @see org.xml.sax.ErrorHandler#fatalError 2223 * @see org.xml.sax.SAXParseException 2224 */ 2225 public void fatalError(SAXParseException e) throws SAXException 2226 { 2227 throw e; 2228 } 2229 2230 //////////////////////////////////////////////////////////////////// 2231 // Implementation of the DeclHandler interface. 2232 //////////////////////////////////////////////////////////////////// 2233 2234 /** 2235 * Report an element type declaration. 2236 * 2237 * <p>The content model will consist of the string "EMPTY", the 2238 * string "ANY", or a parenthesised group, optionally followed 2239 * by an occurrence indicator. The model will be normalized so 2240 * that all whitespace is removed,and will include the enclosing 2241 * parentheses.</p> 2242 * 2243 * @param name The element type name. 2244 * @param model The content model as a normalized string. 2245 * @throws SAXException The application may raise an exception. 2246 */ 2247 public void elementDecl(String name, String model) throws SAXException 2248 { 2249 2250 // no op 2251 } 2252 2253 /** 2254 * Report an attribute type declaration. 2255 * 2256 * <p>Only the effective (first) declaration for an attribute will 2257 * be reported. The type will be one of the strings "CDATA", 2258 * "ID", "IDREF", "IDREFS", "NMTOKEN", "NMTOKENS", "ENTITY", 2259 * "ENTITIES", or "NOTATION", or a parenthesized token group with 2260 * the separator "|" and all whitespace removed.</p> 2261 * 2262 * @param eName The name of the associated element. 2263 * @param aName The name of the attribute. 2264 * @param type A string representing the attribute type. 2265 * @param valueDefault A string representing the attribute default 2266 * ("#IMPLIED", "#REQUIRED", or "#FIXED") or null if 2267 * none of these applies. 2268 * @param value A string representing the attribute's default value, 2269 * or null if there is none. 2270 * @throws SAXException The application may raise an exception. 2271 */ 2272 public void attributeDecl( 2273 String eName, String aName, String type, String valueDefault, String value) 2274 throws SAXException 2275 { 2276 2277 // no op 2278 } 2279 2280 /** 2281 * Report an internal entity declaration. 2282 * 2283 * <p>Only the effective (first) declaration for each entity 2284 * will be reported.</p> 2285 * 2286 * @param name The name of the entity. If it is a parameter 2287 * entity, the name will begin with '%'. 2288 * @param value The replacement text of the entity. 2289 * @throws SAXException The application may raise an exception. 2290 * @see #externalEntityDecl 2291 * @see org.xml.sax.DTDHandler#unparsedEntityDecl 2292 */ 2293 public void internalEntityDecl(String name, String value) 2294 throws SAXException 2295 { 2296 2297 // no op 2298 } 2299 2300 /** 2301 * Report a parsed external entity declaration. 2302 * 2303 * <p>Only the effective (first) declaration for each entity 2304 * will be reported.</p> 2305 * 2306 * @param name The name of the entity. If it is a parameter 2307 * entity, the name will begin with '%'. 2308 * @param publicId The declared public identifier of the entity, or 2309 * null if none was declared. 2310 * @param systemId The declared system identifier of the entity. 2311 * @throws SAXException The application may raise an exception. 2312 * @see #internalEntityDecl 2313 * @see org.xml.sax.DTDHandler#unparsedEntityDecl 2314 */ 2315 public void externalEntityDecl( 2316 String name, String publicId, String systemId) throws SAXException 2317 { 2318 2319 // no op 2320 } 2321 2322 //////////////////////////////////////////////////////////////////// 2323 // Implementation of the LexicalHandler interface. 2324 //////////////////////////////////////////////////////////////////// 2325 2326 /** 2327 * Report the start of DTD declarations, if any. 2328 * 2329 * <p>Any declarations are assumed to be in the internal subset 2330 * unless otherwise indicated by a {@link #startEntity startEntity} 2331 * event.</p> 2332 * 2333 * <p>Note that the start/endDTD events will appear within 2334 * the start/endDocument events from ContentHandler and 2335 * before the first startElement event.</p> 2336 * 2337 * @param name The document type name. 2338 * @param publicId The declared public identifier for the 2339 * external DTD subset, or null if none was declared. 2340 * @param systemId The declared system identifier for the 2341 * external DTD subset, or null if none was declared. 2342 * @throws SAXException The application may raise an 2343 * exception. 2344 * @see #endDTD 2345 * @see #startEntity 2346 */ 2347 public void startDTD(String name, String publicId, String systemId) 2348 throws SAXException 2349 { 2350 2351 m_insideDTD = true; 2352 } 2353 2354 /** 2355 * Report the end of DTD declarations. 2356 * 2357 * @throws SAXException The application may raise an exception. 2358 * @see #startDTD 2359 */ 2360 public void endDTD() throws SAXException 2361 { 2362 2363 m_insideDTD = false; 2364 } 2365 2366 /** 2367 * Report the beginning of an entity in content. 2368 * 2369 * <p><strong>NOTE:</entity> entity references in attribute 2370 * values -- and the start and end of the document entity -- 2371 * are never reported.</p> 2372 * 2373 * <p>The start and end of the external DTD subset are reported 2374 * using the pseudo-name "[dtd]". All other events must be 2375 * properly nested within start/end entity events.</p> 2376 * 2377 * <p>Note that skipped entities will be reported through the 2378 * {@link org.xml.sax.ContentHandler#skippedEntity skippedEntity} 2379 * event, which is part of the ContentHandler interface.</p> 2380 * 2381 * @param name The name of the entity. If it is a parameter 2382 * entity, the name will begin with '%'. 2383 * @throws SAXException The application may raise an exception. 2384 * @see #endEntity 2385 * @see org.xml.sax.ext.DeclHandler#internalEntityDecl 2386 * @see org.xml.sax.ext.DeclHandler#externalEntityDecl 2387 */ 2388 public void startEntity(String name) throws SAXException 2389 { 2390 2391 // no op 2392 } 2393 2394 /** 2395 * Report the end of an entity. 2396 * 2397 * @param name The name of the entity that is ending. 2398 * @throws SAXException The application may raise an exception. 2399 * @see #startEntity 2400 */ 2401 public void endEntity(String name) throws SAXException 2402 { 2403 2404 // no op 2405 } 2406 2407 /** 2408 * Report the start of a CDATA section. 2409 * 2410 * <p>The contents of the CDATA section will be reported through 2411 * the regular {@link org.xml.sax.ContentHandler#characters 2412 * characters} event.</p> 2413 * 2414 * @throws SAXException The application may raise an exception. 2415 * @see #endCDATA 2416 */ 2417 public void startCDATA() throws SAXException 2418 { 2419 m_textType = DTM.CDATA_SECTION_NODE; 2420 } 2421 2422 /** 2423 * Report the end of a CDATA section. 2424 * 2425 * @throws SAXException The application may raise an exception. 2426 * @see #startCDATA 2427 */ 2428 public void endCDATA() throws SAXException 2429 { 2430 m_textType = DTM.TEXT_NODE; 2431 } 2432 2433 /** 2434 * Report an XML comment anywhere in the document. 2435 * 2436 * <p>This callback will be used for comments inside or outside the 2437 * document element, including comments in the external DTD 2438 * subset (if read).</p> 2439 * 2440 * @param ch An array holding the characters in the comment. 2441 * @param start The starting position in the array. 2442 * @param length The number of characters to use from the array. 2443 * @throws SAXException The application may raise an exception. 2444 */ 2445 public void comment(char ch[], int start, int length) throws SAXException 2446 { 2447 2448 if (m_insideDTD) // ignore comments if we're inside the DTD 2449 return; 2450 2451 charactersFlush(); 2452 2453 int exName = m_expandedNameTable.getExpandedTypeID(DTM.COMMENT_NODE); 2454 2455 // For now, treat comments as strings... I guess we should do a 2456 // seperate FSB buffer instead. 2457 int dataIndex = m_valuesOrPrefixes.stringToIndex(new String(ch, start, 2458 length)); 2459 2460 2461 m_previous = addNode(DTM.COMMENT_NODE, exName, 2462 m_parents.peek(), m_previous, dataIndex, false); 2463 } 2464 2465 /** 2466 * Set a run time property for this DTM instance. 2467 * 2468 * %REVIEW% Now that we no longer use this method to support 2469 * getSourceLocatorFor, can we remove it? 2470 * 2471 * @param property a <code>String</code> value 2472 * @param value an <code>Object</code> value 2473 */ 2474 public void setProperty(String property, Object value) 2475 { 2476 } 2477 2478 /** Retrieve the SourceLocator associated with a specific node. 2479 * This is only meaningful if the XalanProperties.SOURCE_LOCATION flag was 2480 * set True using setProperty; if it was never set, or was set false, we 2481 * will return null. 2482 * 2483 * (We _could_ return a locator with the document's base URI and bogus 2484 * line/column information. Trying that; see the else clause.) 2485 * */ 2486 public SourceLocator getSourceLocatorFor(int node) 2487 { 2488 if (m_useSourceLocationProperty) 2489 { 2490 2491 node = makeNodeIdentity(node); 2492 2493 2494 return new NodeLocator(null, 2495 m_sourceSystemId.elementAt(node), 2496 m_sourceLine.elementAt(node), 2497 m_sourceColumn.elementAt(node)); 2498 } 2499 else if(m_locator!=null) 2500 { 2501 return new NodeLocator(null,m_locator.getSystemId(),-1,-1); 2502 } 2503 else if(m_systemId!=null) 2504 { 2505 return new NodeLocator(null,m_systemId,-1,-1); 2506 } 2507 return null; 2508 } 2509 2510 public String getFixedNames(int type){ 2511 return m_fixednames[type]; 2512 } 2513 } 2514