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