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