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 }