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    */
execute(XPathContext xctxt)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