1 /* 2 * $Header$ 3 * $Revision$ 4 * $Date$ 5 * 6 * ==================================================================== 7 * 8 * Copyright 2000-2002 bob mcwhirter & James Strachan. 9 * All rights reserved. 10 * 11 * Redistribution and use in source and binary forms, with or without 12 * modification, are permitted provided that the following conditions are 13 * met: 14 * 15 * * Redistributions of source code must retain the above copyright 16 * notice, this list of conditions and the following disclaimer. 17 * 18 * * Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 22 * * Neither the name of the Jaxen Project nor the names of its 23 * contributors may be used to endorse or promote products derived 24 * from this software without specific prior written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS 27 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A 29 * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER 30 * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 31 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 32 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 33 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF 34 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 35 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 36 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37 * 38 * ==================================================================== 39 * This software consists of voluntary contributions made by many 40 * individuals on behalf of the Jaxen Project and was originally 41 * created by bob mcwhirter <bob@werken.com> and 42 * James Strachan <jstrachan@apache.org>. For more information on the 43 * Jaxen Project, please see <http://www.jaxen.org/>. 44 * 45 * $Id$ 46 */ 47 48 package org.jaxen.function; 49 50 import java.util.ArrayList; 51 import java.util.Collections; 52 import java.util.Iterator; 53 import java.util.List; 54 import java.util.StringTokenizer; 55 56 import org.jaxen.Context; 57 import org.jaxen.Function; 58 import org.jaxen.FunctionCallException; 59 import org.jaxen.Navigator; 60 61 /** 62 * <p><b>4.1</b> <code><i>node-set</i> id(<i>object</i>)</code> </p> 63 * 64 * <p>The <b>id</b> function returns a <code>List</code> 65 * of all the elements in the context document that have an ID 66 * matching one of a specified list of IDs. How an attribute is determined 67 * to be of type ID depends on the navigator, but it normally requires that 68 * the attribute be declared to have type ID in the DTD. 69 * </p> 70 * 71 * <p> 72 * There should be no more than one element in any document with a 73 * certain ID. However, if there are multiple such elements--i.e. if 74 * there are duplicate IDs--then this function selects only the first element 75 * in document order with the specified ID. 76 * </p> 77 * 78 * @author Erwin Bolwidt (ejb @ klomp.org) 79 * @author J\u00e9r\u00f4me N\u00e8gre (jerome.negre @ e-xmlmedia.fr) 80 * 81 * @see <a href="https://www.w3.org/TR/xpath#function-id" target="_top">Section 4.1 of the XPath Specification</a> 82 */ 83 public class IdFunction implements Function 84 { 85 86 /** 87 * Create a new <code>IdFunction</code> object. 88 */ 89 public IdFunction() {} 90 91 /** 92 * Returns a list of the nodes with the specified IDs. 93 * 94 * @param context the context at the point in the 95 * expression when the function is called 96 * @param args a list with exactly one item which is either a string 97 * a node-set 98 * 99 * @return a <code>List</code> containing the first node in document 100 * with each of the specified IDs; or 101 * an empty list if there are no such nodes 102 * 103 * @throws FunctionCallException if <code>args</code> has more or less than one item 104 */ 105 public Object call(Context context, List args) throws FunctionCallException 106 { 107 if ( args.size() == 1 ) { 108 return evaluate( context.getNodeSet(), 109 args.get(0), context.getNavigator() ); 110 } 111 112 throw new FunctionCallException( "id() requires one argument" ); 113 } 114 115 /** 116 * Returns a list of the nodes with the specified IDs. 117 * 118 * @param contextNodes the context node-set. The first item in this list 119 * determines the document in which the search is performed. 120 * @param arg the ID or IDs to search for 121 * @param nav the navigator used to calculate string-values and search 122 * by ID 123 * 124 * @return a <code>List</code> containing the first node in document 125 * with each of the specified IDs; or 126 * an empty list if there are no such nodes 127 * 128 */ 129 public static List evaluate(List contextNodes, Object arg, Navigator nav) 130 { 131 if (contextNodes.size() == 0) return Collections.EMPTY_LIST; 132 133 List nodes = new ArrayList(); 134 135 Object contextNode = contextNodes.get(0); 136 137 if (arg instanceof List) { 138 Iterator iter = ((List)arg).iterator(); 139 while (iter.hasNext()) { 140 String id = StringFunction.evaluate(iter.next(), nav); 141 nodes.addAll( evaluate( contextNodes, id, nav ) ); 142 } 143 } 144 else { 145 String ids = StringFunction.evaluate(arg, nav); 146 StringTokenizer tok = new StringTokenizer(ids, " \t\n\r"); 147 while (tok.hasMoreTokens()) { 148 String id = tok.nextToken(); 149 Object node = nav.getElementById(contextNode, id); 150 if (node != null) { 151 nodes.add(node); 152 } 153 } 154 } 155 return nodes; 156 } 157 158 } 159