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: FuncKey.java 468643 2006-10-28 06:56:03Z minchau $
020     */
021    package org.apache.xalan.templates;
022    
023    import java.util.Hashtable;
024    
025    import org.apache.xalan.transformer.KeyManager;
026    import org.apache.xalan.transformer.TransformerImpl;
027    import org.apache.xml.dtm.DTM;
028    import org.apache.xml.dtm.DTMIterator;
029    import org.apache.xml.utils.QName;
030    import org.apache.xml.utils.XMLString;
031    import org.apache.xpath.XPathContext;
032    import org.apache.xpath.axes.UnionPathIterator;
033    import org.apache.xpath.functions.Function2Args;
034    import org.apache.xpath.objects.XNodeSet;
035    import org.apache.xpath.objects.XObject;
036    
037    /**
038     * Execute the Key() function.
039     * @xsl.usage advanced
040     */
041    public class FuncKey extends Function2Args
042    {
043        static final long serialVersionUID = 9089293100115347340L;
044    
045      /** Dummy value to be used in usedrefs hashtable           */
046      static private Boolean ISTRUE = new Boolean(true);
047    
048      /**
049       * Execute the function.  The function must return
050       * a valid object.
051       * @param xctxt The current execution context.
052       * @return A valid XObject.
053       *
054       * @throws javax.xml.transform.TransformerException
055       */
056      public XObject execute(XPathContext xctxt) throws javax.xml.transform.TransformerException
057      {
058    
059        // TransformerImpl transformer = (TransformerImpl)xctxt;
060        TransformerImpl transformer = (TransformerImpl) xctxt.getOwnerObject();
061        XNodeSet nodes = null;
062        int context = xctxt.getCurrentNode();
063        DTM dtm = xctxt.getDTM(context);
064        int docContext = dtm.getDocumentRoot(context);
065    
066        if (DTM.NULL == docContext)
067        {
068    
069          // path.error(context, XPATHErrorResources.ER_CONTEXT_HAS_NO_OWNERDOC); //"context does not have an owner document!");
070        }
071    
072        String xkeyname = getArg0().execute(xctxt).str();
073        QName keyname = new QName(xkeyname, xctxt.getNamespaceContext());
074        XObject arg = getArg1().execute(xctxt);
075        boolean argIsNodeSetDTM = (XObject.CLASS_NODESET == arg.getType());
076        KeyManager kmgr = transformer.getKeyManager();
077        
078        // Don't bother with nodeset logic if the thing is only one node.
079        if(argIsNodeSetDTM)
080        {
081            XNodeSet ns = (XNodeSet)arg;
082            ns.setShouldCacheNodes(true);
083            int len = ns.getLength();
084            if(len <= 1)
085                    argIsNodeSetDTM = false;
086        }
087    
088        if (argIsNodeSetDTM)
089        {
090          Hashtable usedrefs = null;
091          DTMIterator ni = arg.iter();
092          int pos;
093          UnionPathIterator upi = new UnionPathIterator();
094          upi.exprSetParent(this);
095    
096          while (DTM.NULL != (pos = ni.nextNode()))
097          {
098            dtm = xctxt.getDTM(pos);
099            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    }