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 */ 21 package org.apache.xpath.objects; 22 23 import org.apache.xml.dtm.DTM; 24 import org.apache.xml.dtm.DTMIterator; 25 import org.apache.xml.utils.XMLString; 26 import org.apache.xpath.Expression; 27 import org.apache.xpath.ExpressionNode; 28 import org.apache.xpath.XPathContext; 29 import org.apache.xpath.axes.RTFIterator; 30 31 import 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 */ 38 public 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