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