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 */
21package org.apache.xpath.functions;
22
23import java.util.StringTokenizer;
24
25import org.apache.xml.dtm.DTM;
26import org.apache.xml.dtm.DTMIterator;
27import org.apache.xml.utils.StringVector;
28import org.apache.xpath.NodeSetDTM;
29import org.apache.xpath.XPathContext;
30import org.apache.xpath.objects.XNodeSet;
31import org.apache.xpath.objects.XObject;
32import org.apache.xpath.res.XPATHErrorResources;
33
34/**
35 * Execute the Id() function.
36 * @xsl.usage advanced
37 */
38public 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   */
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   */
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