001    /*
002     * Licensed to the Apache Software Foundation (ASF) under one
003     * or more contributor license agreements. See the NOTICE file
004     * distributed with this work for additional information
005     * regarding copyright ownership. The ASF licenses this file
006     * to you under the Apache License, Version 2.0 (the  "License");
007     * you may not use this file except in compliance with the License.
008     * You may obtain a copy of the License at
009     *
010     *     http://www.apache.org/licenses/LICENSE-2.0
011     *
012     * Unless required by applicable law or agreed to in writing, software
013     * distributed under the License is distributed on an "AS IS" BASIS,
014     * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015     * See the License for the specific language governing permissions and
016     * limitations under the License.
017     */
018    /*
019     * $Id: DTMNodeIterator.java 468653 2006-10-28 07:07:05Z minchau $
020     */
021    package org.apache.xml.dtm.ref;
022    
023    import org.apache.xml.dtm.DTM;
024    import org.apache.xml.dtm.DTMDOMException;
025    import org.apache.xml.dtm.DTMIterator;
026    
027    import org.w3c.dom.DOMException;
028    import org.w3c.dom.Node;
029    import org.w3c.dom.traversal.NodeFilter;
030    
031    /**
032     * <code>DTMNodeIterator</code> gives us an implementation of the 
033     * DTMNodeIterator which returns DOM nodes.
034     *
035     * Please note that this is not necessarily equivlaent to a DOM
036     * NodeIterator operating over the same document. In particular:
037     * <ul>
038     *
039     * <li>If there are several Text nodes in logical succession (ie,
040     * across CDATASection and EntityReference boundaries), we will return
041     * only the first; the caller is responsible for stepping through
042     * them.
043     * (%REVIEW% Provide a convenience routine here to assist, pending
044     * proposed DOM Level 3 getAdjacentText() operation?) </li>
045     *
046     * <li>Since the whole XPath/XSLT architecture assumes that the source
047     * document is not altered while we're working with it, we do not
048     * promise to implement the DOM NodeIterator's "maintain current
049     * position" response to document mutation. </li>
050     *
051     * <li>Since our design for XPath NodeIterators builds a stateful
052     * filter directly into the traversal object, getNodeFilter() is not
053     * supported.</li>
054     *
055     * </ul>
056     *
057     * <p>State: In progress!!</p>
058     * */
059    public class DTMNodeIterator implements org.w3c.dom.traversal.NodeIterator
060    {
061      private DTMIterator dtm_iter;
062      private boolean valid=true;
063    
064      //================================================================
065      // Methods unique to this class
066    
067      /** Public constructor: Wrap a DTMNodeIterator around an existing
068       * and preconfigured DTMIterator
069       * */
070      public DTMNodeIterator(DTMIterator dtmIterator)
071        {
072          try
073          {
074            dtm_iter=(DTMIterator)dtmIterator.clone();
075          }
076          catch(CloneNotSupportedException cnse)
077          {
078            throw new org.apache.xml.utils.WrappedRuntimeException(cnse);
079          }
080        }
081    
082      /** Access the wrapped DTMIterator. I'm not sure whether anyone will
083       * need this or not, but let's write it and think about it.
084       * */
085      public DTMIterator getDTMIterator()
086        {
087          return dtm_iter;
088        }
089      
090    
091      //================================================================
092      // org.w3c.dom.traversal.NodeFilter API follows
093    
094      /** Detaches the NodeIterator from the set which it iterated over,
095       * releasing any computational resources and placing the iterator in
096       * the INVALID state.
097       * */
098      public void detach() 
099        {
100          // Theoretically, we could release dtm_iter at this point. But
101          // some of the operations may still want to consult it even though
102          // navigation is now invalid.
103          valid=false;
104        }
105    
106      /** The value of this flag determines whether the children
107       * of entity reference nodes are visible to the iterator.
108       *
109       * @return false, always (the DTM model flattens entity references)
110       * */
111      public boolean getExpandEntityReferences()
112        {
113          return false;
114        }
115      
116      /** Return a handle to the filter used to screen nodes.
117       *
118       * This is ill-defined in Xalan's usage of Nodeiterator, where we have
119       * built stateful XPath-based filtering directly into the traversal
120       * object. We could return something which supports the NodeFilter interface
121       * and allows querying whether a given node would be permitted if it appeared
122       * as our next node, but in the current implementation that would be very
123       * complex -- and just isn't all that useful.
124       * 
125       * @throws DOMException -- NOT_SUPPORTED_ERROR because I can't think
126       * of anything more useful to do in this case
127       * */
128      public NodeFilter getFilter() 
129        {
130          throw new DTMDOMException(DOMException.NOT_SUPPORTED_ERR);
131        }
132      
133    
134      /** @return The root node of the NodeIterator, as specified
135       * when it was created.
136       * */
137      public Node getRoot()
138        {
139          int handle=dtm_iter.getRoot();
140          return dtm_iter.getDTM(handle).getNode(handle);
141        }
142      
143    
144      /** Return a mask describing which node types are presented via the
145       * iterator.
146       **/
147      public int getWhatToShow()
148        {
149          return dtm_iter.getWhatToShow();
150        }
151    
152      /** @return the next node in the set and advance the position of the
153       * iterator in the set.
154       *
155       * @throws DOMException - INVALID_STATE_ERR Raised if this method is
156       * called after the detach method was invoked.
157       *  */
158      public Node nextNode() throws DOMException
159        {
160          if(!valid)
161            throw new DTMDOMException(DOMException.INVALID_STATE_ERR);
162          
163          int handle=dtm_iter.nextNode();
164          if (handle==DTM.NULL)
165            return null;
166          return dtm_iter.getDTM(handle).getNode(handle);
167        }
168      
169    
170      /** @return the next previous in the set and advance the position of the
171       * iterator in the set.
172       *
173       * @throws DOMException - INVALID_STATE_ERR Raised if this method is
174       * called after the detach method was invoked.
175       *  */
176      public Node previousNode() 
177        {
178          if(!valid)
179            throw new DTMDOMException(DOMException.INVALID_STATE_ERR);
180          
181          int handle=dtm_iter.previousNode();
182          if (handle==DTM.NULL)
183            return null;      
184          return dtm_iter.getDTM(handle).getNode(handle);
185        }
186    }