001 /*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements. See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership. The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the "License");
007 * you may not use this file except in compliance with the License.
008 * You may obtain a copy of the License at
009 *
010 * http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018 /*
019 * $Id: FuncId.java 468655 2006-10-28 07:12:06Z minchau $
020 */
021 package org.apache.xpath.functions;
022
023 import java.util.StringTokenizer;
024
025 import org.apache.xml.dtm.DTM;
026 import org.apache.xml.dtm.DTMIterator;
027 import org.apache.xml.utils.StringVector;
028 import org.apache.xpath.NodeSetDTM;
029 import org.apache.xpath.XPathContext;
030 import org.apache.xpath.objects.XNodeSet;
031 import org.apache.xpath.objects.XObject;
032 import org.apache.xpath.res.XPATHErrorResources;
033
034 /**
035 * Execute the Id() function.
036 * @xsl.usage advanced
037 */
038 public class FuncId extends FunctionOneArg
039 {
040 static final long serialVersionUID = 8930573966143567310L;
041
042 /**
043 * Fill in a list with nodes that match a space delimited list if ID
044 * ID references.
045 *
046 * @param xctxt The runtime XPath context.
047 * @param docContext The document where the nodes are being looked for.
048 * @param refval A space delimited list of ID references.
049 * @param usedrefs List of references for which nodes were found.
050 * @param nodeSet Node set where the nodes will be added to.
051 * @param mayBeMore true if there is another set of nodes to be looked for.
052 *
053 * @return The usedrefs value.
054 */
055 private StringVector getNodesByID(XPathContext xctxt, int docContext,
056 String refval, StringVector usedrefs,
057 NodeSetDTM nodeSet, boolean mayBeMore)
058 {
059
060 if (null != refval)
061 {
062 String ref = null;
063 // DOMHelper dh = xctxt.getDOMHelper();
064 StringTokenizer tokenizer = new StringTokenizer(refval);
065 boolean hasMore = tokenizer.hasMoreTokens();
066 DTM dtm = xctxt.getDTM(docContext);
067
068 while (hasMore)
069 {
070 ref = tokenizer.nextToken();
071 hasMore = tokenizer.hasMoreTokens();
072
073 if ((null != usedrefs) && usedrefs.contains(ref))
074 {
075 ref = null;
076
077 continue;
078 }
079
080 int node = dtm.getElementById(ref);
081
082 if (DTM.NULL != node)
083 nodeSet.addNodeInDocOrder(node, xctxt);
084
085 if ((null != ref) && (hasMore || mayBeMore))
086 {
087 if (null == usedrefs)
088 usedrefs = new StringVector();
089
090 usedrefs.addElement(ref);
091 }
092 }
093 }
094
095 return usedrefs;
096 }
097
098 /**
099 * 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 }