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 */
21package org.apache.xalan.templates;
22
23import java.util.Hashtable;
24
25import org.apache.xalan.transformer.KeyManager;
26import org.apache.xalan.transformer.TransformerImpl;
27import org.apache.xml.dtm.DTM;
28import org.apache.xml.dtm.DTMIterator;
29import org.apache.xml.utils.QName;
30import org.apache.xml.utils.XMLString;
31import org.apache.xpath.XPathContext;
32import org.apache.xpath.axes.UnionPathIterator;
33import org.apache.xpath.functions.Function2Args;
34import org.apache.xpath.objects.XNodeSet;
35import org.apache.xpath.objects.XObject;
36
37/**
38 * Execute the Key() function.
39 * @xsl.usage advanced
40 */
41public 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