KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > net > sf > saxon > pattern > CombinedNodeTest


1 package net.sf.saxon.pattern;
2 import net.sf.saxon.expr.Token;
3 import net.sf.saxon.om.NamePool;
4 import net.sf.saxon.om.NodeInfo;
5 import net.sf.saxon.type.AnyType;
6 import net.sf.saxon.type.SchemaType;
7 import net.sf.saxon.type.Type;
8 import net.sf.saxon.type.ItemType;
9 import net.sf.saxon.tinytree.TinyTree;
10
11 import java.util.Set JavaDoc;
12 import java.util.HashSet JavaDoc;
13
14 /**
15   * A CombinedNodeTest combines two nodetests using one of the operators
16   * union (=or), intersect (=and), difference (= "and not"). This arises
17   * when optimizing a union (etc) of two path expressions using the same axis.
18   * A CombinedNodeTest is also used to support constructs such as element(N,T),
19   * which can be expressed as (element(N,*) AND element(*,T))
20   *
21   * @author Michael H. Kay
22   */

23
24 public class CombinedNodeTest extends NodeTest {
25
26     private NodeTest nodetest1;
27     private NodeTest nodetest2;
28     private int operator;
29
30     public CombinedNodeTest(NodeTest nt1, int operator, NodeTest nt2) {
31         nodetest1 = nt1;
32         this.operator = operator;
33         nodetest2 = nt2;
34     }
35
36     /**
37     * Test whether this node test is satisfied by a given node.
38     * @param nodeType The type of node to be matched
39      @param fingerprint identifies the expanded name of the node to be matched.
40
41      */

42
43     public boolean matches(int nodeType, int fingerprint, int annotation) {
44         switch (operator) {
45             case Token.UNION:
46                 return nodetest1==null ||
47                        nodetest2==null ||
48                        nodetest1.matches(nodeType, fingerprint, annotation) ||
49                        nodetest2.matches(nodeType, fingerprint, annotation);
50             case Token.INTERSECT:
51                 return (nodetest1==null || nodetest1.matches(nodeType, fingerprint, annotation)) &&
52                        (nodetest2==null || nodetest2.matches(nodeType, fingerprint, annotation));
53             case Token.EXCEPT:
54                 return (nodetest1==null || nodetest1.matches(nodeType, fingerprint, annotation)) &&
55                        !(nodetest2==null || nodetest2.matches(nodeType, fingerprint, annotation));
56             default:
57                 throw new IllegalArgumentException JavaDoc("Unknown operator in Combined Node Test");
58         }
59     }
60
61     /**
62      * Test whether this node test is satisfied by a given node on a TinyTree. The node
63      * must be a document, element, text, comment, or processing instruction node.
64      * This method is provided
65      * so that when navigating a TinyTree a node can be rejected without
66      * actually instantiating a NodeInfo object.
67      *
68      * @param tree the TinyTree containing the node
69      * @param nodeNr the number of the node within the TinyTree
70      * @return true if the node matches the NodeTest, otherwise false
71      */

72
73     public boolean matches(TinyTree tree, int nodeNr) {
74         switch (operator) {
75             case Token.UNION:
76                 return nodetest1==null ||
77                        nodetest2==null ||
78                        nodetest1.matches(tree, nodeNr) ||
79                        nodetest2.matches(tree, nodeNr);
80             case Token.INTERSECT:
81                 return (nodetest1==null || nodetest1.matches(tree, nodeNr)) &&
82                        (nodetest2==null || nodetest2.matches(tree, nodeNr));
83             case Token.EXCEPT:
84                 return (nodetest1==null || nodetest1.matches(tree, nodeNr)) &&
85                        !(nodetest2==null || nodetest2.matches(tree, nodeNr));
86             default:
87                 throw new IllegalArgumentException JavaDoc("Unknown operator in Combined Node Test");
88         }
89     }
90
91     /**
92      * Test whether this node test is satisfied by a given node. This alternative
93      * method is used in the case of nodes where calculating the fingerprint is expensive,
94      * for example DOM or JDOM nodes.
95      * @param node the node to be matched
96      */

97
98     public boolean matches(NodeInfo node) {
99         switch (operator) {
100             case Token.UNION:
101                 return nodetest1==null ||
102                        nodetest2==null ||
103                        nodetest1.matches(node) ||
104                        nodetest2.matches(node);
105             case Token.INTERSECT:
106                 return (nodetest1==null || nodetest1.matches(node)) &&
107                        (nodetest2==null || nodetest2.matches(node));
108             case Token.EXCEPT:
109                 return (nodetest1==null || nodetest1.matches(node)) &&
110                        !(nodetest2==null || nodetest2.matches(node));
111             default:
112                 throw new IllegalArgumentException JavaDoc("Unknown operator in Combined Node Test");
113         }
114     }
115
116     public String JavaDoc toString(NamePool pool) {
117         if (nodetest1 instanceof NameTest && operator==Token.INTERSECT) {
118             int kind = nodetest1.getPrimitiveType();
119             String JavaDoc content = "";
120             if (nodetest2 instanceof ContentTypeTest) {
121                 content = ", " + ((ContentTypeTest)nodetest2).getSchemaType().getDisplayName();
122             }
123             String JavaDoc name = pool.getDisplayName(nodetest1.getFingerprint());
124             if (kind == Type.ELEMENT) {
125                 return "element(" + name + content + ')';
126             } else if (kind == Type.ATTRIBUTE) {
127                 return "attribute(" + name + content + ')';
128             }
129         }
130         String JavaDoc nt1 = (nodetest1==null ? "true()" : nodetest1.toString(pool));
131         String JavaDoc nt2 = (nodetest2==null ? "true()" : nodetest2.toString(pool));
132         return '(' + nt1 + ' ' + Token.tokens[operator] + ' ' + nt2 + ')';
133     }
134
135     /**
136      * Get the supertype of this type. This isn't actually a well-defined concept: the types
137      * form a lattice rather than a strict hierarchy.
138      */

139
140     public ItemType getSuperType() {
141         switch (operator) {
142             case Token.UNION:
143                 return Type.getCommonSuperType(nodetest1, nodetest2);
144             case Token.INTERSECT:
145                 return nodetest1;
146             case Token.EXCEPT:
147                 return nodetest1;
148             default:
149                 throw new IllegalArgumentException JavaDoc("Unknown operator in Combined Node Test");
150         }
151     }
152
153     /**
154      * Get a mask indicating which kinds of nodes this NodeTest can match. This is a combination
155      * of bits: 1<<Type.ELEMENT for element nodes, 1<<Type.TEXT for text nodes, and so on.
156      */

157
158     public int getNodeKindMask() {
159         switch (operator) {
160             case Token.UNION:
161                 return nodetest1.getNodeKindMask() | nodetest2.getNodeKindMask();
162             case Token.INTERSECT:
163                 return nodetest1.getNodeKindMask() & nodetest2.getNodeKindMask();
164             case Token.EXCEPT:
165                 return nodetest1.getNodeKindMask();
166             default:
167                 return 0;
168         }
169
170     }
171
172     /**
173      * Get the basic kind of object that this ItemType matches: for a NodeTest, this is the kind of node,
174      * or Type.Node if it matches different kinds of nodes.
175      *
176      * @return the node kind matched by this node test
177      */

178
179     public int getPrimitiveType() {
180         int mask = getNodeKindMask();
181         if (mask == (1<<Type.ELEMENT)) {
182             return Type.ELEMENT;
183         }
184         if (mask == (1<<Type.ATTRIBUTE)) {
185             return Type.ATTRIBUTE;
186         }
187         if (mask == (1<<Type.DOCUMENT)) {
188             return Type.DOCUMENT;
189         }
190         return Type.NODE;
191     }
192
193     /**
194      * Get the set of node names allowed by this NodeTest. This is returned as a set of Integer fingerprints.
195      * A null value indicates that all names are permitted (i.e. that there are no constraints on the node name.
196      * The default implementation returns null.
197      */

198
199     public Set JavaDoc getRequiredNodeNames() {
200         Set JavaDoc s1 = nodetest1.getRequiredNodeNames();
201         Set JavaDoc s2 = nodetest2.getRequiredNodeNames();
202         if (s2 == null) {
203             return s1;
204         }
205         if (s1 == null) {
206             return s2;
207         }
208         switch (operator) {
209             case Token.UNION: {
210                 Set JavaDoc result = new HashSet JavaDoc(s1);
211                 result.addAll(s2);
212                 return result;
213             }
214             case Token.INTERSECT: {
215                 Set JavaDoc result = new HashSet JavaDoc(s1);
216                 result.retainAll(s2);
217                 return result;
218             }
219             case Token.EXCEPT: {
220                 Set JavaDoc result = new HashSet JavaDoc(s1);
221                 result.removeAll(s2);
222                 return result;
223             }
224             default:
225                 throw new UnsupportedOperationException JavaDoc();
226         }
227     }
228
229     /**
230      * Get the content type allowed by this NodeTest (that is, the type annotation of the matched nodes).
231      * Return AnyType if there are no restrictions. The default implementation returns AnyType.
232      */

233
234     public SchemaType getContentType() {
235         SchemaType type1 = nodetest1.getContentType();
236         SchemaType type2 = nodetest2.getContentType();
237         if (type1.isSameType(type2)) return type1;
238         if (operator == Token.INTERSECT) {
239             if (type2 instanceof AnyType) {
240                 return type1;
241             }
242             if (type1 instanceof AnyType) {
243                 return type2;
244             }
245         }
246         return AnyType.getInstance();
247     }
248
249     /**
250      * Get the name of the nodes matched by this nodetest, if it matches a specific name.
251      * Return -1 if the node test matches nodes of more than one name
252      */

253
254     public int getFingerprint() {
255         int fp1 = nodetest1.getFingerprint();
256         int fp2 = nodetest2.getFingerprint();
257         if (fp1 == fp2) return fp1;
258         if (fp2 == -1 && operator==Token.INTERSECT) return fp1;
259         if (fp1 == -1 && operator==Token.INTERSECT) return fp2;
260         return -1;
261     }
262
263     /**
264       * Returns a hash code value for the object.
265       */

266
267      public int hashCode() {
268          return nodetest1.hashCode() ^ nodetest2.hashCode();
269      }
270
271     /**
272      * get the default priority of this nodeTest when used as a pattern
273      */

274
275     public double getDefaultPriority() {
276         return 0.25;
277     }
278
279     /**
280      * Get the two parts of the combined node test
281      */

282
283     public NodeTest[] getComponentNodeTests() {
284         NodeTest[] tests = {nodetest1, nodetest2};
285         return tests;
286     }
287 }
288
289 //
290
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
291
// you may not use this file except in compliance with the License. You may obtain a copy of the
292
// License at http://www.mozilla.org/MPL/
293
//
294
// Software distributed under the License is distributed on an "AS IS" basis,
295
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
296
// See the License for the specific language governing rights and limitations under the License.
297
//
298
// The Original Code is: all this file.
299
//
300
// The Initial Developer of the Original Code is Michael H. Kay.
301
//
302
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
303
//
304
// Contributor(s): none.
305
//
306
Popular Tags