1 /* KeyFunction.java -- 2 Copyright (C) 2004 Free Software Foundation, Inc. 3 4 This file is part of GNU Classpath. 5 6 GNU Classpath is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by 8 the Free Software Foundation; either version 2, or (at your option) 9 any later version. 10 11 GNU Classpath is distributed in the hope that it will be useful, but 12 WITHOUT ANY WARRANTY; without even the implied warranty of 13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 General Public License for more details. 15 16 You should have received a copy of the GNU General Public License 17 along with GNU Classpath; see the file COPYING. If not, write to the 18 Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 19 02110-1301 USA. 20 21 Linking this library statically or dynamically with other modules is 22 making a combined work based on this library. Thus, the terms and 23 conditions of the GNU General Public License cover the whole 24 combination. 25 26 As a special exception, the copyright holders of this library give you 27 permission to link this library with independent modules to produce an 28 executable, regardless of the license terms of these independent 29 modules, and to copy and distribute the resulting executable under 30 terms of your choice, provided that you also meet, for each linked 31 independent module, the terms and conditions of the license of that 32 module. An independent module is a module which is not derived from 33 or based on this library. If you modify this library, you may extend 34 this exception to your version of the library, but you are not 35 obligated to do so. If you do not wish to do so, delete this 36 exception statement from your version. */ 37 38 package gnu.xml.transform; 39 40 import java.util.ArrayList; 41 import java.util.Collection; 42 import java.util.Collections; 43 import java.util.Iterator; 44 import java.util.LinkedHashSet; 45 import java.util.LinkedList; 46 import java.util.List; 47 import javax.xml.namespace.QName; 48 import javax.xml.xpath.XPathFunction; 49 import javax.xml.xpath.XPathFunctionException; 50 import org.w3c.dom.Document; 51 import org.w3c.dom.Node; 52 import gnu.xml.xpath.Expr; 53 import gnu.xml.xpath.Function; 54 import gnu.xml.xpath.Pattern; 55 56 /** 57 * The XSLT <code>key()</code>function. 58 * 59 * @author <a href='mailto:dog@gnu.org'>Chris Burdess</a> 60 */ 61 final class KeyFunction 62 extends Pattern 63 implements XPathFunction, Function 64 { 65 66 final Stylesheet stylesheet; 67 List args; 68 KeyFunction(Stylesheet stylesheet)69 KeyFunction(Stylesheet stylesheet) 70 { 71 this.stylesheet = stylesheet; 72 } 73 evaluate(List args)74 public Object evaluate(List args) 75 throws XPathFunctionException 76 { 77 // Useless... 78 return Collections.EMPTY_SET; 79 } 80 setArguments(List args)81 public void setArguments(List args) 82 { 83 this.args = args; 84 } 85 matches(Node context)86 public boolean matches(Node context) 87 { 88 Object ret = evaluate(context, 1, 1); 89 return !((Collection) ret).isEmpty(); 90 } 91 evaluate(Node context, int pos, int len)92 public Object evaluate(Node context, int pos, int len) 93 { 94 // Evaluate arguments 95 int arity = args.size(); 96 List values = new ArrayList(arity); 97 for (int i = 0; i < arity; i++) 98 { 99 Expr arg = (Expr) args.get(i); 100 values.add(arg.evaluate(context, pos, len)); 101 } 102 // Get key name 103 QName keyName = QName.valueOf(_string(context, values.get(0))); 104 // Expand qualified name 105 String uri = keyName.getNamespaceURI(); 106 String prefix = keyName.getPrefix(); 107 if ((uri == null || uri.length() == 0) && 108 (prefix != null && prefix.length() > 0)) 109 { 110 uri = stylesheet.getNamespaceURI(prefix); 111 if (uri != null && uri.length() > 0) 112 { 113 String localName = keyName.getLocalPart(); 114 keyName = new QName(uri, localName, prefix); 115 } 116 } 117 // Compute matching key set 118 Collection keySet = new LinkedList(); 119 for (Iterator i = stylesheet.keys.iterator(); i.hasNext(); ) 120 { 121 Key key = (Key) i.next(); 122 if (key.name.equals(keyName)) 123 { 124 keySet.add(key); 125 } 126 } 127 // Get target 128 Object target = values.get(1); 129 Collection acc = new LinkedHashSet(); 130 Document doc = (context instanceof Document) ? (Document) context : 131 context.getOwnerDocument(); 132 if (target instanceof Collection) 133 { 134 for (Iterator i = ((Collection) target).iterator(); i.hasNext(); ) 135 { 136 String val = Expr.stringValue((Node) i.next()); 137 addKeyNodes(doc, keySet, val, acc); 138 } 139 } 140 else 141 { 142 String val = Expr._string(context, target); 143 addKeyNodes(doc, keySet, val, acc); 144 } 145 List ret = new ArrayList(acc); 146 Collections.sort(ret, documentOrderComparator); 147 return ret; 148 } 149 addKeyNodes(Node node, Collection keySet, String value, Collection acc)150 final void addKeyNodes(Node node, Collection keySet, 151 String value, Collection acc) 152 { 153 addKeyNodeIfMatch(node, keySet, value, acc); 154 // Apply children 155 for (Node ctx = node.getFirstChild(); ctx != null; 156 ctx = ctx.getNextSibling()) 157 { 158 addKeyNodes(ctx, keySet, value, acc); 159 } 160 } 161 addKeyNodeIfMatch(Node node, Collection keySet, String value, Collection acc)162 final void addKeyNodeIfMatch(Node node, Collection keySet, 163 String value, Collection acc) 164 { 165 for (Iterator i = keySet.iterator(); i.hasNext(); ) 166 { 167 Key key = (Key) i.next(); 168 if (key.match.matches(node)) 169 { 170 Object eval = key.use.evaluate(node, 1, 1); 171 if (eval instanceof Collection) 172 { 173 for (Iterator j = ((Collection) eval).iterator(); 174 j.hasNext(); ) 175 { 176 String keyValue = Expr.stringValue((Node) j.next()); 177 if (value.equals(keyValue)) 178 { 179 acc.add(node); 180 return; 181 } 182 } 183 } 184 else 185 { 186 String keyValue = Expr._string(node, eval); 187 if (value.equals(keyValue)) 188 { 189 acc.add(node); 190 return; 191 } 192 } 193 } 194 } 195 } 196 clone(Object context)197 public Expr clone(Object context) 198 { 199 Stylesheet s = stylesheet; 200 if (context instanceof Stylesheet) 201 { 202 s = (Stylesheet) context; 203 } 204 KeyFunction f = new KeyFunction(s); 205 int len = args.size(); 206 List args2 = new ArrayList(len); 207 for (int i = 0; i < len; i++) 208 { 209 args2.add(((Expr) args.get(i)).clone(context)); 210 } 211 f.setArguments(args2); 212 return f; 213 } 214 references(QName var)215 public boolean references(QName var) 216 { 217 for (Iterator i = args.iterator(); i.hasNext(); ) 218 { 219 if (((Expr) i.next()).references(var)) 220 { 221 return true; 222 } 223 } 224 return false; 225 } 226 227 } 228 229