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: XRTreeFrag.java 469368 2006-10-31 04:41:36Z minchau $
020 */
021 package org.apache.xpath.objects;
022
023 import org.apache.xml.dtm.DTM;
024 import org.apache.xml.dtm.DTMIterator;
025 import org.apache.xml.utils.XMLString;
026 import org.apache.xpath.Expression;
027 import org.apache.xpath.ExpressionNode;
028 import org.apache.xpath.XPathContext;
029 import org.apache.xpath.axes.RTFIterator;
030
031 import org.w3c.dom.NodeList;
032
033 /**
034 * This class represents an XPath result tree fragment object, and is capable of
035 * converting the RTF to other types, such as a string.
036 * @xsl.usage general
037 */
038 public class XRTreeFrag extends XObject implements Cloneable
039 {
040 static final long serialVersionUID = -3201553822254911567L;
041 private DTMXRTreeFrag m_DTMXRTreeFrag;
042 private int m_dtmRoot = DTM.NULL;
043 protected boolean m_allowRelease = false;
044
045
046 /**
047 * Create an XRTreeFrag Object.
048 *
049 */
050 public XRTreeFrag(int root, XPathContext xctxt, ExpressionNode parent)
051 {
052 super(null);
053 exprSetParent(parent);
054 initDTM(root, xctxt);
055 }
056
057 /**
058 * Create an XRTreeFrag Object.
059 *
060 */
061 public XRTreeFrag(int root, XPathContext xctxt)
062 {
063 super(null);
064 initDTM(root, xctxt);
065 }
066
067 private final void initDTM(int root, XPathContext xctxt){
068 m_dtmRoot = root;
069 final DTM dtm = xctxt.getDTM(root);
070 if(dtm != null){
071 m_DTMXRTreeFrag = xctxt.getDTMXRTreeFrag(xctxt.getDTMIdentity(dtm));
072 }
073 }
074
075 /**
076 * Return a java object that's closest to the representation
077 * that should be handed to an extension.
078 *
079 * @return The object that this class wraps
080 */
081 public Object object()
082 {
083 if (m_DTMXRTreeFrag.getXPathContext() != null)
084 return new org.apache.xml.dtm.ref.DTMNodeIterator((DTMIterator)(new org.apache.xpath.NodeSetDTM(m_dtmRoot, m_DTMXRTreeFrag.getXPathContext().getDTMManager())));
085 else
086 return super.object();
087 }
088
089 /**
090 * Create an XRTreeFrag Object.
091 *
092 */
093 public XRTreeFrag(Expression expr)
094 {
095 super(expr);
096 }
097
098 /**
099 * Specify if it's OK for detach to release the iterator for reuse.
100 *
101 * @param allowRelease true if it is OK for detach to release this iterator
102 * for pooling.
103 */
104 public void allowDetachToRelease(boolean allowRelease)
105 {
106 m_allowRelease = allowRelease;
107 }
108
109 /**
110 * Detaches the <code>DTMIterator</code> from the set which it iterated
111 * over, releasing any computational resources and placing the iterator
112 * in the INVALID state. After <code>detach</code> has been invoked,
113 * calls to <code>nextNode</code> or <code>previousNode</code> will
114 * raise a runtime exception.
115 *
116 * In general, detach should only be called once on the object.
117 */
118 public void detach(){
119 if(m_allowRelease){
120 m_DTMXRTreeFrag.destruct();
121 setObject(null);
122 }
123 }
124
125 /**
126 * Tell what kind of class this is.
127 *
128 * @return type CLASS_RTREEFRAG
129 */
130 public int getType()
131 {
132 return CLASS_RTREEFRAG;
133 }
134
135 /**
136 * Given a request type, return the equivalent string.
137 * For diagnostic purposes.
138 *
139 * @return type string "#RTREEFRAG"
140 */
141 public String getTypeString()
142 {
143 return "#RTREEFRAG";
144 }
145
146 /**
147 * Cast result object to a number.
148 *
149 * @return The result tree fragment as a number or NaN
150 */
151 public double num()
152 throws javax.xml.transform.TransformerException
153 {
154
155 XMLString s = xstr();
156
157 return s.toDouble();
158 }
159
160 /**
161 * Cast result object to a boolean. This always returns true for a RTreeFrag
162 * because it is treated like a node-set with a single root node.
163 *
164 * @return true
165 */
166 public boolean bool()
167 {
168 return true;
169 }
170
171 private XMLString m_xmlStr = null;
172
173 /**
174 * Cast result object to an XMLString.
175 *
176 * @return The document fragment node data or the empty string.
177 */
178 public XMLString xstr()
179 {
180 if(null == m_xmlStr)
181 m_xmlStr = m_DTMXRTreeFrag.getDTM().getStringValue(m_dtmRoot);
182
183 return m_xmlStr;
184 }
185
186 /**
187 * Cast result object to a string.
188 *
189 * @return The string this wraps or the empty string if null
190 */
191 public void appendToFsb(org.apache.xml.utils.FastStringBuffer fsb)
192 {
193 XString xstring = (XString)xstr();
194 xstring.appendToFsb(fsb);
195 }
196
197
198 /**
199 * Cast result object to a string.
200 *
201 * @return The document fragment node data or the empty string.
202 */
203 public String str()
204 {
205 String str = m_DTMXRTreeFrag.getDTM().getStringValue(m_dtmRoot).toString();
206
207 return (null == str) ? "" : str;
208 }
209
210 /**
211 * Cast result object to a result tree fragment.
212 *
213 * @return The document fragment this wraps
214 */
215 public int rtf()
216 {
217 return m_dtmRoot;
218 }
219
220 /**
221 * Cast result object to a DTMIterator.
222 * dml - modified to return an RTFIterator for
223 * benefit of EXSLT object-type function in
224 * {@link org.apache.xalan.lib.ExsltCommon}.
225 * @return The document fragment as a DTMIterator
226 */
227 public DTMIterator asNodeIterator()
228 {
229 return new RTFIterator(m_dtmRoot, m_DTMXRTreeFrag.getXPathContext().getDTMManager());
230 }
231
232 /**
233 * Cast result object to a nodelist. (special function).
234 *
235 * @return The document fragment as a nodelist
236 */
237 public NodeList convertToNodeset()
238 {
239
240 if (m_obj instanceof NodeList)
241 return (NodeList) m_obj;
242 else
243 return new org.apache.xml.dtm.ref.DTMNodeList(asNodeIterator());
244 }
245
246 /**
247 * Tell if two objects are functionally equal.
248 *
249 * @param obj2 Object to compare this to
250 *
251 * @return True if the two objects are equal
252 *
253 * @throws javax.xml.transform.TransformerException
254 */
255 public boolean equals(XObject obj2)
256 {
257
258 try
259 {
260 if (XObject.CLASS_NODESET == obj2.getType())
261 {
262
263 // In order to handle the 'all' semantics of
264 // nodeset comparisons, we always call the
265 // nodeset function.
266 return obj2.equals(this);
267 }
268 else if (XObject.CLASS_BOOLEAN == obj2.getType())
269 {
270 return bool() == obj2.bool();
271 }
272 else if (XObject.CLASS_NUMBER == obj2.getType())
273 {
274 return num() == obj2.num();
275 }
276 else if (XObject.CLASS_NODESET == obj2.getType())
277 {
278 return xstr().equals(obj2.xstr());
279 }
280 else if (XObject.CLASS_STRING == obj2.getType())
281 {
282 return xstr().equals(obj2.xstr());
283 }
284 else if (XObject.CLASS_RTREEFRAG == obj2.getType())
285 {
286
287 // Probably not so good. Think about this.
288 return xstr().equals(obj2.xstr());
289 }
290 else
291 {
292 return super.equals(obj2);
293 }
294 }
295 catch(javax.xml.transform.TransformerException te)
296 {
297 throw new org.apache.xml.utils.WrappedRuntimeException(te);
298 }
299 }
300
301 }