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: KeyRefIterator.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 org.apache.xalan.res.XSLMessages;
026 import org.apache.xalan.res.XSLTErrorResources;
027 import org.apache.xalan.templates.KeyDeclaration;
028 import org.apache.xml.dtm.DTM;
029 import org.apache.xml.dtm.DTMIterator;
030 import org.apache.xml.utils.QName;
031 import org.apache.xml.utils.XMLString;
032 import org.apache.xpath.objects.XNodeSet;
033 import org.apache.xpath.objects.XObject;
034
035 /**
036 * This class filters nodes from a key iterator, according to
037 * whether or not the use value matches the ref value.
038 * @xsl.usage internal
039 */
040 public class KeyRefIterator extends org.apache.xpath.axes.ChildTestIterator
041 {
042 static final long serialVersionUID = 3837456451659435102L;
043 /**
044 * Constructor KeyRefIterator
045 *
046 *
047 * @param ref Key value to match
048 * @param ki The main key iterator used to walk the source tree
049 */
050 public KeyRefIterator(QName name, XMLString ref, Vector keyDecls, DTMIterator ki)
051 {
052 super(null);
053 m_name = name;
054 m_ref = ref;
055 m_keyDeclarations = keyDecls;
056 m_keysNodes = ki;
057 setWhatToShow(org.apache.xml.dtm.DTMFilter.SHOW_ALL);
058 }
059
060 DTMIterator m_keysNodes;
061
062 /**
063 * Get the next node via getNextXXX. Bottlenecked for derived class override.
064 * @return The next node on the axis, or DTM.NULL.
065 */
066 protected int getNextNode()
067 {
068 int next;
069 while(DTM.NULL != (next = m_keysNodes.nextNode()))
070 {
071 if(DTMIterator.FILTER_ACCEPT == filterNode(next))
072 break;
073 }
074 m_lastFetched = next;
075
076 return next;
077 }
078
079
080 /**
081 * Test whether a specified node is visible in the logical view of a
082 * TreeWalker or NodeIterator. This function will be called by the
083 * implementation of TreeWalker and NodeIterator; it is not intended to
084 * be called directly from user code.
085 *
086 * @param testNode The node to check to see if it passes the filter or not.
087 *
088 * @return a constant to determine whether the node is accepted,
089 * rejected, or skipped, as defined above .
090 */
091 public short filterNode(int testNode)
092 {
093 boolean foundKey = false;
094 Vector keys = m_keyDeclarations;
095
096 QName name = m_name;
097 KeyIterator ki = (KeyIterator)(((XNodeSet)m_keysNodes).getContainedIter());
098 org.apache.xpath.XPathContext xctxt = ki.getXPathContext();
099
100 if(null == xctxt)
101 assertion(false, "xctxt can not be null here!");
102
103 try
104 {
105 XMLString lookupKey = m_ref;
106
107 // System.out.println("lookupKey: "+lookupKey);
108 int nDeclarations = keys.size();
109
110 // Walk through each of the declarations made with xsl:key
111 for (int i = 0; i < nDeclarations; i++)
112 {
113 KeyDeclaration kd = (KeyDeclaration) keys.elementAt(i);
114
115 // Only continue if the name on this key declaration
116 // matches the name on the iterator for this walker.
117 if (!kd.getName().equals(name))
118 continue;
119
120 foundKey = true;
121 // xctxt.setNamespaceContext(ki.getPrefixResolver());
122
123 // Query from the node, according the the select pattern in the
124 // use attribute in xsl:key.
125 XObject xuse = kd.getUse().execute(xctxt, testNode, ki.getPrefixResolver());
126
127 if (xuse.getType() != xuse.CLASS_NODESET)
128 {
129 XMLString exprResult = xuse.xstr();
130
131 if (lookupKey.equals(exprResult))
132 return DTMIterator.FILTER_ACCEPT;
133 }
134 else
135 {
136 DTMIterator nl = ((XNodeSet)xuse).iterRaw();
137 int useNode;
138
139 while (DTM.NULL != (useNode = nl.nextNode()))
140 {
141 DTM dtm = getDTM(useNode);
142 XMLString exprResult = dtm.getStringValue(useNode);
143 if ((null != exprResult) && lookupKey.equals(exprResult))
144 return DTMIterator.FILTER_ACCEPT;
145 }
146 }
147
148 } // end for(int i = 0; i < nDeclarations; i++)
149 }
150 catch (javax.xml.transform.TransformerException te)
151 {
152 throw new org.apache.xml.utils.WrappedRuntimeException(te);
153 }
154
155 if (!foundKey)
156 throw new RuntimeException(
157 XSLMessages.createMessage(
158 XSLTErrorResources.ER_NO_XSLKEY_DECLARATION,
159 new Object[] { name.getLocalName()}));
160 return DTMIterator.FILTER_REJECT;
161 }
162
163 protected XMLString m_ref;
164 protected QName m_name;
165
166 /** Vector of Key declarations in the stylesheet.
167 * @serial */
168 protected Vector m_keyDeclarations;
169
170 }