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 }