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