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