KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > icl > saxon > KeyManager


1 package com.icl.saxon;
2
3 import com.icl.saxon.om.*;
4 import com.icl.saxon.pattern.Pattern;
5 import com.icl.saxon.expr.Expression;
6 import com.icl.saxon.pattern.AnyNodeTest;
7 import com.icl.saxon.expr.Value;
8 import com.icl.saxon.expr.NodeSetValue;
9 import com.icl.saxon.om.NodeEnumeration;
10 import com.icl.saxon.expr.NodeSetExtent;
11 import com.icl.saxon.om.Axis;
12 import com.icl.saxon.om.SingletonEnumeration;
13 import com.icl.saxon.om.EmptyEnumeration;
14 import com.icl.saxon.expr.XPathException;
15 import com.icl.saxon.sort.LocalOrderComparer;
16
17 import java.util.*;
18
19 /**
20   * KeyManager manages the set of key definitions in a stylesheet, and the indexes
21   * associated with these key definitions
22   * @author Michael H. Kay (mhkay@iclway.co.uk)
23   */

24   
25 public class KeyManager {
26
27     private Hashtable keyList; // one entry for each named key; the entry contains
28
// a list of key definitions with that name
29

30     /**
31     * create a KeyManager and initialise variables
32     */

33
34     public KeyManager() {
35         keyList = new Hashtable();
36     }
37
38     /**
39     * Register a key definition. Note that multiple key definitions with the same name are
40     * allowed
41     * @param keyDefinition The details of the key's definition
42     */

43
44     public void setKeyDefinition(KeyDefinition keydef) {
45         Integer keykey = new Integer(keydef.getFingerprint());
46         Vector v = (Vector)keyList.get(keykey);
47         if (v==null) {
48             v = new Vector();
49             keyList.put(keykey, v);
50         }
51         v.addElement(keydef);
52     }
53
54     /**
55     * Get all the key definitions that match a particular fingerprint
56     * @param fingerprint The fingerprint of the name of the required key
57     * @return The key definition of the named key if there is one, or null otherwise.
58     */

59
60     public Vector getKeyDefinitions(int fingerprint) {
61         return (Vector)keyList.get(new Integer(fingerprint));
62     }
63
64     /**
65     * Build the index for a particular document for a named key
66     * @param fingerprint The fingerprint of the name of the required key
67     * @param doc The source document in question
68     * @param controller The controller
69     * @return the index in question, as a Hashtable mapping a key value onto a Vector of nodes
70     */

71
72     private synchronized Hashtable buildIndex(int fingerprint,
73                                            DocumentInfo doc,
74                                            Controller controller) throws XPathException {
75
76         Vector definitions = getKeyDefinitions(fingerprint);
77         if (definitions==null) {
78             throw new XPathException("Key " +
79                     controller.getNamePool().getDisplayName(fingerprint) +
80                                         " has not been defined");
81         }
82
83         Hashtable index = new Hashtable();
84
85         for (int k=0; k<definitions.size(); k++) {
86             constructIndex(doc, index, (KeyDefinition)definitions.elementAt(k),
87              controller, k==0);
88         }
89
90         return index;
91         
92     }
93
94     /**
95     * Process one key definition to add entries to an index
96     */

97
98     private void constructIndex( DocumentInfo doc,
99                                     Hashtable index,
100                                     KeyDefinition keydef,
101                                     Controller controller,
102                                     boolean isFirst) throws XPathException {
103                                         
104         Pattern match = keydef.getMatch();
105         Expression use = keydef.getUse();
106         NodeInfo sourceRoot = doc;
107         NodeInfo curr = sourceRoot;
108         Context c = controller.makeContext(doc);
109
110         short type = match.getNodeType();
111         
112         NodeEnumeration all =
113             doc.getEnumeration( Axis.DESCENDANT,
114                                 AnyNodeTest.getInstance());
115
116         
117         if (type==NodeInfo.ATTRIBUTE || type==NodeInfo.NODE) {
118             while(all.hasMoreElements()) {
119                 curr = all.nextElement();
120                 if (curr.getNodeType()==NodeInfo.ELEMENT) {
121                     NodeEnumeration atts =
122                         curr.getEnumeration(Axis.ATTRIBUTE, AnyNodeTest.getInstance());
123                     while (atts.hasMoreElements()) {
124                         processKeyNode(atts.nextElement(), match, use, index, c, isFirst);
125                     }
126                     if (type==NodeInfo.NODE) {
127                         // index the element as well (bug 6.3/001)
128
processKeyNode(curr, match, use, index, c, isFirst);
129                     }
130                 } else {
131                     processKeyNode(curr, match, use, index, c, isFirst);
132                 }
133             }
134
135         } else {
136             while(all.hasMoreElements()) {
137                 curr = all.nextElement();
138                 processKeyNode(curr, match, use, index, c, isFirst);
139             }
140         }
141     }
142
143     /**
144     * Process one node, adding it to the index if appropriate
145     */

146
147     private void processKeyNode(NodeInfo curr, Pattern match, Expression use,
148                                 Hashtable index, Context c, boolean isFirst) throws XPathException {
149         if (match.matches(curr, c)) {
150             c.setContextNode(curr);
151             c.setCurrentNode(curr);
152             c.setPosition(1);
153             c.setLast(1);
154             Value useval = use.evaluate(c);
155             if (useval instanceof NodeSetValue) {
156                 //c.setContextNode(curr);
157
NodeEnumeration enum = ((NodeSetValue)useval).enumerate();
158                 while (enum.hasMoreElements()) {
159                     NodeInfo node = (NodeInfo)enum.nextElement();
160                     String val = node.getStringValue();
161                     NodeSetExtent nodes = (NodeSetExtent)index.get(val);
162                     if (nodes==null) {
163                         nodes = new NodeSetExtent(LocalOrderComparer.getInstance());
164                         nodes.setSorted(true);
165                         index.put(val, nodes);
166                     }
167                     nodes.append(curr);
168                     if (!isFirst) {
169                         // when adding nodes for a second key definition, we
170
// need to keep the list sorted. This is very inefficient,
171
// but hopefully not done too often.
172
nodes.setSorted(false);
173                         nodes.sort();
174                     }
175                 }
176             } else {
177                 String val = useval.asString();
178                 c.setContextNode(curr);
179                 NodeSetExtent nodes = (NodeSetExtent)index.get(val);
180                 if (nodes==null) {
181                     nodes = new NodeSetExtent(LocalOrderComparer.getInstance());
182                     nodes.setSorted(true);
183                     index.put(val, nodes);
184                 }
185                 nodes.append(curr);
186                 if (!isFirst) {
187                     // when adding nodes for a second key definition, we
188
// need to keep the list sorted. This is very inefficient,
189
// but hopefully not done too often.
190
nodes.setSorted(false);
191                     nodes.sort();
192                 }
193             }
194         }
195     }
196
197     /**
198     * Get the nodes with a given key value
199     * @param fingerprint The fingerprint of the name of the required key
200     * @param doc The source document in question
201     * @param value The required key value
202     * @param controller The controller, needed only the first time when the key is being built
203     * @return an enumeration of nodes, always in document order
204     */

205
206     public NodeEnumeration selectByKey( int fingerprint,
207                                 DocumentInfo doc,
208                                 String value,
209                                 Controller controller) throws XPathException {
210                                     
211         Hashtable index = doc.getKeyIndex(this, fingerprint);
212         if (index==null) {
213             index = buildIndex(fingerprint, doc, controller);
214             doc.setKeyIndex(this, fingerprint, index);
215         }
216         NodeSetExtent nodes = (NodeSetExtent)index.get(value);
217         return (nodes==null ? EmptyEnumeration.getInstance() : nodes.enumerate());
218     }
219
220 }
221
222 //
223
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
224
// you may not use this file except in compliance with the License. You may obtain a copy of the
225
// License at http://www.mozilla.org/MPL/
226
//
227
// Software distributed under the License is distributed on an "AS IS" basis,
228
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
229
// See the License for the specific language governing rights and limitations under the License.
230
//
231
// The Original Code is: all this file.
232
//
233
// The Initial Developer of the Original Code is
234
// Michael Kay of International Computers Limited (mhkay@iclway.co.uk).
235
//
236
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
237
//
238
// Contributor(s): none.
239
//
240
Popular Tags