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: XRTreeFrag.java 469368 2006-10-31 04:41:36Z minchau $
20 */
21package org.apache.xpath.objects;
22
23import org.apache.xml.dtm.DTM;
24import org.apache.xml.dtm.DTMIterator;
25import org.apache.xml.utils.XMLString;
26import org.apache.xpath.Expression;
27import org.apache.xpath.ExpressionNode;
28import org.apache.xpath.XPathContext;
29import org.apache.xpath.axes.RTFIterator;
30
31import org.w3c.dom.NodeList;
32
33/**
34 * This class represents an XPath result tree fragment object, and is capable of
35 * converting the RTF to other types, such as a string.
36 * @xsl.usage general
37 */
38public class XRTreeFrag extends XObject implements Cloneable
39{
40    static final long serialVersionUID = -3201553822254911567L;
41  private DTMXRTreeFrag m_DTMXRTreeFrag;
42  private int m_dtmRoot = DTM.NULL;
43  protected boolean m_allowRelease = false;
44
45
46  /**
47   * Create an XRTreeFrag Object.
48   *
49   */
50  public XRTreeFrag(int root, XPathContext xctxt, ExpressionNode parent)
51  {
52    super(null);
53    exprSetParent(parent);
54    initDTM(root, xctxt);
55  }
56
57  /**
58   * Create an XRTreeFrag Object.
59   *
60   */
61  public XRTreeFrag(int root, XPathContext xctxt)
62  {
63    super(null);
64   initDTM(root, xctxt);
65  }
66
67  private final void initDTM(int root, XPathContext xctxt){
68    m_dtmRoot = root;
69    final DTM dtm = xctxt.getDTM(root);
70    if(dtm != null){
71      m_DTMXRTreeFrag = xctxt.getDTMXRTreeFrag(xctxt.getDTMIdentity(dtm));
72    }
73  }
74
75  /**
76   * Return a java object that's closest to the representation
77   * that should be handed to an extension.
78   *
79   * @return The object that this class wraps
80   */
81  public Object object()
82  {
83    if (m_DTMXRTreeFrag.getXPathContext() != null)
84      return new org.apache.xml.dtm.ref.DTMNodeIterator((DTMIterator)(new org.apache.xpath.NodeSetDTM(m_dtmRoot, m_DTMXRTreeFrag.getXPathContext().getDTMManager())));
85    else
86      return super.object();
87  }
88
89  /**
90   * Create an XRTreeFrag Object.
91   *
92   */
93  public XRTreeFrag(Expression expr)
94  {
95    super(expr);
96  }
97
98  /**
99   * 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   * {@code 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}
302