KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > xml > dtm > ref > sax2dtm > SAX2DTM


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 org.apache.xml.dtm.ref.sax2dtm;
20
21 import java.util.Hashtable JavaDoc;
22 import java.util.Vector JavaDoc;
23 import javax.xml.transform.Source JavaDoc;
24 import javax.xml.transform.SourceLocator JavaDoc;
25
26 import org.apache.xml.dtm.*;
27 import org.apache.xml.dtm.ref.*;
28 import org.apache.xml.utils.StringVector;
29 import org.apache.xml.utils.IntVector;
30 import org.apache.xml.utils.FastStringBuffer;
31 import org.apache.xml.utils.IntStack;
32 import org.apache.xml.utils.SuballocatedIntVector;
33 import org.apache.xml.utils.SystemIDResolver;
34 import org.apache.xml.utils.WrappedRuntimeException;
35 import org.apache.xml.utils.XMLString;
36 import org.apache.xml.utils.XMLStringFactory;
37 import org.apache.xml.res.XMLErrorResources;
38 import org.apache.xml.res.XMLMessages;
39 import org.xml.sax.*;
40 import org.xml.sax.ext.*;
41
42 /**
43  * This class implements a DTM that tends to be optimized more for speed than
44  * for compactness, that is constructed via SAX2 ContentHandler events.
45  */

46 public class SAX2DTM extends DTMDefaultBaseIterators
47         implements EntityResolver, DTDHandler, ContentHandler, ErrorHandler,
48                    DeclHandler, LexicalHandler
49 {
50   /** Set true to monitor SAX events and similar diagnostic info. */
51   private static final boolean DEBUG = false;
52
53   /**
54    * If we're building the model incrementally on demand, we need to
55    * be able to tell the source when to send us more data.
56    *
57    * Note that if this has not been set, and you attempt to read ahead
58    * of the current build point, we'll probably throw a null-pointer
59    * exception. We could try to wait-and-retry instead, as a very poor
60    * fallback, but that has all the known problems with multithreading
61    * on multiprocessors and we Don't Want to Go There.
62    *
63    * @see setIncrementalSAXSource
64    */

65   private IncrementalSAXSource m_incrementalSAXSource = null;
66
67   /**
68    * All the character content, including attribute values, are stored in
69    * this buffer.
70    *
71    * %REVIEW% Should this have an option of being shared across DTMs?
72    * Sequentially only; not threadsafe... Currently, I think not.
73    *
74    * %REVIEW% Initial size was pushed way down to reduce weight of RTFs.
75    * pending reduction in number of RTF DTMs. Now that we're sharing a DTM
76    * between RTFs, and tail-pruning... consider going back to the larger/faster.
77    *
78    * Made protected rather than private so SAX2RTFDTM can access it.
79    */

80   //private FastStringBuffer m_chars = new FastStringBuffer(13, 13);
81
protected FastStringBuffer m_chars;
82
83   /** This vector holds offset and length data.
84    */

85   protected SuballocatedIntVector m_data;
86
87   /** The parent stack, needed only for construction.
88    * Made protected rather than private so SAX2RTFDTM can access it.
89    */

90   transient protected IntStack m_parents;
91
92   /** The current previous node, needed only for construction time.
93    * Made protected rather than private so SAX2RTFDTM can access it.
94    */

95   transient protected int m_previous = 0;
96
97   /** Namespace support, only relevent at construction time.
98    * Made protected rather than private so SAX2RTFDTM can access it.
99    */

100   transient protected java.util.Vector JavaDoc m_prefixMappings =
101     new java.util.Vector JavaDoc();
102
103   /** Namespace support, only relevent at construction time.
104    * Made protected rather than private so SAX2RTFDTM can access it.
105    */

106   transient protected IntStack m_contextIndexes;
107
108   /** Type of next characters() event within text block in prgress. */
109   transient protected int m_textType = DTM.TEXT_NODE;
110
111   /**
112    * Type of coalesced text block. See logic in the characters()
113    * method.
114    */

115   transient protected int m_coalescedTextType = DTM.TEXT_NODE;
116
117   /** The SAX Document locator */
118   transient protected Locator JavaDoc m_locator = null;
119
120   /** The SAX Document system-id */
121   transient private String JavaDoc m_systemId = null;
122
123   /** We are inside the DTD. This is used for ignoring comments. */
124   transient protected boolean m_insideDTD = false;
125
126   /** Tree Walker for dispatchToEvents. */
127   protected DTMTreeWalker m_walker = new DTMTreeWalker();
128
129   /** pool of string values that come as strings. */
130   protected DTMStringPool m_valuesOrPrefixes;
131
132   /** End document has been reached.
133    * Made protected rather than private so SAX2RTFDTM can access it.
134    */

135   protected boolean m_endDocumentOccured = false;
136
137   /** Data or qualified name values, one array element for each node. */
138   protected SuballocatedIntVector m_dataOrQName;
139
140   /**
141    * This table holds the ID string to node associations, for
142    * XML IDs.
143    */

144   protected Hashtable JavaDoc m_idAttributes = new Hashtable JavaDoc();
145
146   /**
147    * fixed dom-style names.
148    */

149   static final String JavaDoc[] m_fixednames = { null, null, // nothing, Element
150
null, "#text", // Attr, Text
151
"#cdata_section", null, // CDATA, EntityReference
152
null, null, // Entity, PI
153
"#comment", "#document", // Comment, Document
154
null, "#document-fragment", // Doctype, DocumentFragment
155
null }; // Notation
156

157   /**
158    * Vector of entities. Each record is composed of four Strings:
159    * publicId, systemID, notationName, and name.
160    */

161   private Vector JavaDoc m_entities = null;
162
163   /** m_entities public ID offset. */
164   private static final int ENTITY_FIELD_PUBLICID = 0;
165
166   /** m_entities system ID offset. */
167   private static final int ENTITY_FIELD_SYSTEMID = 1;
168
169   /** m_entities notation name offset. */
170   private static final int ENTITY_FIELD_NOTATIONNAME = 2;
171
172   /** m_entities name offset. */
173   private static final int ENTITY_FIELD_NAME = 3;
174
175   /** Number of entries per record for m_entities. */
176   private static final int ENTITY_FIELDS_PER = 4;
177
178   /**
179    * The starting offset within m_chars for the text or
180    * CDATA_SECTION node currently being acumulated,
181    * or -1 if there is no text node in progress
182    */

183   protected int m_textPendingStart = -1;
184
185   /**
186    * Describes whether information about document source location
187    * should be maintained or not.
188    *
189    * Made protected for access by SAX2RTFDTM.
190    */

191   protected boolean m_useSourceLocationProperty = false;
192
193   /**
194    * Describes whether information about document source location
195    * should be maintained or not. This static flag is set by TransformerFactoryImpl.
196    */

197   protected static boolean m_source_location = false;
198
199    /** Made protected for access by SAX2RTFDTM.
200    */

201   protected StringVector m_sourceSystemId;
202    /** Made protected for access by SAX2RTFDTM.
203    */

204   protected IntVector m_sourceLine;
205    /** Made protected for access by SAX2RTFDTM.
206    */

207   protected IntVector m_sourceColumn;
208   
209   /**
210    * Construct a SAX2DTM object using the default block size.
211    *
212    * @param mgr The DTMManager who owns this DTM.
213    * @param source the JAXP 1.1 Source object for this DTM.
214    * @param dtmIdentity The DTM identity ID for this DTM.
215    * @param whiteSpaceFilter The white space filter for this DTM, which may
216    * be null.
217    * @param xstringfactory XMLString factory for creating character content.
218    * @param doIndexing true if the caller considers it worth it to use
219    * indexing schemes.
220    */

221   public SAX2DTM(DTMManager mgr, Source JavaDoc source, int dtmIdentity,
222                  DTMWSFilter whiteSpaceFilter,
223                  XMLStringFactory xstringfactory,
224                  boolean doIndexing)
225   {
226
227     this(mgr, source, dtmIdentity, whiteSpaceFilter,
228           xstringfactory, doIndexing, DEFAULT_BLOCKSIZE, true, false);
229   }
230   
231   /**
232    * Construct a SAX2DTM object ready to be constructed from SAX2
233    * ContentHandler events.
234    *
235    * @param mgr The DTMManager who owns this DTM.
236    * @param source the JAXP 1.1 Source object for this DTM.
237    * @param dtmIdentity The DTM identity ID for this DTM.
238    * @param whiteSpaceFilter The white space filter for this DTM, which may
239    * be null.
240    * @param xstringfactory XMLString factory for creating character content.
241    * @param doIndexing true if the caller considers it worth it to use
242    * indexing schemes.
243    * @param blocksize The block size of the DTM.
244    * @param usePrevsib true if we want to build the previous sibling node array.
245    * @param newNameTable true if we want to use a new ExpandedNameTable for this DTM.
246    */

247   public SAX2DTM(DTMManager mgr, Source JavaDoc source, int dtmIdentity,
248                  DTMWSFilter whiteSpaceFilter,
249                  XMLStringFactory xstringfactory,
250                  boolean doIndexing,
251                  int blocksize,
252                  boolean usePrevsib,
253                  boolean newNameTable)
254   {
255
256     super(mgr, source, dtmIdentity, whiteSpaceFilter,
257           xstringfactory, doIndexing, blocksize, usePrevsib, newNameTable);
258
259     // %OPT% Use smaller sizes for all internal storage units when
260
// the blocksize is small. This reduces the cost of creating an RTF.
261
if (blocksize <= 64)
262     {
263       m_data = new SuballocatedIntVector(blocksize, DEFAULT_NUMBLOCKS_SMALL);
264       m_dataOrQName = new SuballocatedIntVector(blocksize, DEFAULT_NUMBLOCKS_SMALL);
265       m_valuesOrPrefixes = new DTMStringPool(16);
266       m_chars = new FastStringBuffer(7, 10);
267       m_contextIndexes = new IntStack(4);
268       m_parents = new IntStack(4);
269     }
270     else
271     {
272       m_data = new SuballocatedIntVector(blocksize, DEFAULT_NUMBLOCKS);
273       m_dataOrQName = new SuballocatedIntVector(blocksize, DEFAULT_NUMBLOCKS);
274       m_valuesOrPrefixes = new DTMStringPool();
275       m_chars = new FastStringBuffer(10, 13);
276       m_contextIndexes = new IntStack();
277       m_parents = new IntStack();
278     }
279          
280     // %REVIEW% Initial size pushed way down to reduce weight of RTFs
281
// (I'm not entirely sure 0 would work, so I'm playing it safe for now.)
282
//m_data = new SuballocatedIntVector(doIndexing ? (1024*2) : 512, 1024);
283
//m_data = new SuballocatedIntVector(blocksize);
284

285     m_data.addElement(0); // Need placeholder in case index into here must be <0.
286

287     //m_dataOrQName = new SuballocatedIntVector(blocksize);
288

289     // m_useSourceLocationProperty=org.apache.xalan.processor.TransformerFactoryImpl.m_source_location;
290
m_useSourceLocationProperty = m_source_location;
291     m_sourceSystemId = (m_useSourceLocationProperty) ? new StringVector() : null;
292     m_sourceLine = (m_useSourceLocationProperty) ? new IntVector() : null;
293     m_sourceColumn = (m_useSourceLocationProperty) ? new IntVector() : null;
294   }
295
296   /**
297    * Set whether information about document source location
298    * should be maintained or not.
299    */

300   public static void setUseSourceLocation(boolean useSourceLocation)
301   {
302     m_source_location = useSourceLocation;
303   }
304
305   /**
306    * Get the data or qualified name for the given node identity.
307    *
308    * @param identity The node identity.
309    *
310    * @return The data or qualified name, or DTM.NULL.
311    */

312   protected int _dataOrQName(int identity)
313   {
314
315     if (identity < m_size)
316       return m_dataOrQName.elementAt(identity);
317
318     // Check to see if the information requested has been processed, and,
319
// if not, advance the iterator until we the information has been
320
// processed.
321
while (true)
322     {
323       boolean isMore = nextNode();
324
325       if (!isMore)
326         return NULL;
327       else if (identity < m_size)
328         return m_dataOrQName.elementAt(identity);
329     }
330   }
331
332   /**
333    * Ask the CoRoutine parser to doTerminate and clear the reference.
334    */

335   public void clearCoRoutine()
336   {
337     clearCoRoutine(true);
338   }
339
340   /**
341    * Ask the CoRoutine parser to doTerminate and clear the reference. If
342    * the CoRoutine parser has already been cleared, this will have no effect.
343    *
344    * @param callDoTerminate true of doTerminate should be called on the
345    * coRoutine parser.
346    */

347   public void clearCoRoutine(boolean callDoTerminate)
348   {
349
350     if (null != m_incrementalSAXSource)
351     {
352       if (callDoTerminate)
353         m_incrementalSAXSource.deliverMoreNodes(false);
354
355       m_incrementalSAXSource = null;
356     }
357   }
358
359   /**
360    * Bind a IncrementalSAXSource to this DTM. If we discover we need nodes
361    * that have not yet been built, we will ask this object to send us more
362    * events, and it will manage interactions with its data sources.
363    *
364    * Note that we do not actually build the IncrementalSAXSource, since we don't
365    * know what source it's reading from, what thread that source will run in,
366    * or when it will run.
367    *
368    * @param incrementalSAXSource The parser that we want to recieve events from
369    * on demand.
370    * @param appCoRID The CoRoutine ID for the application.
371    */

372   public void setIncrementalSAXSource(IncrementalSAXSource incrementalSAXSource)
373   {
374
375     // Establish coroutine link so we can request more data
376
//
377
// Note: It's possible that some versions of IncrementalSAXSource may
378
// not actually use a CoroutineManager, and hence may not require
379
// that we obtain an Application Coroutine ID. (This relies on the
380
// coroutine transaction details having been encapsulated in the
381
// IncrementalSAXSource.do...() methods.)
382
m_incrementalSAXSource = incrementalSAXSource;
383
384     // Establish SAX-stream link so we can receive the requested data
385
incrementalSAXSource.setContentHandler(this);
386     incrementalSAXSource.setLexicalHandler(this);
387     incrementalSAXSource.setDTDHandler(this);
388
389     // Are the following really needed? incrementalSAXSource doesn't yet
390
// support them, and they're mostly no-ops here...
391
//incrementalSAXSource.setErrorHandler(this);
392
//incrementalSAXSource.setDeclHandler(this);
393
}
394
395   /**
396    * getContentHandler returns "our SAX builder" -- the thing that
397    * someone else should send SAX events to in order to extend this
398    * DTM model.
399    *
400    * %REVIEW% Should this return null if constrution already done/begun?
401    *
402    * @return null if this model doesn't respond to SAX events,
403    * "this" if the DTM object has a built-in SAX ContentHandler,
404    * the IncrementalSAXSource if we're bound to one and should receive
405    * the SAX stream via it for incremental build purposes...
406    */

407   public ContentHandler getContentHandler()
408   {
409
410     if (m_incrementalSAXSource instanceof IncrementalSAXSource_Filter)
411       return (ContentHandler) m_incrementalSAXSource;
412     else
413       return this;
414   }
415
416   /**
417    * Return this DTM's lexical handler.
418    *
419    * %REVIEW% Should this return null if constrution already done/begun?
420    *
421    * @return null if this model doesn't respond to lexical SAX events,
422    * "this" if the DTM object has a built-in SAX ContentHandler,
423    * the IncrementalSAXSource if we're bound to one and should receive
424    * the SAX stream via it for incremental build purposes...
425    */

426   public LexicalHandler getLexicalHandler()
427   {
428
429     if (m_incrementalSAXSource instanceof IncrementalSAXSource_Filter)
430       return (LexicalHandler) m_incrementalSAXSource;
431     else
432       return this;
433   }
434
435   /**
436    * Return this DTM's EntityResolver.
437    *
438    * @return null if this model doesn't respond to SAX entity ref events.
439    */

440   public EntityResolver getEntityResolver()
441   {
442     return this;
443   }
444
445   /**
446    * Return this DTM's DTDHandler.
447    *
448    * @return null if this model doesn't respond to SAX dtd events.
449    */

450   public DTDHandler getDTDHandler()
451   {
452     return this;
453   }
454
455   /**
456    * Return this DTM's ErrorHandler.
457    *
458    * @return null if this model doesn't respond to SAX error events.
459    */

460   public ErrorHandler getErrorHandler()
461   {
462     return this;
463   }
464
465   /**
466    * Return this DTM's DeclHandler.
467    *
468    * @return null if this model doesn't respond to SAX Decl events.
469    */

470   public DeclHandler getDeclHandler()
471   {
472     return this;
473   }
474
475   /**
476    * @return true iff we're building this model incrementally (eg
477    * we're partnered with a IncrementalSAXSource) and thus require that the
478    * transformation and the parse run simultaneously. Guidance to the
479    * DTMManager.
480    */

481   public boolean needsTwoThreads()
482   {
483     return null != m_incrementalSAXSource;
484   }
485
486   /**
487    * Directly call the
488    * characters method on the passed ContentHandler for the
489    * string-value of the given node (see http://www.w3.org/TR/xpath#data-model
490    * for the definition of a node's string-value). Multiple calls to the
491    * ContentHandler's characters methods may well occur for a single call to
492    * this method.
493    *
494    * @param nodeHandle The node ID.
495    * @param ch A non-null reference to a ContentHandler.
496    * @param normalize true if the content should be normalized according to
497    * the rules for the XPath
498    * <a HREF="http://www.w3.org/TR/xpath#function-normalize-space">normalize-space</a>
499    * function.
500    *
501    * @throws SAXException
502    */

503   public void dispatchCharactersEvents(int nodeHandle, ContentHandler ch,
504                                        boolean normalize)
505           throws SAXException
506   {
507
508     int identity = makeNodeIdentity(nodeHandle);
509     
510     if (identity == DTM.NULL)
511       return;
512     
513     int type = _type(identity);
514
515     if (isTextType(type))
516     {
517       int dataIndex = m_dataOrQName.elementAt(identity);
518       int offset = m_data.elementAt(dataIndex);
519       int length = m_data.elementAt(dataIndex + 1);
520
521       if(normalize)
522         m_chars.sendNormalizedSAXcharacters(ch, offset, length);
523       else
524         m_chars.sendSAXcharacters(ch, offset, length);
525     }
526     else
527     {
528       int firstChild = _firstch(identity);
529
530       if (DTM.NULL != firstChild)
531       {
532         int offset = -1;
533         int length = 0;
534         int startNode = identity;
535
536         identity = firstChild;
537
538         do {
539           type = _type(identity);
540
541           if (isTextType(type))
542           {
543             int dataIndex = _dataOrQName(identity);
544
545             if (-1 == offset)
546             {
547               offset = m_data.elementAt(dataIndex);
548             }
549
550             length += m_data.elementAt(dataIndex + 1);
551           }
552
553           identity = getNextNodeIdentity(identity);
554         } while (DTM.NULL != identity && (_parent(identity) >= startNode));
555
556         if (length > 0)
557         {
558           if(normalize)
559             m_chars.sendNormalizedSAXcharacters(ch, offset, length);
560           else
561             m_chars.sendSAXcharacters(ch, offset, length);
562         }
563       }
564       else if(type != DTM.ELEMENT_NODE)
565       {
566         int dataIndex = _dataOrQName(identity);
567
568         if (dataIndex < 0)
569         {
570           dataIndex = -dataIndex;
571           dataIndex = m_data.elementAt(dataIndex + 1);
572         }
573
574         String JavaDoc str = m_valuesOrPrefixes.indexToString(dataIndex);
575
576           if(normalize)
577             FastStringBuffer.sendNormalizedSAXcharacters(str.toCharArray(),
578                                                          0, str.length(), ch);
579           else
580             ch.characters(str.toCharArray(), 0, str.length());
581       }
582     }
583   }
584
585
586   /**
587    * Given a node handle, return its DOM-style node name. This will
588    * include names such as #text or #document.
589    *
590    * @param nodeHandle the id of the node.
591    * @return String Name of this node, which may be an empty string.
592    * %REVIEW% Document when empty string is possible...
593    * %REVIEW-COMMENT% It should never be empty, should it?
594    */

595   public String JavaDoc getNodeName(int nodeHandle)
596   {
597
598     int expandedTypeID = getExpandedTypeID(nodeHandle);
599     // If just testing nonzero, no need to shift...
600
int namespaceID = m_expandedNameTable.getNamespaceID(expandedTypeID);
601
602     if (0 == namespaceID)
603     {
604       // Don't retrieve name until/unless needed
605
// String name = m_expandedNameTable.getLocalName(expandedTypeID);
606
int type = getNodeType(nodeHandle);
607
608       if (type == DTM.NAMESPACE_NODE)
609       {
610         if (null == m_expandedNameTable.getLocalName(expandedTypeID))
611           return "xmlns";
612         else
613           return "xmlns:" + m_expandedNameTable.getLocalName(expandedTypeID);
614       }
615       else if (0 == m_expandedNameTable.getLocalNameID(expandedTypeID))
616       {
617         return m_fixednames[type];
618       }
619       else
620         return m_expandedNameTable.getLocalName(expandedTypeID);
621     }
622     else
623     {
624       int qnameIndex = m_dataOrQName.elementAt(makeNodeIdentity(nodeHandle));
625
626       if (qnameIndex < 0)
627       {
628         qnameIndex = -qnameIndex;
629         qnameIndex = m_data.elementAt(qnameIndex);
630       }
631
632       return m_valuesOrPrefixes.indexToString(qnameIndex);
633     }
634   }
635
636   /**
637    * Given a node handle, return the XPath node name. This should be
638    * the name as described by the XPath data model, NOT the DOM-style
639    * name.
640    *
641    * @param nodeHandle the id of the node.
642    * @return String Name of this node, which may be an empty string.
643    */

644   public String JavaDoc getNodeNameX(int nodeHandle)
645   {
646
647     int expandedTypeID = getExpandedTypeID(nodeHandle);
648     int namespaceID = m_expandedNameTable.getNamespaceID(expandedTypeID);
649
650     if (0 == namespaceID)
651     {
652       String JavaDoc name = m_expandedNameTable.getLocalName(expandedTypeID);
653
654       if (name == null)
655         return "";
656       else
657         return name;
658     }
659     else
660     {
661       int qnameIndex = m_dataOrQName.elementAt(makeNodeIdentity(nodeHandle));
662
663       if (qnameIndex < 0)
664       {
665         qnameIndex = -qnameIndex;
666         qnameIndex = m_data.elementAt(qnameIndex);
667       }
668
669       return m_valuesOrPrefixes.indexToString(qnameIndex);
670     }
671   }
672
673   /**
674    * 5. [specified] A flag indicating whether this attribute was actually
675    * specified in the start-tag of its element, or was defaulted from the
676    * DTD.
677    *
678    * @param the attribute handle
679    *
680    * @param attributeHandle Must be a valid handle to an attribute node.
681    * @return <code>true</code> if the attribute was specified;
682    * <code>false</code> if it was defaulted.
683    */

684   public boolean isAttributeSpecified(int attributeHandle)
685   {
686
687     // I'm not sure if I want to do anything with this...
688
return true; // ??
689
}
690
691   /**
692    * A document type declaration information item has the following properties:
693    *
694    * 1. [system identifier] The system identifier of the external subset, if
695    * it exists. Otherwise this property has no value.
696    *
697    * @return the system identifier String object, or null if there is none.
698    */

699   public String JavaDoc getDocumentTypeDeclarationSystemIdentifier()
700   {
701
702     /** @todo: implement this org.apache.xml.dtm.DTMDefaultBase abstract method */
703     error(XMLMessages.createXMLMessage(XMLErrorResources.ER_METHOD_NOT_SUPPORTED, null));//"Not yet supported!");
704

705     return null;
706   }
707
708   /**
709    * Get the next node identity value in the list, and call the iterator
710    * if it hasn't been added yet.
711    *
712    * @param identity The node identity (index).
713    * @return identity+1, or DTM.NULL.
714    */

715   protected int getNextNodeIdentity(int identity)
716   {
717
718     identity += 1;
719
720     while (identity >= m_size)
721     {
722       if (null == m_incrementalSAXSource)
723         return DTM.NULL;
724
725       nextNode();
726     }
727
728     return identity;
729   }
730
731   /**
732    * Directly create SAX parser events from a subtree.
733    *
734    * @param nodeHandle The node ID.
735    * @param ch A non-null reference to a ContentHandler.
736    *
737    * @throws org.xml.sax.SAXException
738    */

739   public void dispatchToEvents(int nodeHandle, org.xml.sax.ContentHandler JavaDoc ch)
740           throws org.xml.sax.SAXException JavaDoc
741   {
742
743     DTMTreeWalker treeWalker = m_walker;
744     ContentHandler prevCH = treeWalker.getcontentHandler();
745
746     if (null != prevCH)
747     {
748       treeWalker = new DTMTreeWalker();
749     }
750
751     treeWalker.setcontentHandler(ch);
752     treeWalker.setDTM(this);
753
754     try
755     {
756       treeWalker.traverse(nodeHandle);
757     }
758     finally
759     {
760       treeWalker.setcontentHandler(null);
761     }
762   }
763
764   /**
765    * Get the number of nodes that have been added.
766    *
767    * @return The number of that are currently in the tree.
768    */

769   public int getNumberOfNodes()
770   {
771     return m_size;
772   }
773
774   /**
775    * This method should try and build one or more nodes in the table.
776    *
777    * @return The true if a next node is found or false if
778    * there are no more nodes.
779    */

780   protected boolean nextNode()
781   {
782
783     if (null == m_incrementalSAXSource)
784       return false;
785
786     if (m_endDocumentOccured)
787     {
788       clearCoRoutine();
789
790       return false;
791     }
792
793     Object JavaDoc gotMore = m_incrementalSAXSource.deliverMoreNodes(true);
794
795     // gotMore may be a Boolean (TRUE if still parsing, FALSE if
796
// EOF) or an exception if IncrementalSAXSource malfunctioned
797
// (code error rather than user error).
798
//
799
// %REVIEW% Currently the ErrorHandlers sketched herein are
800
// no-ops, so I'm going to initially leave this also as a
801
// no-op.
802
if (!(gotMore instanceof Boolean JavaDoc))
803     {
804       if(gotMore instanceof RuntimeException JavaDoc)
805       {
806         throw (RuntimeException JavaDoc)gotMore;
807       }
808       else if(gotMore instanceof Exception JavaDoc)
809       {
810         throw new WrappedRuntimeException((Exception JavaDoc)gotMore);
811       }
812       // for now...
813
clearCoRoutine();
814
815       return false;
816
817       // %TBD%
818
}
819
820     if (gotMore != Boolean.TRUE)
821     {
822
823       // EOF reached without satisfying the request
824
clearCoRoutine(); // Drop connection, stop trying
825

826       // %TBD% deregister as its listener?
827
}
828
829     return true;
830   }
831
832   /**
833    * Bottleneck determination of text type.
834    *
835    * @param type oneof DTM.XXX_NODE.
836    *
837    * @return true if this is a text or cdata section.
838    */

839   private final boolean isTextType(int type)
840   {
841     return (DTM.TEXT_NODE == type || DTM.CDATA_SECTION_NODE == type);
842   }
843
844 // /**
845
// * Ensure that the size of the information arrays can hold another entry
846
// * at the given index.
847
// *
848
// * @param on exit from this function, the information arrays sizes must be
849
// * at least index+1.
850
// *
851
// * NEEDSDOC @param index
852
// */
853
// protected void ensureSize(int index)
854
// {
855
// // dataOrQName is an SuballocatedIntVector and hence self-sizing.
856
// // But DTMDefaultBase may need fixup.
857
// super.ensureSize(index);
858
// }
859

860   /**
861    * Construct the node map from the node.
862    *
863    * @param type raw type ID, one of DTM.XXX_NODE.
864    * @param expandedTypeID The expended type ID.
865    * @param parentIndex The current parent index.
866    * @param previousSibling The previous sibling index.
867    * @param dataOrPrefix index into m_data table, or string handle.
868    * @param canHaveFirstChild true if the node can have a first child, false
869    * if it is atomic.
870    *
871    * @return The index identity of the node that was added.
872    */

873   protected int addNode(int type, int expandedTypeID,
874                         int parentIndex, int previousSibling,
875                         int dataOrPrefix, boolean canHaveFirstChild)
876   {
877     // Common to all nodes:
878
int nodeIndex = m_size++;
879
880     // Have we overflowed a DTM Identity's addressing range?
881
if(m_dtmIdent.size() == (nodeIndex>>>DTMManager.IDENT_DTM_NODE_BITS))
882     {
883       addNewDTMID(nodeIndex);
884     }
885
886     m_firstch.addElement(canHaveFirstChild ? NOTPROCESSED : DTM.NULL);
887     m_nextsib.addElement(NOTPROCESSED);
888     m_parent.addElement(parentIndex);
889     m_exptype.addElement(expandedTypeID);
890     m_dataOrQName.addElement(dataOrPrefix);
891
892     if (m_prevsib != null) {
893       m_prevsib.addElement(previousSibling);
894     }
895
896     if (DTM.NULL != previousSibling) {
897       m_nextsib.setElementAt(nodeIndex,previousSibling);
898     }
899
900     if (m_locator != null && m_useSourceLocationProperty) {
901       setSourceLocation();
902     }
903
904     // Note that nextSibling is not processed until charactersFlush()
905
// is called, to handle successive characters() events.
906

907     // Special handling by type: Declare namespaces, attach first child
908
switch(type)
909     {
910     case DTM.NAMESPACE_NODE:
911       declareNamespaceInContext(parentIndex,nodeIndex);
912       break;
913     case DTM.ATTRIBUTE_NODE:
914       break;
915     default:
916       if (DTM.NULL == previousSibling && DTM.NULL != parentIndex) {
917         m_firstch.setElementAt(nodeIndex,parentIndex);
918       }
919       break;
920     }
921
922     return nodeIndex;
923   }
924
925   /**
926    * Get a new DTM ID beginning at the specified node index.
927    * @param nodeIndex The node identity at which the new DTM ID will begin
928    * addressing.
929    */

930   protected void addNewDTMID(int nodeIndex) {
931     try
932     {
933       if(m_mgr==null)
934         throw new ClassCastException JavaDoc();
935                               
936                               // Handle as Extended Addressing
937
DTMManagerDefault mgrD=(DTMManagerDefault)m_mgr;
938       int id=mgrD.getFirstFreeDTMID();
939       mgrD.addDTM(this,id,nodeIndex);
940       m_dtmIdent.addElement(id<<DTMManager.IDENT_DTM_NODE_BITS);
941     }
942     catch(ClassCastException JavaDoc e)
943     {
944       // %REVIEW% Wrong error message, but I've been told we're trying
945
// not to add messages right not for I18N reasons.
946
// %REVIEW% Should this be a Fatal Error?
947
error(XMLMessages.createXMLMessage(XMLErrorResources.ER_NO_DTMIDS_AVAIL, null));//"No more DTM IDs are available";
948
}
949   }
950
951   /**
952     * Migrate a DTM built with an old DTMManager to a new DTMManager.
953     * After the migration, the new DTMManager will treat the DTM as
954     * one that is built by itself.
955     * This is used to support DTM sharing between multiple transformations.
956     * @param manager the DTMManager
957     */

958   public void migrateTo(DTMManager manager) {
959     super.migrateTo(manager);
960     
961     // We have to reset the information in m_dtmIdent and
962
// register the DTM with the new manager.
963
int numDTMs = m_dtmIdent.size();
964     int dtmId = m_mgrDefault.getFirstFreeDTMID();
965     int nodeIndex = 0;
966     for (int i = 0; i < numDTMs; i++)
967     {
968       m_dtmIdent.setElementAt(dtmId << DTMManager.IDENT_DTM_NODE_BITS, i);
969       m_mgrDefault.addDTM(this, dtmId, nodeIndex);
970       dtmId++;
971       nodeIndex += (1 << DTMManager.IDENT_DTM_NODE_BITS);
972     }
973   }
974
975   /**
976    * Store the source location of the current node. This method must be called
977    * as every node is added to the DTM or for no node.
978    */

979   protected void setSourceLocation() {
980     m_sourceSystemId.addElement(m_locator.getSystemId());
981     m_sourceLine.addElement(m_locator.getLineNumber());
982     m_sourceColumn.addElement(m_locator.getColumnNumber());
983
984     //%REVIEW% %BUG% Prevent this from arising in the first place
985
// by not allowing the enabling conditions to change after we start
986
// building the document.
987
if (m_sourceSystemId.size() != m_size) {
988         System.err.println("CODING ERROR in Source Location: " + m_size
989                            + " != "
990                             + m_sourceSystemId.size());
991         System.exit(1);
992     }
993   }
994
995   /**
996    * Given a node handle, return its node value. This is mostly
997    * as defined by the DOM, but may ignore some conveniences.
998    * <p>
999    *
1000   * @param nodeHandle The node id.
1001   * @return String Value of this node, or null if not
1002   * meaningful for this node type.
1003   */

1004  public String JavaDoc getNodeValue(int nodeHandle)
1005  {
1006
1007    int identity = makeNodeIdentity(nodeHandle);
1008    int type = _type(identity);
1009
1010    if (isTextType(type))
1011    {
1012      int dataIndex = _dataOrQName(identity);
1013      int offset = m_data.elementAt(dataIndex);
1014      int length = m_data.elementAt(dataIndex + 1);
1015
1016      // %OPT% We should cache this, I guess.
1017
return m_chars.getString(offset, length);
1018    }
1019    else if (DTM.ELEMENT_NODE == type || DTM.DOCUMENT_FRAGMENT_NODE == type
1020             || DTM.DOCUMENT_NODE == type)
1021    {
1022      return null;
1023    }
1024    else
1025    {
1026      int dataIndex = _dataOrQName(identity);
1027
1028      if (dataIndex < 0)
1029      {
1030        dataIndex = -dataIndex;
1031        dataIndex = m_data.elementAt(dataIndex + 1);
1032      }
1033
1034      return m_valuesOrPrefixes.indexToString(dataIndex);
1035    }
1036  }
1037
1038  /**
1039   * Given a node handle, return its XPath-style localname.
1040   * (As defined in Namespaces, this is the portion of the name after any
1041   * colon character).
1042   *
1043   * @param nodeHandle the id of the node.
1044   * @return String Local name of this node.
1045   */

1046  public String JavaDoc getLocalName(int nodeHandle)
1047  {
1048    return m_expandedNameTable.getLocalName(_exptype(makeNodeIdentity(nodeHandle)));
1049  }
1050
1051  /**
1052   * The getUnparsedEntityURI function returns the URI of the unparsed
1053   * entity with the specified name in the same document as the context
1054   * node (see [3.3 Unparsed Entities]). It returns the empty string if
1055   * there is no such entity.
1056   * <p>
1057   * XML processors may choose to use the System Identifier (if one
1058   * is provided) to resolve the entity, rather than the URI in the
1059   * Public Identifier. The details are dependent on the processor, and
1060   * we would have to support some form of plug-in resolver to handle
1061   * this properly. Currently, we simply return the System Identifier if
1062   * present, and hope that it a usable URI or that our caller can
1063   * map it to one.
1064   * TODO: Resolve Public Identifiers... or consider changing function name.
1065   * <p>
1066   * If we find a relative URI
1067   * reference, XML expects it to be resolved in terms of the base URI
1068   * of the document. The DOM doesn't do that for us, and it isn't
1069   * entirely clear whether that should be done here; currently that's
1070   * pushed up to a higher level of our application. (Note that DOM Level
1071   * 1 didn't store the document's base URI.)
1072   * TODO: Consider resolving Relative URIs.
1073   * <p>
1074   * (The DOM's statement that "An XML processor may choose to
1075   * completely expand entities before the structure model is passed
1076   * to the DOM" refers only to parsed entities, not unparsed, and hence
1077   * doesn't affect this function.)
1078   *
1079   * @param name A string containing the Entity Name of the unparsed
1080   * entity.
1081   *
1082   * @return String containing the URI of the Unparsed Entity, or an
1083   * empty string if no such entity exists.
1084   */

1085  public String JavaDoc getUnparsedEntityURI(String JavaDoc name)
1086  {
1087
1088    String JavaDoc url = "";
1089
1090    if (null == m_entities)
1091      return url;
1092
1093    int n = m_entities.size();
1094
1095    for (int i = 0; i < n; i += ENTITY_FIELDS_PER)
1096    {
1097      String JavaDoc ename = (String JavaDoc) m_entities.elementAt(i + ENTITY_FIELD_NAME);
1098
1099      if (null != ename && ename.equals(name))
1100      {
1101        String JavaDoc nname = (String JavaDoc) m_entities.elementAt(i
1102                         + ENTITY_FIELD_NOTATIONNAME);
1103
1104        if (null != nname)
1105        {
1106
1107          // The draft says: "The XSLT processor may use the public
1108
// identifier to generate a URI for the entity instead of the URI
1109
// specified in the system identifier. If the XSLT processor does
1110
// not use the public identifier to generate the URI, it must use
1111
// the system identifier; if the system identifier is a relative
1112
// URI, it must be resolved into an absolute URI using the URI of
1113
// the resource containing the entity declaration as the base
1114
// URI [RFC2396]."
1115
// So I'm falling a bit short here.
1116
url = (String JavaDoc) m_entities.elementAt(i + ENTITY_FIELD_SYSTEMID);
1117
1118          if (null == url)
1119          {
1120            url = (String JavaDoc) m_entities.elementAt(i + ENTITY_FIELD_PUBLICID);
1121          }
1122        }
1123
1124        break;
1125      }
1126    }
1127
1128    return url;
1129  }
1130
1131  /**
1132   * Given a namespace handle, return the prefix that the namespace decl is
1133   * mapping.
1134   * Given a node handle, return the prefix used to map to the namespace.
1135   *
1136   * <p> %REVIEW% Are you sure you want "" for no prefix? </p>
1137   * <p> %REVIEW-COMMENT% I think so... not totally sure. -sb </p>
1138   *
1139   * @param nodeHandle the id of the node.
1140   * @return String prefix of this node's name, or "" if no explicit
1141   * namespace prefix was given.
1142   */

1143  public String JavaDoc getPrefix(int nodeHandle)
1144  {
1145
1146    int identity = makeNodeIdentity(nodeHandle);
1147    int type = _type(identity);
1148
1149    if (DTM.ELEMENT_NODE == type)
1150    {
1151      int prefixIndex = _dataOrQName(identity);
1152
1153      if (0 == prefixIndex)
1154        return "";
1155      else
1156      {
1157        String JavaDoc qname = m_valuesOrPrefixes.indexToString(prefixIndex);
1158
1159        return getPrefix(qname, null);
1160      }
1161    }
1162    else if (DTM.ATTRIBUTE_NODE == type)
1163    {
1164      int prefixIndex = _dataOrQName(identity);
1165
1166      if (prefixIndex < 0)
1167      {
1168        prefixIndex = m_data.elementAt(-prefixIndex);
1169
1170        String JavaDoc qname = m_valuesOrPrefixes.indexToString(prefixIndex);
1171
1172        return getPrefix(qname, null);
1173      }
1174    }
1175
1176    return "";
1177  }
1178
1179  /**
1180   * Retrieves an attribute node by by qualified name and namespace URI.
1181   *
1182   * @param nodeHandle int Handle of the node upon which to look up this attribute..
1183   * @param namespaceURI The namespace URI of the attribute to
1184   * retrieve, or null.
1185   * @param name The local name of the attribute to
1186   * retrieve.
1187   * @return The attribute node handle with the specified name (
1188   * <code>nodeName</code>) or <code>DTM.NULL</code> if there is no such
1189   * attribute.
1190   */

1191  public int getAttributeNode(int nodeHandle, String JavaDoc namespaceURI,
1192                              String JavaDoc name)
1193  {
1194
1195    for (int attrH = getFirstAttribute(nodeHandle); DTM.NULL != attrH;
1196            attrH = getNextAttribute(attrH))
1197    {
1198      String JavaDoc attrNS = getNamespaceURI(attrH);
1199      String JavaDoc attrName = getLocalName(attrH);
1200      boolean nsMatch = namespaceURI == attrNS
1201                        || (namespaceURI != null
1202                            && namespaceURI.equals(attrNS));
1203
1204      if (nsMatch && name.equals(attrName))
1205        return attrH;
1206    }
1207
1208    return DTM.NULL;
1209  }
1210
1211  /**
1212   * Return the public identifier of the external subset,
1213   * normalized as described in 4.2.2 External Entities [XML]. If there is
1214   * no external subset or if it has no public identifier, this property
1215   * has no value.
1216   *
1217   * @param the document type declaration handle
1218   *
1219   * @return the public identifier String object, or null if there is none.
1220   */

1221  public String JavaDoc getDocumentTypeDeclarationPublicIdentifier()
1222  {
1223
1224    /** @todo: implement this org.apache.xml.dtm.DTMDefaultBase abstract method */
1225    error(XMLMessages.createXMLMessage(XMLErrorResources.ER_METHOD_NOT_SUPPORTED, null));//"Not yet supported!");
1226

1227    return null;
1228  }
1229
1230  /**
1231   * Given a node handle, return its DOM-style namespace URI
1232   * (As defined in Namespaces, this is the declared URI which this node's
1233   * prefix -- or default in lieu thereof -- was mapped to.)
1234   *
1235   * <p>%REVIEW% Null or ""? -sb</p>
1236   *
1237   * @param nodeHandle the id of the node.
1238   * @return String URI value of this node's namespace, or null if no
1239   * namespace was resolved.
1240   */

1241  public String JavaDoc getNamespaceURI(int nodeHandle)
1242  {
1243
1244    return m_expandedNameTable.getNamespace(_exptype(makeNodeIdentity(nodeHandle)));
1245  }
1246
1247  /**
1248   * Get the string-value of a node as a String object
1249   * (see http://www.w3.org/TR/xpath#data-model
1250   * for the definition of a node's string-value).
1251   *
1252   * @param nodeHandle The node ID.
1253   *
1254   * @return A string object that represents the string-value of the given node.
1255   */

1256  public XMLString getStringValue(int nodeHandle)
1257  {
1258    int identity = makeNodeIdentity(nodeHandle);
1259    int type;
1260    if(identity==DTM.NULL) // Separate lines because I wanted to breakpoint it
1261
type = DTM.NULL;
1262    else
1263      type= _type(identity);
1264
1265    if (isTextType(type))
1266    {
1267      int dataIndex = _dataOrQName(identity);
1268      int offset = m_data.elementAt(dataIndex);
1269      int length = m_data.elementAt(dataIndex + 1);
1270
1271      return m_xstrf.newstr(m_chars, offset, length);
1272    }
1273    else
1274    {
1275      int firstChild = _firstch(identity);
1276
1277      if (DTM.NULL != firstChild)
1278      {
1279        int offset = -1;
1280        int length = 0;
1281        int startNode = identity;
1282
1283        identity = firstChild;
1284
1285        do {
1286          type = _type(identity);
1287
1288          if (isTextType(type))
1289          {
1290            int dataIndex = _dataOrQName(identity);
1291
1292            if (-1 == offset)
1293            {
1294              offset = m_data.elementAt(dataIndex);
1295            }
1296
1297            length += m_data.elementAt(dataIndex + 1);
1298          }
1299
1300          identity = getNextNodeIdentity(identity);
1301        } while (DTM.NULL != identity && (_parent(identity) >= startNode));
1302
1303        if (length > 0)
1304        {
1305          return m_xstrf.newstr(m_chars, offset, length);
1306        }
1307      }
1308      else if(type != DTM.ELEMENT_NODE)
1309      {
1310        int dataIndex = _dataOrQName(identity);
1311
1312        if (dataIndex < 0)
1313        {
1314          dataIndex = -dataIndex;
1315          dataIndex = m_data.elementAt(dataIndex + 1);
1316        }
1317        return m_xstrf.newstr(m_valuesOrPrefixes.indexToString(dataIndex));
1318      }
1319    }
1320
1321    return m_xstrf.emptystr();
1322  }
1323  
1324  /**
1325   * Determine if the string-value of a node is whitespace
1326   *
1327   * @param nodeHandle The node Handle.
1328   *
1329   * @return Return true if the given node is whitespace.
1330   */

1331  public boolean isWhitespace(int nodeHandle)
1332  {
1333    int identity = makeNodeIdentity(nodeHandle);
1334    int type;
1335    if(identity==DTM.NULL) // Separate lines because I wanted to breakpoint it
1336
type = DTM.NULL;
1337    else
1338      type= _type(identity);
1339
1340    if (isTextType(type))
1341    {
1342      int dataIndex = _dataOrQName(identity);
1343      int offset = m_data.elementAt(dataIndex);
1344      int length = m_data.elementAt(dataIndex + 1);
1345
1346      return m_chars.isWhitespace(offset, length);
1347    }
1348    return false;
1349  }
1350
1351  /**
1352   * Returns the <code>Element</code> whose <code>ID</code> is given by
1353   * <code>elementId</code>. If no such element exists, returns
1354   * <code>DTM.NULL</code>. Behavior is not defined if more than one element
1355   * has this <code>ID</code>. Attributes (including those
1356   * with the name "ID") are not of type ID unless so defined by DTD/Schema
1357   * information available to the DTM implementation.
1358   * Implementations that do not know whether attributes are of type ID or
1359   * not are expected to return <code>DTM.NULL</code>.
1360   *
1361   * <p>%REVIEW% Presumably IDs are still scoped to a single document,
1362   * and this operation searches only within a single document, right?
1363   * Wouldn't want collisions between DTMs in the same process.</p>
1364   *
1365   * @param elementId The unique <code>id</code> value for an element.
1366   * @return The handle of the matching element.
1367   */

1368  public int getElementById(String JavaDoc elementId)
1369  {
1370
1371    Integer JavaDoc intObj;
1372    boolean isMore = true;
1373
1374    do
1375    {
1376      intObj = (Integer JavaDoc) m_idAttributes.get(elementId);
1377
1378      if (null != intObj)
1379        return makeNodeHandle(intObj.intValue());
1380
1381      if (!isMore || m_endDocumentOccured)
1382        break;
1383
1384      isMore = nextNode();
1385    }
1386    while (null == intObj);
1387
1388    return DTM.NULL;
1389  }
1390
1391  /**
1392   * Get a prefix either from the qname or from the uri mapping, or just make
1393   * one up!
1394   *
1395   * @param qname The qualified name, which may be null.
1396   * @param uri The namespace URI, which may be null.
1397   *
1398   * @return The prefix if there is one, or null.
1399   */

1400  public String JavaDoc getPrefix(String JavaDoc qname, String JavaDoc uri)
1401  {
1402
1403    String JavaDoc prefix;
1404    int uriIndex = -1;
1405
1406    if (null != uri && uri.length() > 0)
1407    {
1408
1409      do
1410      {
1411        uriIndex = m_prefixMappings.indexOf(uri, ++uriIndex);
1412      } while ( (uriIndex & 0x01) == 0);
1413
1414      if (uriIndex >= 0)
1415      {
1416        prefix = (String JavaDoc) m_prefixMappings.elementAt(uriIndex - 1);
1417      }
1418      else if (null != qname)
1419      {
1420        int indexOfNSSep = qname.indexOf(':');
1421
1422        if (qname.equals("xmlns"))
1423          prefix = "";
1424        else if (qname.startsWith("xmlns:"))
1425          prefix = qname.substring(indexOfNSSep + 1);
1426        else
1427          prefix = (indexOfNSSep > 0)
1428                   ? qname.substring(0, indexOfNSSep) : null;
1429      }
1430      else
1431      {
1432        prefix = null;
1433      }
1434    }
1435    else if (null != qname)
1436    {
1437      int indexOfNSSep = qname.indexOf(':');
1438
1439      if (indexOfNSSep > 0)
1440      {
1441        if (qname.startsWith("xmlns:"))
1442          prefix = qname.substring(indexOfNSSep + 1);
1443        else
1444          prefix = qname.substring(0, indexOfNSSep);
1445      }
1446      else
1447      {
1448        if (qname.equals("xmlns"))
1449          prefix = "";
1450        else
1451          prefix = null;
1452      }
1453    }
1454    else
1455    {
1456      prefix = null;
1457    }
1458
1459    return prefix;
1460  }
1461  
1462  /**
1463   * Get a prefix either from the uri mapping, or just make
1464   * one up!
1465   *
1466   * @param uri The namespace URI, which may be null.
1467   *
1468   * @return The prefix if there is one, or null.
1469   */

1470  public int getIdForNamespace(String JavaDoc uri)
1471  {
1472
1473     return m_valuesOrPrefixes.stringToIndex(uri);
1474    
1475  }
1476
1477    /**
1478   * Get a prefix either from the qname or from the uri mapping, or just make
1479   * one up!
1480   *
1481   * @param qname The qualified name, which may be null.
1482   * @param uri The namespace URI, which may be null.
1483   *
1484   * @return The prefix if there is one, or null.
1485   */

1486  public String JavaDoc getNamespaceURI(String JavaDoc prefix)
1487  {
1488
1489    String JavaDoc uri = "";
1490    int prefixIndex = m_contextIndexes.peek() - 1 ;
1491
1492    if(null == prefix)
1493      prefix = "";
1494
1495      do
1496      {
1497        prefixIndex = m_prefixMappings.indexOf(prefix, ++prefixIndex);
1498      } while ( (prefixIndex >= 0) && (prefixIndex & 0x01) == 0x01);
1499
1500      if (prefixIndex > -1)
1501      {
1502        uri = (String JavaDoc) m_prefixMappings.elementAt(prefixIndex + 1);
1503      }
1504
1505
1506    return uri;
1507  }
1508
1509  /**
1510   * Set an ID string to node association in the ID table.
1511   *
1512   * @param id The ID string.
1513   * @param elem The associated element handle.
1514   */

1515  public void setIDAttribute(String JavaDoc id, int elem)
1516  {
1517    m_idAttributes.put(id, new Integer JavaDoc(elem));
1518  }
1519
1520  /**
1521   * Check whether accumulated text should be stripped; if not,
1522   * append the appropriate flavor of text/cdata node.
1523   */

1524  protected void charactersFlush()
1525  {
1526
1527    if (m_textPendingStart >= 0) // -1 indicates no-text-in-progress
1528
{
1529      int length = m_chars.size() - m_textPendingStart;
1530      boolean doStrip = false;
1531
1532      if (getShouldStripWhitespace())
1533      {
1534        doStrip = m_chars.isWhitespace(m_textPendingStart, length);
1535      }
1536
1537      if (doStrip)
1538        m_chars.setLength(m_textPendingStart); // Discard accumulated text
1539
else
1540      {
1541        int exName = m_expandedNameTable.getExpandedTypeID(DTM.TEXT_NODE);
1542        int dataIndex = m_data.size();
1543
1544        m_previous = addNode(m_coalescedTextType, exName,
1545                             m_parents.peek(), m_previous, dataIndex, false);
1546
1547        m_data.addElement(m_textPendingStart);
1548        m_data.addElement(length);
1549      }
1550
1551      // Reset for next text block
1552
m_textPendingStart = -1;
1553      m_textType = m_coalescedTextType = DTM.TEXT_NODE;
1554    }
1555  }
1556
1557  ////////////////////////////////////////////////////////////////////
1558
// Implementation of the EntityResolver interface.
1559
////////////////////////////////////////////////////////////////////
1560

1561  /**
1562   * Resolve an external entity.
1563   *
1564   * <p>Always return null, so that the parser will use the system
1565   * identifier provided in the XML document. This method implements
1566   * the SAX default behaviour: application writers can override it
1567   * in a subclass to do special translations such as catalog lookups
1568   * or URI redirection.</p>
1569   *
1570   * @param publicId The public identifer, or null if none is
1571   * available.
1572   * @param systemId The system identifier provided in the XML
1573   * document.
1574   * @return The new input source, or null to require the
1575   * default behaviour.
1576   * @throws SAXException Any SAX exception, possibly
1577   * wrapping another exception.
1578   * @see org.xml.sax.EntityResolver#resolveEntity
1579   *
1580   * @throws SAXException
1581   */

1582  public InputSource resolveEntity(String JavaDoc publicId, String JavaDoc systemId)
1583          throws SAXException
1584  {
1585    return null;
1586  }
1587
1588  ////////////////////////////////////////////////////////////////////
1589
// Implementation of DTDHandler interface.
1590
////////////////////////////////////////////////////////////////////
1591

1592  /**
1593   * Receive notification of a notation declaration.
1594   *
1595   * <p>By default, do nothing. Application writers may override this
1596   * method in a subclass if they wish to keep track of the notations
1597   * declared in a document.</p>
1598   *
1599   * @param name The notation name.
1600   * @param publicId The notation public identifier, or null if not
1601   * available.
1602   * @param systemId The notation system identifier.
1603   * @throws SAXException Any SAX exception, possibly
1604   * wrapping another exception.
1605   * @see org.xml.sax.DTDHandler#notationDecl
1606   *
1607   * @throws SAXException
1608   */

1609  public void notationDecl(String JavaDoc name, String JavaDoc publicId, String JavaDoc systemId)
1610          throws SAXException
1611  {
1612
1613    // no op
1614
}
1615
1616  /**
1617   * Receive notification of an unparsed entity declaration.
1618   *
1619   * <p>By default, do nothing. Application writers may override this
1620   * method in a subclass to keep track of the unparsed entities
1621   * declared in a document.</p>
1622   *
1623   * @param name The entity name.
1624   * @param publicId The entity public identifier, or null if not
1625   * available.
1626   * @param systemId The entity system identifier.
1627   * @param notationName The name of the associated notation.
1628   * @throws SAXException Any SAX exception, possibly
1629   * wrapping another exception.
1630   * @see org.xml.sax.DTDHandler#unparsedEntityDecl
1631   *
1632   * @throws SAXException
1633   */

1634  public void unparsedEntityDecl(
1635          String JavaDoc name, String JavaDoc publicId, String JavaDoc systemId, String JavaDoc notationName)
1636            throws SAXException
1637  {
1638
1639    if (null == m_entities)
1640    {
1641      m_entities = new Vector JavaDoc();
1642    }
1643
1644    try
1645    {
1646      systemId = SystemIDResolver.getAbsoluteURI(systemId,
1647                                                 getDocumentBaseURI());
1648    }
1649    catch (Exception JavaDoc e)
1650    {
1651      throw new org.xml.sax.SAXException JavaDoc(e);
1652    }
1653
1654    // private static final int ENTITY_FIELD_PUBLICID = 0;
1655
m_entities.addElement(publicId);
1656
1657    // private static final int ENTITY_FIELD_SYSTEMID = 1;
1658
m_entities.addElement(systemId);
1659
1660    // private static final int ENTITY_FIELD_NOTATIONNAME = 2;
1661
m_entities.addElement(notationName);
1662
1663    // private static final int ENTITY_FIELD_NAME = 3;
1664
m_entities.addElement(name);
1665  }
1666
1667  ////////////////////////////////////////////////////////////////////
1668
// Implementation of ContentHandler interface.
1669
////////////////////////////////////////////////////////////////////
1670

1671  /**
1672   * Receive a Locator object for document events.
1673   *
1674   * <p>By default, do nothing. Application writers may override this
1675   * method in a subclass if they wish to store the locator for use
1676   * with other document events.</p>
1677   *
1678   * @param locator A locator for all SAX document events.
1679   * @see org.xml.sax.ContentHandler#setDocumentLocator
1680   * @see org.xml.sax.Locator
1681   */

1682  public void setDocumentLocator(Locator JavaDoc locator)
1683  {
1684    m_locator = locator;
1685    m_systemId = locator.getSystemId();
1686  }
1687
1688  /**
1689   * Receive notification of the beginning of the document.
1690   *
1691   * @throws SAXException Any SAX exception, possibly
1692   * wrapping another exception.
1693   * @see org.xml.sax.ContentHandler#startDocument
1694   */

1695  public void startDocument() throws SAXException
1696  {
1697    if (DEBUG)
1698      System.out.println("startDocument");
1699
1700        
1701    int doc = addNode(DTM.DOCUMENT_NODE,
1702                      m_expandedNameTable.getExpandedTypeID(DTM.DOCUMENT_NODE),
1703                      DTM.NULL, DTM.NULL, 0, true);
1704
1705    m_parents.push(doc);
1706    m_previous = DTM.NULL;
1707
1708    m_contextIndexes.push(m_prefixMappings.size()); // for the next element.
1709
}
1710
1711  /**
1712   * Receive notification of the end of the document.
1713   *
1714   * @throws SAXException Any SAX exception, possibly
1715   * wrapping another exception.
1716   * @see org.xml.sax.ContentHandler#endDocument
1717   */

1718  public void endDocument() throws SAXException
1719  {
1720    if (DEBUG)
1721      System.out.println("endDocument");
1722
1723        charactersFlush();
1724
1725    m_nextsib.setElementAt(NULL,0);
1726
1727    if (m_firstch.elementAt(0) == NOTPROCESSED)
1728      m_firstch.setElementAt(NULL,0);
1729
1730    if (DTM.NULL != m_previous)
1731      m_nextsib.setElementAt(DTM.NULL,m_previous);
1732
1733    m_parents = null;
1734    m_prefixMappings = null;
1735    m_contextIndexes = null;
1736
1737    m_endDocumentOccured = true;
1738    
1739    // Bugzilla 4858: throw away m_locator. we cache m_systemId
1740
m_locator = null;
1741  }
1742
1743  /**
1744   * Receive notification of the start of a Namespace mapping.
1745   *
1746   * <p>By default, do nothing. Application writers may override this
1747   * method in a subclass to take specific actions at the start of
1748   * each Namespace prefix scope (such as storing the prefix mapping).</p>
1749   *
1750   * @param prefix The Namespace prefix being declared.
1751   * @param uri The Namespace URI mapped to the prefix.
1752   * @throws SAXException Any SAX exception, possibly
1753   * wrapping another exception.
1754   * @see org.xml.sax.ContentHandler#startPrefixMapping
1755   */

1756  public void startPrefixMapping(String JavaDoc prefix, String JavaDoc uri)
1757          throws SAXException
1758  {
1759
1760    if (DEBUG)
1761      System.out.println("startPrefixMapping: prefix: " + prefix + ", uri: "
1762                         + uri);
1763
1764    if(null == prefix)
1765      prefix = "";
1766    m_prefixMappings.addElement(prefix); // JDK 1.1.x compat -sc
1767
m_prefixMappings.addElement(uri); // JDK 1.1.x compat -sc
1768
}
1769
1770  /**
1771   * Receive notification of the end of a Namespace mapping.
1772   *
1773   * <p>By default, do nothing. Application writers may override this
1774   * method in a subclass to take specific actions at the end of
1775   * each prefix mapping.</p>
1776   *
1777   * @param prefix The Namespace prefix being declared.
1778   * @throws SAXException Any SAX exception, possibly
1779   * wrapping another exception.
1780   * @see org.xml.sax.ContentHandler#endPrefixMapping
1781   */

1782  public void endPrefixMapping(String JavaDoc prefix) throws SAXException
1783  {
1784    if (DEBUG)
1785      System.out.println("endPrefixMapping: prefix: " + prefix);
1786
1787    if(null == prefix)
1788      prefix = "";
1789
1790    int index = m_contextIndexes.peek() - 1;
1791
1792    do
1793    {
1794      index = m_prefixMappings.indexOf(prefix, ++index);
1795    } while ( (index >= 0) && ((index & 0x01) == 0x01) );
1796
1797
1798    if (index > -1)
1799    {
1800      m_prefixMappings.setElementAt("%@$#^@#", index);
1801      m_prefixMappings.setElementAt("%@$#^@#", index + 1);
1802    }
1803
1804    // no op
1805
}
1806
1807  /**
1808   * Check if a declaration has already been made for a given prefix.
1809   *
1810   * @param prefix non-null prefix string.
1811   *
1812   * @return true if the declaration has already been declared in the
1813   * current context.
1814   */

1815  protected boolean declAlreadyDeclared(String JavaDoc prefix)
1816  {
1817
1818    int startDecls = m_contextIndexes.peek();
1819    java.util.Vector JavaDoc prefixMappings = m_prefixMappings;
1820    int nDecls = prefixMappings.size();
1821
1822    for (int i = startDecls; i < nDecls; i += 2)
1823    {
1824      String JavaDoc prefixDecl = (String JavaDoc) prefixMappings.elementAt(i);
1825
1826      if (prefixDecl == null)
1827        continue;
1828
1829      if (prefixDecl.equals(prefix))
1830        return true;
1831    }
1832
1833    return false;
1834  }
1835
1836    boolean m_pastFirstElement=false;
1837
1838  /**
1839   * Receive notification of the start of an element.
1840   *
1841   * <p>By default, do nothing. Application writers may override this
1842   * method in a subclass to take specific actions at the start of
1843   * each element (such as allocating a new tree node or writing
1844   * output to a file).</p>
1845   *
1846   * @param name The element type name.
1847   *
1848   * @param uri The Namespace URI, or the empty string if the
1849   * element has no Namespace URI or if Namespace
1850   * processing is not being performed.
1851   * @param localName The local name (without prefix), or the
1852   * empty string if Namespace processing is not being
1853   * performed.
1854   * @param qName The qualified name (with prefix), or the
1855   * empty string if qualified names are not available.
1856   * @param attributes The specified or defaulted attributes.
1857   * @throws SAXException Any SAX exception, possibly
1858   * wrapping another exception.
1859   * @see org.xml.sax.ContentHandler#startElement
1860   */

1861  public void startElement(
1862          String JavaDoc uri, String JavaDoc localName, String JavaDoc qName, Attributes attributes)
1863            throws SAXException
1864  {
1865   if (DEBUG)
1866     {
1867      System.out.println("startElement: uri: " + uri + ", localname: "
1868                                                 + localName + ", qname: "+qName+", atts: " + attributes);
1869
1870            boolean DEBUG_ATTRS=true;
1871            if(DEBUG_ATTRS & attributes!=null)
1872            {
1873                int n = attributes.getLength();
1874                if(n==0)
1875                    System.out.println("\tempty attribute list");
1876                else for (int i = 0; i < n; i++)
1877                    System.out.println("\t attr: uri: " + attributes.getURI(i) +
1878                                                         ", localname: " + attributes.getLocalName(i) +
1879                                                         ", qname: " + attributes.getQName(i) +
1880                                                         ", type: " + attributes.getType(i) +
1881                                                         ", value: " + attributes.getValue(i)
1882                                                         );
1883            }
1884     }
1885        
1886    charactersFlush();
1887
1888    int exName = m_expandedNameTable.getExpandedTypeID(uri, localName, DTM.ELEMENT_NODE);
1889    String JavaDoc prefix = getPrefix(qName, uri);
1890    int prefixIndex = (null != prefix)
1891                      ? m_valuesOrPrefixes.stringToIndex(qName) : 0;
1892
1893    int elemNode = addNode(DTM.ELEMENT_NODE, exName,
1894                           m_parents.peek(), m_previous, prefixIndex, true);
1895
1896    if(m_indexing)
1897      indexNode(exName, elemNode);
1898    
1899
1900    m_parents.push(elemNode);
1901
1902    int startDecls = m_contextIndexes.peek();
1903    int nDecls = m_prefixMappings.size();
1904    int prev = DTM.NULL;
1905
1906    if(!m_pastFirstElement)
1907    {
1908      // SPECIAL CASE: Implied declaration at root element
1909
prefix="xml";
1910      String JavaDoc declURL = "http://www.w3.org/XML/1998/namespace";
1911      exName = m_expandedNameTable.getExpandedTypeID(null, prefix, DTM.NAMESPACE_NODE);
1912      int val = m_valuesOrPrefixes.stringToIndex(declURL);
1913      prev = addNode(DTM.NAMESPACE_NODE, exName, elemNode,
1914                     prev, val, false);
1915      m_pastFirstElement=true;
1916    }
1917
1918    for (int i = startDecls; i < nDecls; i += 2)
1919    {
1920      prefix = (String JavaDoc) m_prefixMappings.elementAt(i);
1921
1922      if (prefix == null)
1923        continue;
1924
1925      String JavaDoc declURL = (String JavaDoc) m_prefixMappings.elementAt(i + 1);
1926
1927      exName = m_expandedNameTable.getExpandedTypeID(null, prefix, DTM.NAMESPACE_NODE);
1928
1929      int val = m_valuesOrPrefixes.stringToIndex(declURL);
1930
1931      prev = addNode(DTM.NAMESPACE_NODE, exName, elemNode,
1932                     prev, val, false);
1933    }
1934
1935    int n = attributes.getLength();
1936
1937    for (int i = 0; i < n; i++)
1938    {
1939      String JavaDoc attrUri = attributes.getURI(i);
1940      String JavaDoc attrQName = attributes.getQName(i);
1941      String JavaDoc valString = attributes.getValue(i);
1942
1943      prefix = getPrefix(attrQName, attrUri);
1944
1945      int nodeType;
1946      
1947       String JavaDoc attrLocalName = attributes.getLocalName(i);
1948
1949      if ((null != attrQName)
1950              && (attrQName.equals("xmlns")
1951                  || attrQName.startsWith("xmlns:")))
1952      {
1953        if (declAlreadyDeclared(prefix))
1954          continue; // go to the next attribute.
1955

1956        nodeType = DTM.NAMESPACE_NODE;
1957      }
1958      else
1959      {
1960        nodeType = DTM.ATTRIBUTE_NODE;
1961
1962        if (attributes.getType(i).equalsIgnoreCase("ID"))
1963          setIDAttribute(valString, elemNode);
1964      }
1965
1966      // Bit of a hack... if somehow valString is null, stringToIndex will
1967
// return -1, which will make things very unhappy.
1968
if(null == valString)
1969        valString = "";
1970
1971      int val = m_valuesOrPrefixes.stringToIndex(valString);
1972      //String attrLocalName = attributes.getLocalName(i);
1973

1974      if (null != prefix)
1975      {
1976
1977        prefixIndex = m_valuesOrPrefixes.stringToIndex(attrQName);
1978
1979        int dataIndex = m_data.size();
1980
1981        m_data.addElement(prefixIndex);
1982        m_data.addElement(val);
1983
1984        val = -dataIndex;
1985      }
1986
1987      exName = m_expandedNameTable.getExpandedTypeID(attrUri, attrLocalName, nodeType);
1988      prev = addNode(nodeType, exName, elemNode, prev, val,
1989                     false);
1990    }
1991
1992    if (DTM.NULL != prev)
1993      m_nextsib.setElementAt(DTM.NULL,prev);
1994
1995    if (null != m_wsfilter)
1996    {
1997      short wsv = m_wsfilter.getShouldStripSpace(makeNodeHandle(elemNode), this);
1998      boolean shouldStrip = (DTMWSFilter.INHERIT == wsv)
1999                            ? getShouldStripWhitespace()
2000                            : (DTMWSFilter.STRIP == wsv);
2001
2002      pushShouldStripWhitespace(shouldStrip);
2003    }
2004
2005    m_previous = DTM.NULL;
2006
2007    m_contextIndexes.push(m_prefixMappings.size()); // for the children.
2008
}
2009
2010  /**
2011   * Receive notification of the end of an element.
2012   *
2013   * <p>By default, do nothing. Application writers may override this
2014   * method in a subclass to take specific actions at the end of
2015   * each element (such as finalising a tree node or writing
2016   * output to a file).</p>
2017   *
2018   * @param name The element type name.
2019   * @param attributes The specified or defaulted attributes.
2020   *
2021   * @param uri The Namespace URI, or the empty string if the
2022   * element has no Namespace URI or if Namespace
2023   * processing is not being performed.
2024   * @param localName The local name (without prefix), or the
2025   * empty string if Namespace processing is not being
2026   * performed.
2027   * @param qName The qualified XML 1.0 name (with prefix), or the
2028   * empty string if qualified names are not available.
2029   * @throws SAXException Any SAX exception, possibly
2030   * wrapping another exception.
2031   * @see org.xml.sax.ContentHandler#endElement
2032   */

2033  public void endElement(String JavaDoc uri, String JavaDoc localName, String JavaDoc qName)
2034          throws SAXException
2035  {
2036   if (DEBUG)
2037      System.out.println("endElement: uri: " + uri + ", localname: "
2038                                                 + localName + ", qname: "+qName);
2039
2040    charactersFlush();
2041
2042    // If no one noticed, startPrefixMapping is a drag.
2043
// Pop the context for the last child (the one pushed by startElement)
2044
m_contextIndexes.quickPop(1);
2045
2046    // Do it again for this one (the one pushed by the last endElement).
2047
int topContextIndex = m_contextIndexes.peek();
2048    if (topContextIndex != m_prefixMappings.size()) {
2049      m_prefixMappings.setSize(topContextIndex);
2050    }
2051
2052    int lastNode = m_previous;
2053
2054    m_previous = m_parents.pop();
2055
2056    // If lastNode is still DTM.NULL, this element had no children
2057
if (DTM.NULL == lastNode)
2058      m_firstch.setElementAt(DTM.NULL,m_previous);
2059    else
2060      m_nextsib.setElementAt(DTM.NULL,lastNode);
2061
2062    popShouldStripWhitespace();
2063  }
2064
2065  /**
2066   * Receive notification of character data inside an element.
2067   *
2068   * <p>By default, do nothing. Application writers may override this
2069   * method to take specific actions for each chunk of character data
2070   * (such as adding the data to a node or buffer, or printing it to
2071   * a file).</p>
2072   *
2073   * @param ch The characters.
2074   * @param start The start position in the character array.
2075   * @param length The number of characters to use from the
2076   * character array.
2077   * @throws SAXException Any SAX exception, possibly
2078   * wrapping another exception.
2079   * @see org.xml.sax.ContentHandler#characters
2080   */

2081  public void characters(char ch[], int start, int length) throws SAXException
2082  {
2083    if (m_textPendingStart == -1) // First one in this block
2084
{
2085      m_textPendingStart = m_chars.size();
2086      m_coalescedTextType = m_textType;
2087    }
2088    // Type logic: If all adjacent text is CDATASections, the
2089
// concatentated text is treated as a single CDATASection (see
2090
// initialization above). If any were ordinary Text, the whole
2091
// thing is treated as Text. This may be worth %REVIEW%ing.
2092
else if (m_textType == DTM.TEXT_NODE)
2093    {
2094      m_coalescedTextType = DTM.TEXT_NODE;
2095    }
2096
2097    m_chars.append(ch, start, length);
2098  }
2099
2100  /**
2101   * Receive notification of ignorable whitespace in element content.
2102   *
2103   * <p>By default, do nothing. Application writers may override this
2104   * method to take specific actions for each chunk of ignorable
2105   * whitespace (such as adding data to a node or buffer, or printing
2106   * it to a file).</p>
2107   *
2108   * @param ch The whitespace characters.
2109   * @param start The start position in the character array.
2110   * @param length The number of characters to use from the
2111   * character array.
2112   * @throws SAXException Any SAX exception, possibly
2113   * wrapping another exception.
2114   * @see org.xml.sax.ContentHandler#ignorableWhitespace
2115   */

2116  public void ignorableWhitespace(char ch[], int start, int length)
2117          throws SAXException
2118  {
2119
2120    // %OPT% We can probably take advantage of the fact that we know this
2121
// is whitespace.
2122
characters(ch, start, length);
2123  }
2124
2125  /**
2126   * Receive notification of a processing instruction.
2127   *
2128   * <p>By default, do nothing. Application writers may override this
2129   * method in a subclass to take specific actions for each
2130   * processing instruction, such as setting status variables or
2131   * invoking other methods.</p>
2132   *
2133   * @param target The processing instruction target.
2134   * @param data The processing instruction data, or null if
2135   * none is supplied.
2136   * @throws SAXException Any SAX exception, possibly
2137   * wrapping another exception.
2138   * @see org.xml.sax.ContentHandler#processingInstruction
2139   */

2140  public void processingInstruction(String JavaDoc target, String JavaDoc data)
2141          throws SAXException
2142  {
2143    if (DEBUG)
2144         System.out.println("processingInstruction: target: " + target +", data: "+data);
2145
2146    charactersFlush();
2147
2148    int exName = m_expandedNameTable.getExpandedTypeID(null, target,
2149                                         DTM.PROCESSING_INSTRUCTION_NODE);
2150    int dataIndex = m_valuesOrPrefixes.stringToIndex(data);
2151
2152    m_previous = addNode(DTM.PROCESSING_INSTRUCTION_NODE, exName,
2153                         m_parents.peek(), m_previous,
2154                         dataIndex, false);
2155  }
2156
2157  /**
2158   * Receive notification of a skipped entity.
2159   *
2160   * <p>By default, do nothing. Application writers may override this
2161   * method in a subclass to take specific actions for each
2162   * processing instruction, such as setting status variables or
2163   * invoking other methods.</p>
2164   *
2165   * @param name The name of the skipped entity.
2166   * @throws SAXException Any SAX exception, possibly
2167   * wrapping another exception.
2168   * @see org.xml.sax.ContentHandler#processingInstruction
2169   */

2170  public void skippedEntity(String JavaDoc name) throws SAXException
2171  {
2172
2173    // %REVIEW% What should be done here?
2174
// no op
2175
}
2176
2177  ////////////////////////////////////////////////////////////////////
2178
// Implementation of the ErrorHandler interface.
2179
////////////////////////////////////////////////////////////////////
2180

2181  /**
2182   * Receive notification of a parser warning.
2183   *
2184   * <p>The default implementation does nothing. Application writers
2185   * may override this method in a subclass to take specific actions
2186   * for each warning, such as inserting the message in a log file or
2187   * printing it to the console.</p>
2188   *
2189   * @param e The warning information encoded as an exception.
2190   * @throws SAXException Any SAX exception, possibly
2191   * wrapping another exception.
2192   * @see org.xml.sax.ErrorHandler#warning
2193   * @see org.xml.sax.SAXParseException
2194   */

2195  public void warning(SAXParseException e) throws SAXException
2196  {
2197
2198    // %REVIEW% Is there anyway to get the JAXP error listener here?
2199
System.err.println(e.getMessage());
2200  }
2201
2202  /**
2203   * Receive notification of a recoverable parser error.
2204   *
2205   * <p>The default implementation does nothing. Application writers
2206   * may override this method in a subclass to take specific actions
2207   * for each error, such as inserting the message in a log file or
2208   * printing it to the console.</p>
2209   *
2210   * @param e The warning information encoded as an exception.
2211   * @throws SAXException Any SAX exception, possibly
2212   * wrapping another exception.
2213   * @see org.xml.sax.ErrorHandler#warning
2214   * @see org.xml.sax.SAXParseException
2215   */

2216  public void error(SAXParseException e) throws SAXException
2217  {
2218    throw e;
2219  }
2220
2221  /**
2222   * Report a fatal XML parsing error.
2223   *
2224   * <p>The default implementation throws a SAXParseException.
2225   * Application writers may override this method in a subclass if
2226   * they need to take specific actions for each fatal error (such as
2227   * collecting all of the errors into a single report): in any case,
2228   * the application must stop all regular processing when this
2229   * method is invoked, since the document is no longer reliable, and
2230   * the parser may no longer report parsing events.</p>
2231   *
2232   * @param e The error information encoded as an exception.
2233   * @throws SAXException Any SAX exception, possibly
2234   * wrapping another exception.
2235   * @see org.xml.sax.ErrorHandler#fatalError
2236   * @see org.xml.sax.SAXParseException
2237   */

2238  public void fatalError(SAXParseException e) throws SAXException
2239  {
2240    throw e;
2241  }
2242
2243  ////////////////////////////////////////////////////////////////////
2244
// Implementation of the DeclHandler interface.
2245
////////////////////////////////////////////////////////////////////
2246

2247  /**
2248   * Report an element type declaration.
2249   *
2250   * <p>The content model will consist of the string "EMPTY", the
2251   * string "ANY", or a parenthesised group, optionally followed
2252   * by an occurrence indicator. The model will be normalized so
2253   * that all whitespace is removed,and will include the enclosing
2254   * parentheses.</p>
2255   *
2256   * @param name The element type name.
2257   * @param model The content model as a normalized string.
2258   * @throws SAXException The application may raise an exception.
2259   */

2260  public void elementDecl(String JavaDoc name, String JavaDoc model) throws SAXException
2261  {
2262
2263    // no op
2264
}
2265
2266  /**
2267   * Report an attribute type declaration.
2268   *
2269   * <p>Only the effective (first) declaration for an attribute will
2270   * be reported. The type will be one of the strings "CDATA",
2271   * "ID", "IDREF", "IDREFS", "NMTOKEN", "NMTOKENS", "ENTITY",
2272   * "ENTITIES", or "NOTATION", or a parenthesized token group with
2273   * the separator "|" and all whitespace removed.</p>
2274   *
2275   * @param eName The name of the associated element.
2276   * @param aName The name of the attribute.
2277   * @param type A string representing the attribute type.
2278   * @param valueDefault A string representing the attribute default
2279   * ("#IMPLIED", "#REQUIRED", or "#FIXED") or null if
2280   * none of these applies.
2281   * @param value A string representing the attribute's default value,
2282   * or null if there is none.
2283   * @throws SAXException The application may raise an exception.
2284   */

2285  public void attributeDecl(
2286          String JavaDoc eName, String JavaDoc aName, String JavaDoc type, String JavaDoc valueDefault, String JavaDoc value)
2287            throws SAXException
2288  {
2289
2290    // no op
2291
}
2292
2293  /**
2294   * Report an internal entity declaration.
2295   *
2296   * <p>Only the effective (first) declaration for each entity
2297   * will be reported.</p>
2298   *
2299   * @param name The name of the entity. If it is a parameter
2300   * entity, the name will begin with '%'.
2301   * @param value The replacement text of the entity.
2302   * @throws SAXException The application may raise an exception.
2303   * @see #externalEntityDecl
2304   * @see org.xml.sax.DTDHandler#unparsedEntityDecl
2305   */

2306  public void internalEntityDecl(String JavaDoc name, String JavaDoc value)
2307          throws SAXException
2308  {
2309
2310    // no op
2311
}
2312
2313  /**
2314   * Report a parsed external entity declaration.
2315   *
2316   * <p>Only the effective (first) declaration for each entity
2317   * will be reported.</p>
2318   *
2319   * @param name The name of the entity. If it is a parameter
2320   * entity, the name will begin with '%'.
2321   * @param publicId The declared public identifier of the entity, or
2322   * null if none was declared.
2323   * @param systemId The declared system identifier of the entity.
2324   * @throws SAXException The application may raise an exception.
2325   * @see #internalEntityDecl
2326   * @see org.xml.sax.DTDHandler#unparsedEntityDecl
2327   */

2328  public void externalEntityDecl(
2329          String JavaDoc name, String JavaDoc publicId, String JavaDoc systemId) throws SAXException
2330  {
2331
2332    // no op
2333
}
2334
2335  ////////////////////////////////////////////////////////////////////
2336
// Implementation of the LexicalHandler interface.
2337
////////////////////////////////////////////////////////////////////
2338

2339  /**
2340   * Report the start of DTD declarations, if any.
2341   *
2342   * <p>Any declarations are assumed to be in the internal subset
2343   * unless otherwise indicated by a {@link #startEntity startEntity}
2344   * event.</p>
2345   *
2346   * <p>Note that the start/endDTD events will appear within
2347   * the start/endDocument events from ContentHandler and
2348   * before the first startElement event.</p>
2349   *
2350   * @param name The document type name.
2351   * @param publicId The declared public identifier for the
2352   * external DTD subset, or null if none was declared.
2353   * @param systemId The declared system identifier for the
2354   * external DTD subset, or null if none was declared.
2355   * @throws SAXException The application may raise an
2356   * exception.
2357   * @see #endDTD
2358   * @see #startEntity
2359   */

2360  public void startDTD(String JavaDoc name, String JavaDoc publicId, String JavaDoc systemId)
2361          throws SAXException
2362  {
2363
2364    m_insideDTD = true;
2365  }
2366
2367  /**
2368   * Report the end of DTD declarations.
2369   *
2370   * @throws SAXException The application may raise an exception.
2371   * @see #startDTD
2372   */

2373  public void endDTD() throws SAXException
2374  {
2375
2376    m_insideDTD = false;
2377  }
2378
2379  /**
2380   * Report the beginning of an entity in content.
2381   *
2382   * <p><strong>NOTE:</entity> entity references in attribute
2383   * values -- and the start and end of the document entity --
2384   * are never reported.</p>
2385   *
2386   * <p>The start and end of the external DTD subset are reported
2387   * using the pseudo-name "[dtd]". All other events must be
2388   * properly nested within start/end entity events.</p>
2389   *
2390   * <p>Note that skipped entities will be reported through the
2391   * {@link org.xml.sax.ContentHandler#skippedEntity skippedEntity}
2392   * event, which is part of the ContentHandler interface.</p>
2393   *
2394   * @param name The name of the entity. If it is a parameter
2395   * entity, the name will begin with '%'.
2396   * @throws SAXException The application may raise an exception.
2397   * @see #endEntity
2398   * @see org.xml.sax.ext.DeclHandler#internalEntityDecl
2399   * @see org.xml.sax.ext.DeclHandler#externalEntityDecl
2400   */

2401  public void startEntity(String JavaDoc name) throws SAXException
2402  {
2403
2404    // no op
2405
}
2406
2407  /**
2408   * Report the end of an entity.
2409   *
2410   * @param name The name of the entity that is ending.
2411   * @throws SAXException The application may raise an exception.
2412   * @see #startEntity
2413   */

2414  public void endEntity(String JavaDoc name) throws SAXException
2415  {
2416
2417    // no op
2418
}
2419
2420  /**
2421   * Report the start of a CDATA section.
2422   *
2423   * <p>The contents of the CDATA section will be reported through
2424   * the regular {@link org.xml.sax.ContentHandler#characters
2425   * characters} event.</p>
2426   *
2427   * @throws SAXException The application may raise an exception.
2428   * @see #endCDATA
2429   */

2430  public void startCDATA() throws SAXException
2431  {
2432    m_textType = DTM.CDATA_SECTION_NODE;
2433  }
2434
2435  /**
2436   * Report the end of a CDATA section.
2437   *
2438   * @throws SAXException The application may raise an exception.
2439   * @see #startCDATA
2440   */

2441  public void endCDATA() throws SAXException
2442  {
2443    m_textType = DTM.TEXT_NODE;
2444  }
2445
2446  /**
2447   * Report an XML comment anywhere in the document.
2448   *
2449   * <p>This callback will be used for comments inside or outside the
2450   * document element, including comments in the external DTD
2451   * subset (if read).</p>
2452   *
2453   * @param ch An array holding the characters in the comment.
2454   * @param start The starting position in the array.
2455   * @param length The number of characters to use from the array.
2456   * @throws SAXException The application may raise an exception.
2457   */

2458  public void comment(char ch[], int start, int length) throws SAXException
2459  {
2460
2461    if (m_insideDTD) // ignore comments if we're inside the DTD
2462
return;
2463
2464    charactersFlush();
2465
2466    int exName = m_expandedNameTable.getExpandedTypeID(DTM.COMMENT_NODE);
2467
2468    // For now, treat comments as strings... I guess we should do a
2469
// seperate FSB buffer instead.
2470
int dataIndex = m_valuesOrPrefixes.stringToIndex(new String JavaDoc(ch, start,
2471                      length));
2472
2473
2474    m_previous = addNode(DTM.COMMENT_NODE, exName,
2475                         m_parents.peek(), m_previous, dataIndex, false);
2476  }
2477
2478  /**
2479   * Set a run time property for this DTM instance.
2480   *
2481   * %REVIEW% Now that we no longer use this method to support
2482   * getSourceLocatorFor, can we remove it?
2483   *
2484   * @param property a <code>String</code> value
2485   * @param value an <code>Object</code> value
2486   */

2487  public void setProperty(String JavaDoc property, Object JavaDoc value)
2488  {
2489  }
2490
2491  /** Retrieve the SourceLocator associated with a specific node.
2492   * This is only meaningful if the XalanProperties.SOURCE_LOCATION flag was
2493   * set True using setProperty; if it was never set, or was set false, we
2494   * will return null.
2495   *
2496   * (We _could_ return a locator with the document's base URI and bogus
2497   * line/column information. Trying that; see the else clause.)
2498   * */

2499  public SourceLocator JavaDoc getSourceLocatorFor(int node)
2500  {
2501    if (m_useSourceLocationProperty)
2502    {
2503
2504      node = makeNodeIdentity(node);
2505      
2506
2507      return new NodeLocator(null,
2508                             m_sourceSystemId.elementAt(node),
2509                             m_sourceLine.elementAt(node),
2510                             m_sourceColumn.elementAt(node));
2511    }
2512    else if(m_locator!=null)
2513    {
2514        return new NodeLocator(null,m_locator.getSystemId(),-1,-1);
2515    }
2516    else if(m_systemId!=null)
2517    {
2518        return new NodeLocator(null,m_systemId,-1,-1);
2519    }
2520    return null;
2521  }
2522}
2523
Popular Tags