1/*
2 * reserved comment block
3 * DO NOT REMOVE OR ALTER!
4 */
5/*
6 * Licensed to the Apache Software Foundation (ASF) under one or more
7 * contributor license agreements.  See the NOTICE file distributed with
8 * this work for additional information regarding copyright ownership.
9 * The ASF licenses this file to You under the Apache License, Version 2.0
10 * (the "License"); you may not use this file except in compliance with
11 * the License.  You may obtain a copy of the License at
12 *
13 *      http://www.apache.org/licenses/LICENSE-2.0
14 *
15 * Unless required by applicable law or agreed to in writing, software
16 * distributed under the License is distributed on an "AS IS" BASIS,
17 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 * See the License for the specific language governing permissions and
19 * limitations under the License.
20 */
21
22package com.sun.org.apache.xpath.internal.functions;
23
24import java.util.StringTokenizer;
25
26import com.sun.org.apache.xml.internal.dtm.DTM;
27import com.sun.org.apache.xml.internal.dtm.DTMIterator;
28import com.sun.org.apache.xml.internal.utils.StringVector;
29import com.sun.org.apache.xpath.internal.NodeSetDTM;
30import com.sun.org.apache.xpath.internal.XPathContext;
31import com.sun.org.apache.xpath.internal.objects.XNodeSet;
32import com.sun.org.apache.xpath.internal.objects.XObject;
33import com.sun.org.apache.xpath.internal.res.XPATHErrorResources;
34
35/**
36 * Execute the Id() function.
37 * @xsl.usage advanced
38 */
39public class FuncId extends FunctionOneArg
40{
41    static final long serialVersionUID = 8930573966143567310L;
42
43  /**
44   * Fill in a list with nodes that match a space delimited list if ID
45   * ID references.
46   *
47   * @param xctxt The runtime XPath context.
48   * @param docContext The document where the nodes are being looked for.
49   * @param refval A space delimited list of ID references.
50   * @param usedrefs List of references for which nodes were found.
51   * @param nodeSet Node set where the nodes will be added to.
52   * @param mayBeMore true if there is another set of nodes to be looked for.
53   *
54   * @return The usedrefs value.
55   */
56  private StringVector getNodesByID(XPathContext xctxt, int docContext,
57                                    String refval, StringVector usedrefs,
58                                    NodeSetDTM nodeSet, boolean mayBeMore)
59  {
60
61    if (null != refval)
62    {
63      String ref = null;
64//      DOMHelper dh = xctxt.getDOMHelper();
65      StringTokenizer tokenizer = new StringTokenizer(refval);
66      boolean hasMore = tokenizer.hasMoreTokens();
67      DTM dtm = xctxt.getDTM(docContext);
68
69      while (hasMore)
70      {
71        ref = tokenizer.nextToken();
72        hasMore = tokenizer.hasMoreTokens();
73
74        if ((null != usedrefs) && usedrefs.contains(ref))
75        {
76          ref = null;
77
78          continue;
79        }
80
81        int node = dtm.getElementById(ref);
82
83        if (DTM.NULL != node)
84          nodeSet.addNodeInDocOrder(node, xctxt);
85
86        if ((null != ref) && (hasMore || mayBeMore))
87        {
88          if (null == usedrefs)
89            usedrefs = new StringVector();
90
91          usedrefs.addElement(ref);
92        }
93      }
94    }
95
96    return usedrefs;
97  }
98
99  /**
100   * Execute the function.  The function must return
101   * a valid object.
102   * @param xctxt The current execution context.
103   * @return A valid XObject.
104   *
105   * @throws javax.xml.transform.TransformerException
106   */
107  public XObject execute(XPathContext xctxt) throws javax.xml.transform.TransformerException
108  {
109
110    int context = xctxt.getCurrentNode();
111    DTM dtm = xctxt.getDTM(context);
112    int docContext = dtm.getDocument();
113
114    if (DTM.NULL == docContext)
115      error(xctxt, XPATHErrorResources.ER_CONTEXT_HAS_NO_OWNERDOC, null);
116
117    XObject arg = m_arg0.execute(xctxt);
118    int argType = arg.getType();
119    XNodeSet nodes = new XNodeSet(xctxt.getDTMManager());
120    NodeSetDTM nodeSet = nodes.mutableNodeset();
121
122    if (XObject.CLASS_NODESET == argType)
123    {
124      DTMIterator ni = arg.iter();
125      StringVector usedrefs = null;
126      int pos = ni.nextNode();
127
128      while (DTM.NULL != pos)
129      {
130        DTM ndtm = ni.getDTM(pos);
131        String refval = ndtm.getStringValue(pos).toString();
132
133        pos = ni.nextNode();
134        usedrefs = getNodesByID(xctxt, docContext, refval, usedrefs, nodeSet,
135                                DTM.NULL != pos);
136      }
137      // ni.detach();
138    }
139    else if (XObject.CLASS_NULL == argType)
140    {
141      return nodes;
142    }
143    else
144    {
145      String refval = arg.str();
146
147      getNodesByID(xctxt, docContext, refval, null, nodeSet, false);
148    }
149
150    return nodes;
151  }
152}
153