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