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: KeyIterator.java 468645 2006-10-28 06:57:24Z minchau $
20 */
21package org.apache.xalan.transformer;
22
23import java.util.Vector;
24
25import javax.xml.transform.TransformerException;
26
27import org.apache.xalan.res.XSLMessages;
28import org.apache.xalan.res.XSLTErrorResources;
29import org.apache.xalan.templates.KeyDeclaration;
30import org.apache.xml.dtm.Axis;
31import org.apache.xml.dtm.DTMIterator;
32import org.apache.xml.utils.QName;
33import org.apache.xpath.XPath;
34import org.apache.xpath.axes.OneStepIteratorForward;
35
36/**
37 * This class implements an optimized iterator for
38 * "key()" patterns, matching each node to the
39 * match attribute in one or more xsl:key declarations.
40 * @xsl.usage internal
41 */
42public class KeyIterator extends OneStepIteratorForward
43{
44    static final long serialVersionUID = -1349109910100249661L;
45
46  /** Key name.
47   *  @serial           */
48  private QName m_name;
49
50  /**
51   * Get the key name from a key declaration this iterator will process
52   *
53   *
54   * @return Key name
55   */
56  public QName getName()
57  {
58    return m_name;
59  }
60
61  /** Vector of Key declarations in the stylesheet.
62   *  @serial          */
63  private Vector m_keyDeclarations;
64
65  /**
66   * Get the key declarations from the stylesheet
67   *
68   *
69   * @return Vector containing the key declarations from the stylesheet
70   */
71  public Vector getKeyDeclarations()
72  {
73    return m_keyDeclarations;
74  }
75
76  /**
77    * Create a KeyIterator object.
78    *
79    * @throws javax.xml.transform.TransformerException
80    */
81  KeyIterator(QName name, Vector keyDeclarations)
82  {
83    super(Axis.ALL);
84    m_keyDeclarations = keyDeclarations;
85    // m_prefixResolver = nscontext;
86    m_name = name;
87  }
88
89  /**
90   *  Test whether a specified node is visible in the logical view of a
91   * TreeWalker or NodeIterator. This function will be called by the
92   * implementation of TreeWalker and NodeIterator; it is not intended to
93   * be called directly from user code.
94   *
95   * @param testNode  The node to check to see if it passes the filter or not.
96   *
97   * @return  a constant to determine whether the node is accepted,
98   *   rejected, or skipped, as defined  above .
99   */
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}
154