Home | History | Annotate | Download | only in objects
      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