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