19f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson/*
29f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Licensed to the Apache Software Foundation (ASF) under one
39f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * or more contributor license agreements. See the NOTICE file
49f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * distributed with this work for additional information
59f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * regarding copyright ownership. The ASF licenses this file
69f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * to you under the Apache License, Version 2.0 (the  "License");
79f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * you may not use this file except in compliance with the License.
89f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * You may obtain a copy of the License at
99f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson *
109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson *     http://www.apache.org/licenses/LICENSE-2.0
119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson *
129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Unless required by applicable law or agreed to in writing, software
139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * distributed under the License is distributed on an "AS IS" BASIS,
149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * See the License for the specific language governing permissions and
169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * limitations under the License.
179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson */
189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson/*
199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * $Id: KeyTable.java 468645 2006-10-28 06:57:24Z minchau $
209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson */
219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonpackage org.apache.xalan.transformer;
229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport java.util.Hashtable;
249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport java.util.Vector;
259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport javax.xml.transform.TransformerException;
279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.apache.xalan.templates.KeyDeclaration;
299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.apache.xml.dtm.DTM;
309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.apache.xml.dtm.DTMIterator;
319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.apache.xml.utils.PrefixResolver;
329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.apache.xml.utils.QName;
339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.apache.xml.utils.WrappedRuntimeException;
349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.apache.xml.utils.XMLString;
359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.apache.xpath.XPathContext;
369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.apache.xpath.objects.XNodeSet;
379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonimport org.apache.xpath.objects.XObject;
389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson/**
409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * Table of element keys, keyed by document node.  An instance of this
419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * class is keyed by a Document node that should be matched with the
429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * root of the current context.
439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson * @xsl.usage advanced
449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson */
459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilsonpublic class KeyTable
469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson{
479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * The document key.  This table should only be used with contexts
499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * whose Document roots match this key.
509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  private int m_docKey;
529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Vector of KeyDeclaration instances holding the key declarations.
559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  private Vector m_keyDeclarations;
579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Hold a cache of key() function result for each ref.
609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Key is XMLString, the ref value
619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Value is XNodeSet, the key() function result for the given ref value.
629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  private Hashtable m_refsTable = null;
649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Get the document root matching this key.
679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @return the document root matching this key
699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public int getDocKey()
719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    return m_docKey;
739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * The main iterator that will walk through the source
779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * tree for this key.
789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  private XNodeSet m_keyNodes;
809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  KeyIterator getKeyIterator()
829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  	return (KeyIterator)(m_keyNodes.getContainedIter());
849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Build a keys table.
889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param doc The owner document key.
899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param nscontext The stylesheet's namespace context.
909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param name The key name
919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param keyDeclarations The stylesheet's xsl:key declarations.
929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @throws javax.xml.transform.TransformerException
949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public KeyTable(
969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson          int doc, PrefixResolver nscontext, QName name, Vector keyDeclarations, XPathContext xctxt)
979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            throws javax.xml.transform.TransformerException
989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    m_docKey = doc;
1009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    m_keyDeclarations = keyDeclarations;
1019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    KeyIterator ki = new KeyIterator(name, keyDeclarations);
1029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    m_keyNodes = new XNodeSet(ki);
1049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    m_keyNodes.allowDetachToRelease(false);
1059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    m_keyNodes.setRoot(doc, xctxt);
1069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
1079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
1099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Given a valid element key, return the corresponding node list.
1109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
1119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param name The name of the key, which must match the 'name' attribute on xsl:key.
1129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param ref The value that must match the value found by the 'match' attribute on xsl:key.
1139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @return a set of nodes referenced by the key named <CODE>name</CODE> and the reference <CODE>ref</CODE>. If no node is referenced by this key, an empty node set is returned.
1149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
1159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public XNodeSet getNodeSetDTMByKey(QName name, XMLString ref)
1169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
1189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    XNodeSet refNodes = (XNodeSet) getRefsTable().get(ref);
1199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    // clone wiht reset the node set
1209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   try
1219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
1229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      if (refNodes != null)
1239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      {
1249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson         refNodes = (XNodeSet) refNodes.cloneWithReset();
1259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson       }
1269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
1279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    catch (CloneNotSupportedException e)
1289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
1299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      refNodes = null;
1309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
1319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if (refNodes == null) {
1339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson     //  create an empty XNodeSet
1349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      KeyIterator ki = (KeyIterator) (m_keyNodes).getContainedIter();
1359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      XPathContext xctxt = ki.getXPathContext();
1369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      refNodes = new XNodeSet(xctxt.getDTMManager()) {
1379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        public void setRoot(int nodeHandle, Object environment) {
1389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson          // Root cannot be set on non-iterated node sets. Ignore it.
1399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        }
1409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      };
1419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      refNodes.reset();
1429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
1439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    return refNodes;
1459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
1469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
1489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Get Key Name for this KeyTable
1499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *
1509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @return Key name
1519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
1529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  public QName getKeyTableName()
1539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
1549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    return getKeyIterator().getName();
1559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
1569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
1589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @return key declarations for the key associated to this KeyTable
1599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
1609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  private Vector getKeyDeclarations() {
1619f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    int nDeclarations = m_keyDeclarations.size();
1629f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    Vector keyDecls = new Vector(nDeclarations);
1639f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1649f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    // Walk through each of the declarations made with xsl:key
1659f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    for (int i = 0; i < nDeclarations; i++)
1669f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
1679f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      KeyDeclaration kd = (KeyDeclaration) m_keyDeclarations.elementAt(i);
1689f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1699f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      // Add the declaration if the name on this key declaration
1709f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      // matches the name on the iterator for this walker.
1719f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      if (kd.getName().equals(getKeyTableName())) {
1729f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        keyDecls.add(kd);
1739f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      }
1749f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
1759f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1769f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    return keyDecls;
1779f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
1789f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1799f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
1809f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @return lazy initialized refs table associating evaluation of key function
1819f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   *         with a XNodeSet
1829f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
1839f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  private Hashtable getRefsTable()
1849f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  {
1859f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if (m_refsTable == null) {
1869f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      // initial capacity set to a prime number to improve hash performance
1879f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      m_refsTable = new Hashtable(89);
1889f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1899f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      KeyIterator ki = (KeyIterator) (m_keyNodes).getContainedIter();
1909f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      XPathContext xctxt = ki.getXPathContext();
1919f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1929f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      Vector keyDecls = getKeyDeclarations();
1939f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      int nKeyDecls = keyDecls.size();
1949f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
1959f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      int currentNode;
1969f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      m_keyNodes.reset();
1979f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      while (DTM.NULL != (currentNode = m_keyNodes.nextNode()))
1989f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      {
1999f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        try
2009f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        {
2019f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson          for (int keyDeclIdx = 0; keyDeclIdx < nKeyDecls; keyDeclIdx++) {
2029f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            KeyDeclaration keyDeclaration =
2039f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                (KeyDeclaration) keyDecls.elementAt(keyDeclIdx);
2049f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            XObject xuse =
2059f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                keyDeclaration.getUse().execute(xctxt,
2069f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                                                currentNode,
2079f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                                                ki.getPrefixResolver());
2089f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2099f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            if (xuse.getType() != xuse.CLASS_NODESET) {
2109f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson              XMLString exprResult = xuse.xstr();
2119f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson              addValueInRefsTable(xctxt, exprResult, currentNode);
2129f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            } else {
2139f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson              DTMIterator i = ((XNodeSet)xuse).iterRaw();
2149f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson              int currentNodeInUseClause;
2159f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2169f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson              while (DTM.NULL != (currentNodeInUseClause = i.nextNode())) {
2179f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                DTM dtm = xctxt.getDTM(currentNodeInUseClause);
2189f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                XMLString exprResult =
2199f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                    dtm.getStringValue(currentNodeInUseClause);
2209f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson                addValueInRefsTable(xctxt, exprResult, currentNode);
2219f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson              }
2229f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson            }
2239f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson          }
2249f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        } catch (TransformerException te) {
2259f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson          throw new WrappedRuntimeException(te);
2269f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson        }
2279f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      }
2289f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
2299f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    return m_refsTable;
2309f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
2319f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2329f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  /**
2339f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Add an association between a ref and a node in the m_refsTable.
2349f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * Requires that m_refsTable != null
2359f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param xctxt XPath context
2369f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param ref the value of the use clause of the current key for the given node
2379f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   * @param node the node to reference
2389f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson   */
2399f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  private void addValueInRefsTable(XPathContext xctxt, XMLString ref, int node) {
2409f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson
2419f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    XNodeSet nodes = (XNodeSet) m_refsTable.get(ref);
2429f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    if (nodes == null)
2439f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
2449f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      nodes = new XNodeSet(node, xctxt.getDTMManager());
2459f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      nodes.nextNode();
2469f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      m_refsTable.put(ref, nodes);
2479f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
2489f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    else
2499f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    {
2509f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      // Nodes are passed to this method in document order.  Since we need to
2519f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      // suppress duplicates, we only need to check against the last entry
2529f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      // in each nodeset.  We use nodes.nextNode after each entry so we can
2539f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      // easily compare node against the current node.
2549f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      if (nodes.getCurrentNode() != node) {
2559f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson          nodes.mutableNodeset().addNode(node);
2569f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson          nodes.nextNode();
2579f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson      }
2589f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson    }
2599f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson  }
2609f8118474e9513f7a5b7d2a05e4a0fb15d1a6569Jesse Wilson}
261