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: FuncId.java 468655 2006-10-28 07:12:06Z minchau $ 20 */ 21 package org.apache.xpath.functions; 22 23 import java.util.StringTokenizer; 24 25 import org.apache.xml.dtm.DTM; 26 import org.apache.xml.dtm.DTMIterator; 27 import org.apache.xml.utils.StringVector; 28 import org.apache.xpath.NodeSetDTM; 29 import org.apache.xpath.XPathContext; 30 import org.apache.xpath.objects.XNodeSet; 31 import org.apache.xpath.objects.XObject; 32 import org.apache.xpath.res.XPATHErrorResources; 33 34 /** 35 * Execute the Id() function. 36 * @xsl.usage advanced 37 */ 38 public class FuncId extends FunctionOneArg 39 { 40 static final long serialVersionUID = 8930573966143567310L; 41 42 /** 43 * Fill in a list with nodes that match a space delimited list if ID 44 * ID references. 45 * 46 * @param xctxt The runtime XPath context. 47 * @param docContext The document where the nodes are being looked for. 48 * @param refval A space delimited list of ID references. 49 * @param usedrefs List of references for which nodes were found. 50 * @param nodeSet Node set where the nodes will be added to. 51 * @param mayBeMore true if there is another set of nodes to be looked for. 52 * 53 * @return The usedrefs value. 54 */ getNodesByID(XPathContext xctxt, int docContext, String refval, StringVector usedrefs, NodeSetDTM nodeSet, boolean mayBeMore)55 private StringVector getNodesByID(XPathContext xctxt, int docContext, 56 String refval, StringVector usedrefs, 57 NodeSetDTM nodeSet, boolean mayBeMore) 58 { 59 60 if (null != refval) 61 { 62 String ref = null; 63 // DOMHelper dh = xctxt.getDOMHelper(); 64 StringTokenizer tokenizer = new StringTokenizer(refval); 65 boolean hasMore = tokenizer.hasMoreTokens(); 66 DTM dtm = xctxt.getDTM(docContext); 67 68 while (hasMore) 69 { 70 ref = tokenizer.nextToken(); 71 hasMore = tokenizer.hasMoreTokens(); 72 73 if ((null != usedrefs) && usedrefs.contains(ref)) 74 { 75 ref = null; 76 77 continue; 78 } 79 80 int node = dtm.getElementById(ref); 81 82 if (DTM.NULL != node) 83 nodeSet.addNodeInDocOrder(node, xctxt); 84 85 if ((null != ref) && (hasMore || mayBeMore)) 86 { 87 if (null == usedrefs) 88 usedrefs = new StringVector(); 89 90 usedrefs.addElement(ref); 91 } 92 } 93 } 94 95 return usedrefs; 96 } 97 98 /** 99 * Execute the function. The function must return 100 * a valid object. 101 * @param xctxt The current execution context. 102 * @return A valid XObject. 103 * 104 * @throws javax.xml.transform.TransformerException 105 */ execute(XPathContext xctxt)106 public XObject execute(XPathContext xctxt) throws javax.xml.transform.TransformerException 107 { 108 109 int context = xctxt.getCurrentNode(); 110 DTM dtm = xctxt.getDTM(context); 111 int docContext = dtm.getDocument(); 112 113 if (DTM.NULL == docContext) 114 error(xctxt, XPATHErrorResources.ER_CONTEXT_HAS_NO_OWNERDOC, null); 115 116 XObject arg = m_arg0.execute(xctxt); 117 int argType = arg.getType(); 118 XNodeSet nodes = new XNodeSet(xctxt.getDTMManager()); 119 NodeSetDTM nodeSet = nodes.mutableNodeset(); 120 121 if (XObject.CLASS_NODESET == argType) 122 { 123 DTMIterator ni = arg.iter(); 124 StringVector usedrefs = null; 125 int pos = ni.nextNode(); 126 127 while (DTM.NULL != pos) 128 { 129 DTM ndtm = ni.getDTM(pos); 130 String refval = ndtm.getStringValue(pos).toString(); 131 132 pos = ni.nextNode(); 133 usedrefs = getNodesByID(xctxt, docContext, refval, usedrefs, nodeSet, 134 DTM.NULL != pos); 135 } 136 // ni.detach(); 137 } 138 else if (XObject.CLASS_NULL == argType) 139 { 140 return nodes; 141 } 142 else 143 { 144 String refval = arg.str(); 145 146 getNodesByID(xctxt, docContext, refval, null, nodeSet, false); 147 } 148 149 return nodes; 150 } 151 } 152