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 }