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: DTMAxisIterNodeList.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.DTMAxisIterator;
025    import org.apache.xml.utils.IntVector;
026    
027    import org.w3c.dom.Node;
028    
029    /**
030     * <code>DTMAxisNodeList</code> gives us an implementation of the DOM's
031     * NodeList interface wrapped around a DTM Iterator. The author
032     * considers this something of an abominations, since NodeList was not
033     * intended to be a general purpose "list of nodes" API and is
034     * generally considered by the DOM WG to have be a mistake... but I'm
035     * told that some of the XPath/XSLT folks say they must have this
036     * solution.
037     *
038     * Please note that this is not necessarily equivlaent to a DOM
039     * NodeList operating over the same document. In particular:
040     * <ul>
041     *
042     * <li>If there are several Text nodes in logical succession (ie,
043     * across CDATASection and EntityReference boundaries), we will return
044     * only the first; the caller is responsible for stepping through
045     * them.
046     * (%REVIEW% Provide a convenience routine here to assist, pending
047     * proposed DOM Level 3 getAdjacentText() operation?) </li>
048     *
049     * <li>Since the whole XPath/XSLT architecture assumes that the source
050     * document is not altered while we're working with it, we do not
051     * promise to implement the DOM NodeList's "live view" response to
052     * document mutation. </li>
053     *
054     * </ul>
055     *
056     * <p>State: In progress!!</p>
057     * */
058    public class DTMAxisIterNodeList extends DTMNodeListBase {
059        private DTM m_dtm;
060        private DTMAxisIterator m_iter;
061        private IntVector m_cachedNodes;
062        private int m_last = -1;
063        //================================================================
064        // Methods unique to this class
065        private DTMAxisIterNodeList() {
066        }
067    
068        /**
069         * Public constructor: Wrap a DTMNodeList around an existing
070         * and preconfigured DTMAxisIterator
071         */
072        public DTMAxisIterNodeList(DTM dtm, DTMAxisIterator dtmAxisIterator) {
073            if (dtmAxisIterator == null) {
074                m_last = 0;
075            } else {
076                m_cachedNodes = new IntVector();
077                m_dtm = dtm;
078            }
079            m_iter = dtmAxisIterator;
080        }
081    
082        /**
083         * Access the wrapped DTMIterator. I'm not sure whether anyone will
084         * need this or not, but let's write it and think about it.
085         *
086         */
087        public DTMAxisIterator getDTMAxisIterator() {
088            return m_iter;
089        }
090      
091    
092        //================================================================
093        // org.w3c.dom.NodeList API follows
094    
095        /**
096         * Returns the <code>index</code>th item in the collection. If 
097         * <code>index</code> is greater than or equal to the number of nodes in 
098         * the list, this returns <code>null</code>.
099         * @param index Index into the collection.
100         * @return The node at the <code>index</code>th position in the 
101         *   <code>NodeList</code>, or <code>null</code> if that is not a valid 
102         *   index.
103         */
104        public Node item(int index) {
105            if (m_iter != null) {
106                int node;
107                int count = m_cachedNodes.size();
108    
109                if (count > index) {
110                    node = m_cachedNodes.elementAt(index);
111                    return m_dtm.getNode(node);
112                } else if (m_last == -1) {
113                    while (((node = m_iter.next()) != DTMAxisIterator.END)
114                               && count <= index) {
115                        m_cachedNodes.addElement(node);
116                        count++;
117                    }
118                    if (node == DTMAxisIterator.END) {
119                        m_last = count;
120                    } else {
121                        return m_dtm.getNode(node);
122                    }
123                }
124            }
125            return null;
126        }
127    
128        /**
129         * The number of nodes in the list. The range of valid child node indices 
130         * is 0 to <code>length-1</code> inclusive. 
131         */
132        public int getLength() {
133            if (m_last == -1) {
134                int node;
135                while ((node = m_iter.next()) != DTMAxisIterator.END) {
136                    m_cachedNodes.addElement(node);
137                }
138                m_last = m_cachedNodes.size();
139            }
140            return m_last;
141        }
142    }