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