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 }