Home | History | Annotate | Download | only in templates
      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: FuncKey.java 468643 2006-10-28 06:56:03Z minchau $
     20  */
     21 package org.apache.xalan.templates;
     22 
     23 import java.util.Hashtable;
     24 
     25 import org.apache.xalan.transformer.KeyManager;
     26 import org.apache.xalan.transformer.TransformerImpl;
     27 import org.apache.xml.dtm.DTM;
     28 import org.apache.xml.dtm.DTMIterator;
     29 import org.apache.xml.utils.QName;
     30 import org.apache.xml.utils.XMLString;
     31 import org.apache.xpath.XPathContext;
     32 import org.apache.xpath.axes.UnionPathIterator;
     33 import org.apache.xpath.functions.Function2Args;
     34 import org.apache.xpath.objects.XNodeSet;
     35 import org.apache.xpath.objects.XObject;
     36 
     37 /**
     38  * Execute the Key() function.
     39  * @xsl.usage advanced
     40  */
     41 public class FuncKey extends Function2Args
     42 {
     43     static final long serialVersionUID = 9089293100115347340L;
     44 
     45   /** Dummy value to be used in usedrefs hashtable           */
     46   static private Boolean ISTRUE = new Boolean(true);
     47 
     48   /**
     49    * Execute the function.  The function must return
     50    * a valid object.
     51    * @param xctxt The current execution context.
     52    * @return A valid XObject.
     53    *
     54    * @throws javax.xml.transform.TransformerException
     55    */
     56   public XObject execute(XPathContext xctxt) throws javax.xml.transform.TransformerException
     57   {
     58 
     59     // TransformerImpl transformer = (TransformerImpl)xctxt;
     60     TransformerImpl transformer = (TransformerImpl) xctxt.getOwnerObject();
     61     XNodeSet nodes = null;
     62     int context = xctxt.getCurrentNode();
     63     DTM dtm = xctxt.getDTM(context);
     64     int docContext = dtm.getDocumentRoot(context);
     65 
     66     if (DTM.NULL == docContext)
     67     {
     68 
     69       // path.error(context, XPATHErrorResources.ER_CONTEXT_HAS_NO_OWNERDOC); //"context does not have an owner document!");
     70     }
     71 
     72     String xkeyname = getArg0().execute(xctxt).str();
     73     QName keyname = new QName(xkeyname, xctxt.getNamespaceContext());
     74     XObject arg = getArg1().execute(xctxt);
     75     boolean argIsNodeSetDTM = (XObject.CLASS_NODESET == arg.getType());
     76     KeyManager kmgr = transformer.getKeyManager();
     77 
     78     // Don't bother with nodeset logic if the thing is only one node.
     79     if(argIsNodeSetDTM)
     80     {
     81     	XNodeSet ns = (XNodeSet)arg;
     82     	ns.setShouldCacheNodes(true);
     83     	int len = ns.getLength();
     84     	if(len <= 1)
     85     		argIsNodeSetDTM = false;
     86     }
     87 
     88     if (argIsNodeSetDTM)
     89     {
     90       Hashtable usedrefs = null;
     91       DTMIterator ni = arg.iter();
     92       int pos;
     93       UnionPathIterator upi = new UnionPathIterator();
     94       upi.exprSetParent(this);
     95 
     96       while (DTM.NULL != (pos = ni.nextNode()))
     97       {
     98         dtm = xctxt.getDTM(pos);
     99         XMLString ref = dtm.getStringValue(pos);
    100 
    101         if (null == ref)
    102           continue;
    103 
    104         if (null == usedrefs)
    105           usedrefs = new Hashtable();
    106 
    107         if (usedrefs.get(ref) != null)
    108         {
    109           continue;  // We already have 'em.
    110         }
    111         else
    112         {
    113 
    114           // ISTRUE being used as a dummy value.
    115           usedrefs.put(ref, ISTRUE);
    116         }
    117 
    118         XNodeSet nl =
    119           kmgr.getNodeSetDTMByKey(xctxt, docContext, keyname, ref,
    120                                xctxt.getNamespaceContext());
    121 
    122         nl.setRoot(xctxt.getCurrentNode(), xctxt);
    123 
    124 //        try
    125 //        {
    126           upi.addIterator(nl);
    127 //        }
    128 //        catch(CloneNotSupportedException cnse)
    129 //        {
    130 //          // will never happen.
    131 //        }
    132         //mnodeset.addNodesInDocOrder(nl, xctxt); needed??
    133       }
    134 
    135       int current = xctxt.getCurrentNode();
    136       upi.setRoot(current, xctxt);
    137 
    138       nodes = new XNodeSet(upi);
    139     }
    140     else
    141     {
    142       XMLString ref = arg.xstr();
    143       nodes = kmgr.getNodeSetDTMByKey(xctxt, docContext, keyname,
    144                                                 ref,
    145                                                 xctxt.getNamespaceContext());
    146       nodes.setRoot(xctxt.getCurrentNode(), xctxt);
    147     }
    148 
    149     return nodes;
    150   }
    151 }
    152