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 */ SAX2DTM(DTMManager mgr, Source source, int dtmIdentity, DTMWSFilter whiteSpaceFilter, XMLStringFactory xstringfactory, boolean doIndexing)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 */ SAX2DTM(DTMManager mgr, Source source, int dtmIdentity, DTMWSFilter whiteSpaceFilter, XMLStringFactory xstringfactory, boolean doIndexing, int blocksize, boolean usePrevsib, boolean newNameTable)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 */ setUseSourceLocation(boolean useSourceLocation)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 */ _dataOrQName(int identity)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 */ clearCoRoutine()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 */ clearCoRoutine(boolean callDoTerminate)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 */ setIncrementalSAXSource(IncrementalSAXSource incrementalSAXSource)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 */ getContentHandler()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 */ getLexicalHandler()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 */ getEntityResolver()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 */ getDTDHandler()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 */ getErrorHandler()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 */ getDeclHandler()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 */ needsTwoThreads()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 */ dispatchCharactersEvents(int nodeHandle, ContentHandler ch, boolean normalize)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 */ getNodeName(int nodeHandle)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 */ getNodeNameX(int nodeHandle)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 */ isAttributeSpecified(int attributeHandle)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 */ getDocumentTypeDeclarationSystemIdentifier()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 */ getNextNodeIdentity(int identity)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 */ dispatchToEvents(int nodeHandle, org.xml.sax.ContentHandler ch)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 */ getNumberOfNodes()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 */ nextNode()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 */ isTextType(int type)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 */ addNode(int type, int expandedTypeID, int parentIndex, int previousSibling, int dataOrPrefix, boolean canHaveFirstChild)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 */ addNewDTMID(int nodeIndex)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 */ migrateTo(DTMManager manager)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 */ setSourceLocation()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 */ getNodeValue(int nodeHandle)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 */ getLocalName(int nodeHandle)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 */ getUnparsedEntityURI(String name)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 */ getPrefix(int nodeHandle)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 */ getAttributeNode(int nodeHandle, String namespaceURI, String name)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 */ getDocumentTypeDeclarationPublicIdentifier()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 */ getNamespaceURI(int nodeHandle)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 */ getStringValue(int nodeHandle)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 */ isWhitespace(int nodeHandle)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 */ getElementById(String elementId)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 */ getPrefix(String qname, String uri)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 */ getIdForNamespace(String uri)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 */ getNamespaceURI(String prefix)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 */ setIDAttribute(String id, int elem)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 */ charactersFlush()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 */ resolveEntity(String publicId, String systemId)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 */ notationDecl(String name, String publicId, String systemId)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 */ unparsedEntityDecl( String name, String publicId, String systemId, String notationName)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 */ setDocumentLocator(Locator locator)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 */ startDocument()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 */ endDocument()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 */ startPrefixMapping(String prefix, String uri)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 */ endPrefixMapping(String prefix)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 */ declAlreadyDeclared(String prefix)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 */ startElement( String uri, String localName, String qName, Attributes attributes)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 */ endElement(String uri, String localName, String qName)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 */ characters(char ch[], int start, int length)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 */ ignorableWhitespace(char ch[], int start, int length)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 */ processingInstruction(String target, String data)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 */ skippedEntity(String name)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 */ warning(SAXParseException e)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 */ error(SAXParseException e)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 */ fatalError(SAXParseException e)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 */ elementDecl(String name, String model)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 */ attributeDecl( String eName, String aName, String type, String valueDefault, String value)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 */ internalEntityDecl(String name, String value)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 */ externalEntityDecl( String name, String publicId, String systemId)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 */ startDTD(String name, String publicId, String systemId)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 */ endDTD()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 */ startEntity(String name)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 */ endEntity(String name)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 */ startCDATA()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 */ endCDATA()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 */ comment(char ch[], int start, int length)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 */ setProperty(String property, Object value)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 * */ getSourceLocatorFor(int node)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 getFixedNames(int type)2510 public String getFixedNames(int type){ 2511 return m_fixednames[type]; 2512 } 2513 } 2514