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: KeyIterator.java 468645 2006-10-28 06:57:24Z minchau $
020     */
021    package org.apache.xalan.transformer;
022    
023    import java.util.Vector;
024    
025    import javax.xml.transform.TransformerException;
026    
027    import org.apache.xalan.res.XSLMessages;
028    import org.apache.xalan.res.XSLTErrorResources;
029    import org.apache.xalan.templates.KeyDeclaration;
030    import org.apache.xml.dtm.Axis;
031    import org.apache.xml.dtm.DTMIterator;
032    import org.apache.xml.utils.QName;
033    import org.apache.xpath.XPath;
034    import org.apache.xpath.axes.OneStepIteratorForward;
035    
036    /**
037     * This class implements an optimized iterator for 
038     * "key()" patterns, matching each node to the 
039     * match attribute in one or more xsl:key declarations.
040     * @xsl.usage internal
041     */
042    public class KeyIterator extends OneStepIteratorForward
043    {
044        static final long serialVersionUID = -1349109910100249661L;
045    
046      /** Key name.
047       *  @serial           */
048      private QName m_name;
049    
050      /**
051       * Get the key name from a key declaration this iterator will process
052       *
053       *
054       * @return Key name
055       */
056      public QName getName()
057      {
058        return m_name;
059      }
060    
061      /** Vector of Key declarations in the stylesheet.
062       *  @serial          */
063      private Vector m_keyDeclarations;
064    
065      /**
066       * Get the key declarations from the stylesheet 
067       *
068       *
069       * @return Vector containing the key declarations from the stylesheet
070       */
071      public Vector getKeyDeclarations()
072      {
073        return m_keyDeclarations;
074      }
075    
076      /**
077        * Create a KeyIterator object.
078        *
079        * @throws javax.xml.transform.TransformerException
080        */
081      KeyIterator(QName name, Vector keyDeclarations)
082      {
083        super(Axis.ALL);
084        m_keyDeclarations = keyDeclarations;
085        // m_prefixResolver = nscontext;
086        m_name = name;
087      }
088    
089      /**
090       *  Test whether a specified node is visible in the logical view of a
091       * TreeWalker or NodeIterator. This function will be called by the
092       * implementation of TreeWalker and NodeIterator; it is not intended to
093       * be called directly from user code.
094       * 
095       * @param testNode  The node to check to see if it passes the filter or not.
096       *
097       * @return  a constant to determine whether the node is accepted,
098       *   rejected, or skipped, as defined  above .
099       */
100      public short acceptNode(int testNode)
101      {
102        boolean foundKey = false;
103        KeyIterator ki = (KeyIterator) m_lpi;
104        org.apache.xpath.XPathContext xctxt = ki.getXPathContext();
105        Vector keys = ki.getKeyDeclarations();
106    
107        QName name = ki.getName();
108        try
109        {
110          // System.out.println("lookupKey: "+lookupKey);
111          int nDeclarations = keys.size();
112    
113          // Walk through each of the declarations made with xsl:key
114          for (int i = 0; i < nDeclarations; i++)
115          {
116            KeyDeclaration kd = (KeyDeclaration) keys.elementAt(i);
117    
118            // Only continue if the name on this key declaration
119            // matches the name on the iterator for this walker. 
120            if (!kd.getName().equals(name))
121              continue;
122    
123            foundKey = true;
124            // xctxt.setNamespaceContext(ki.getPrefixResolver());
125    
126            // See if our node matches the given key declaration according to 
127            // the match attribute on xsl:key.
128            XPath matchExpr = kd.getMatch();
129            double score = matchExpr.getMatchScore(xctxt, testNode);
130    
131            if (score == kd.getMatch().MATCH_SCORE_NONE)
132              continue;
133    
134            return DTMIterator.FILTER_ACCEPT;
135    
136          } // end for(int i = 0; i < nDeclarations; i++)
137        }
138        catch (TransformerException se)
139        {
140    
141          // TODO: What to do?
142        }
143    
144        if (!foundKey)
145          throw new RuntimeException(
146            XSLMessages.createMessage(
147              XSLTErrorResources.ER_NO_XSLKEY_DECLARATION,
148              new Object[] { name.getLocalName()}));
149              
150        return DTMIterator.FILTER_REJECT;
151      }
152    
153    }