001: /*
002: * Copyright 1999-2004 The Apache Software Foundation.
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: /*
017: * $Id: FuncKey.java,v 1.20 2004/08/17 18:35:33 jycli Exp $
018: */
019: package org.apache.xalan.templates;
020:
021: import java.util.Hashtable;
022:
023: import org.apache.xalan.transformer.KeyManager;
024: import org.apache.xalan.transformer.TransformerImpl;
025: import org.apache.xml.dtm.DTM;
026: import org.apache.xml.dtm.DTMIterator;
027: import org.apache.xml.utils.QName;
028: import org.apache.xml.utils.XMLString;
029: import org.apache.xpath.XPathContext;
030: import org.apache.xpath.axes.UnionPathIterator;
031: import org.apache.xpath.functions.Function2Args;
032: import org.apache.xpath.objects.XNodeSet;
033: import org.apache.xpath.objects.XObject;
034:
035: /**
036: * Execute the Key() function.
037: * @xsl.usage advanced
038: */
039: public class FuncKey extends Function2Args {
040: static final long serialVersionUID = 9089293100115347340L;
041:
042: /** Dummy value to be used in usedrefs hashtable */
043: static private Boolean ISTRUE = new Boolean(true);
044:
045: /**
046: * Execute the function. The function must return
047: * a valid object.
048: * @param xctxt The current execution context.
049: * @return A valid XObject.
050: *
051: * @throws javax.xml.transform.TransformerException
052: */
053: public XObject execute(XPathContext xctxt)
054: throws javax.xml.transform.TransformerException {
055:
056: // TransformerImpl transformer = (TransformerImpl)xctxt;
057: TransformerImpl transformer = (TransformerImpl) xctxt
058: .getOwnerObject();
059: XNodeSet nodes = null;
060: int context = xctxt.getCurrentNode();
061: DTM dtm = xctxt.getDTM(context);
062: int docContext = dtm.getDocumentRoot(context);
063:
064: if (DTM.NULL == docContext) {
065:
066: // path.error(context, XPATHErrorResources.ER_CONTEXT_HAS_NO_OWNERDOC); //"context does not have an owner document!");
067: }
068:
069: String xkeyname = getArg0().execute(xctxt).str();
070: QName keyname = new QName(xkeyname, xctxt.getNamespaceContext());
071: XObject arg = getArg1().execute(xctxt);
072: boolean argIsNodeSetDTM = (XObject.CLASS_NODESET == arg
073: .getType());
074: KeyManager kmgr = transformer.getKeyManager();
075:
076: // Don't bother with nodeset logic if the thing is only one node.
077: if (argIsNodeSetDTM) {
078: XNodeSet ns = (XNodeSet) arg;
079: ns.setShouldCacheNodes(true);
080: int len = ns.getLength();
081: if (len <= 1)
082: argIsNodeSetDTM = false;
083: }
084:
085: if (argIsNodeSetDTM) {
086: Hashtable usedrefs = null;
087: DTMIterator ni = arg.iter();
088: int pos;
089: UnionPathIterator upi = new UnionPathIterator();
090: upi.exprSetParent(this );
091:
092: while (DTM.NULL != (pos = ni.nextNode())) {
093: dtm = xctxt.getDTM(pos);
094: XMLString ref = dtm.getStringValue(pos);
095:
096: if (null == ref)
097: continue;
098:
099: if (null == usedrefs)
100: usedrefs = new Hashtable();
101:
102: if (usedrefs.get(ref) != null) {
103: continue; // We already have 'em.
104: } else {
105:
106: // ISTRUE being used as a dummy value.
107: usedrefs.put(ref, ISTRUE);
108: }
109:
110: XNodeSet nl = kmgr.getNodeSetDTMByKey(xctxt,
111: docContext, keyname, ref, xctxt
112: .getNamespaceContext());
113:
114: nl.setRoot(xctxt.getCurrentNode(), xctxt);
115:
116: // try
117: // {
118: upi.addIterator(nl);
119: // }
120: // catch(CloneNotSupportedException cnse)
121: // {
122: // // will never happen.
123: // }
124: //mnodeset.addNodesInDocOrder(nl, xctxt); needed??
125: }
126:
127: int current = xctxt.getCurrentNode();
128: upi.setRoot(current, xctxt);
129:
130: nodes = new XNodeSet(upi);
131: } else {
132: XMLString ref = arg.xstr();
133: nodes = kmgr.getNodeSetDTMByKey(xctxt, docContext, keyname,
134: ref, xctxt.getNamespaceContext());
135: nodes.setRoot(xctxt.getCurrentNode(), xctxt);
136: }
137:
138: return nodes;
139: }
140: }
|