KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > icl > saxon > pattern > LocationPathPattern


1 package com.icl.saxon.pattern;
2 import com.icl.saxon.expr.*;
3 import com.icl.saxon.*;
4 import com.icl.saxon.om.*;
5 import com.icl.saxon.om.Axis;
6 import com.icl.saxon.expr.XPathException;
7
8 /**
9 * A LocationPathPattern represents a path, e.g. of the form A/B/C... The components are represented
10 * as a linked list, each component pointing to its predecessor
11 */

12
13 public final class LocationPathPattern extends Pattern {
14
15     // the following public variables are exposed to the ExpressionParser
16

17     public Pattern parentPattern = null;
18     public Pattern ancestorPattern = null;
19     public NodeTest nodeTest = AnyNodeTest.getInstance();
20     protected Expression[] filters = null;
21     protected int numberOfFilters = 0;
22     protected Expression equivalentExpr = null;
23     protected boolean firstElementPattern = false;
24     protected boolean lastElementPattern = false;
25     protected boolean specialFilter = false;
26
27     /**
28     * Add a filter to the pattern (while under construction)
29     * @param filter The predicate (a boolean expression or numeric expression) to be added
30     */

31
32     public void addFilter(Expression filter) {
33         if (filters==null) {
34             filters = new Expression[3];
35         } else if (numberOfFilters == filters.length) {
36             Expression[] f2 = new Expression[numberOfFilters * 2];
37             System.arraycopy(filters, 0, f2, 0, numberOfFilters);
38             filters = f2;
39         }
40         filters[numberOfFilters++] = filter;
41     }
42
43     /**
44     * Simplify the pattern: perform any context-independent optimisations
45     */

46
47     public Pattern simplify() throws XPathException {
48
49         // detect the simple cases: no parent or ancestor pattern, no predicates
50

51         if ( parentPattern == null &&
52                 ancestorPattern == null &&
53                 filters == null) {
54             nodeTest.setStaticContext(getStaticContext());
55             return nodeTest;
56         }
57
58         // simplify each component of the pattern
59

60         if (parentPattern != null) parentPattern = parentPattern.simplify();
61         if (ancestorPattern != null) ancestorPattern = ancestorPattern.simplify();
62         if (filters != null) {
63             for (int i=numberOfFilters-1; i>=0; i--) {
64                 Expression filter = filters[i].simplify();
65                 filters[i] = filter;
66                 // if the last filter is constant true, remove it
67
if ((filter instanceof BooleanValue) && (((Value)filter).asBoolean())) {
68                     if (i==numberOfFilters-1) {
69                         numberOfFilters--;
70                     } // otherwise don't bother doing anything with it.
71
}
72             }
73         }
74
75         // see if it's an element pattern with a single positional predicate of [1]
76

77         if (nodeTest.getNodeType() == NodeInfo.ELEMENT &&
78                 numberOfFilters==1 &&
79                 (filters[0] instanceof NumericValue) &&
80                 (int)((NumericValue)filters[0]).asNumber()==1 ) {
81             firstElementPattern = true;
82             specialFilter = true;
83             numberOfFilters = 0;
84             filters = null;
85         }
86
87         // see if it's an element pattern with a single positional predicate
88
// of [position()=last()]
89

90         if (nodeTest.getNodeType() == NodeInfo.ELEMENT &&
91                 numberOfFilters==1 &&
92                 filters[0] instanceof IsLastExpression &&
93                 ((IsLastExpression)filters[0]).getCondition()) {
94             lastElementPattern = true;
95             specialFilter = true;
96             numberOfFilters = 0;
97             filters = null;
98         }
99
100         if (isRelative()) {
101             makeEquivalentExpression();
102             specialFilter = true;
103         }
104
105         return this;
106     }
107     
108
109     /**
110     * For a positional pattern, make an equivalent nodeset expression to evaluate the filters
111     */

112
113     private void makeEquivalentExpression() throws XPathException {
114         byte axis = (nodeTest.getNodeType()==NodeInfo.ATTRIBUTE ?
115                         Axis.ATTRIBUTE :
116                         Axis.CHILD );
117         Step step = new Step(axis, nodeTest);
118         step.setFilters(filters, numberOfFilters);
119         equivalentExpr = new PathExpression(new ParentNodeExpression(), step);
120     }
121
122     /**
123     * Determine whether the pattern matches a given node.
124     * @param node the node to be tested
125     * @return true if the pattern matches, else false
126     */

127
128     // diagnostic version of method
129
public boolean matchesX(NodeInfo node, Context context) throws XPathException {
130         System.err.println("Matching node " + node + " against LP pattern " + this);
131         System.err.println("Node types " + node.getNodeType() + " / " + this.getNodeType());
132         boolean b = matches(node, context);
133         System.err.println((b ? "matches" : "no match"));
134         return b;
135     }
136
137     public boolean matches(NodeInfo node, Context context) throws XPathException {
138
139         if (!nodeTest.matches(node)) return false;
140         
141         if (parentPattern!=null) {
142             NodeInfo par = node.getParent();
143             if (par==null) return false;
144             if (!(parentPattern.matches(par, context))) return false;
145         }
146
147         if (ancestorPattern!=null) {
148             NodeInfo anc = node.getParent();
149             while (true) {
150                 if (ancestorPattern.matches(anc, context)) break;
151                 anc = anc.getParent();
152                 if (anc==null) return false;
153             }
154         }
155         
156         if (specialFilter) {
157             if (firstElementPattern) {
158                 NodeEnumeration enum = node.getEnumeration(Axis.PRECEDING_SIBLING, nodeTest);
159                 return !enum.hasMoreElements();
160             }
161
162             if (lastElementPattern) {
163                 NodeEnumeration enum = node.getEnumeration(Axis.FOLLOWING_SIBLING, nodeTest);
164                 return !enum.hasMoreElements();
165             }
166             
167             if (equivalentExpr!=null) {
168                     
169                 // for a positional pattern, we do it the hard way: test whether the
170
// node is a member of the nodeset obtained by evaluating the
171
// equivalent expression
172

173                 Context c = context.newContext();
174                 c.setContextNode(node);
175                 c.setPosition(1);
176                 c.setLast(1);
177                 NodeEnumeration nsv = equivalentExpr.enumerate(c, false);
178                 while (nsv.hasMoreElements()) {
179                     NodeInfo n = nsv.nextElement();
180                     if (n.isSameNode(node)) {
181                         return true;
182                     }
183                 }
184                 return false;
185             }
186         }
187
188         if (filters!=null) {
189             Context c = context.newContext();
190             c.setContextNode(node);
191             c.setPosition(1); // the filters aren't positional
192
c.setLast(1);
193                     
194             for (int i=0; i<numberOfFilters; i++) {
195                 if (!filters[i].evaluateAsBoolean(c)) return false;
196             }
197         }
198
199         return true;
200     }
201
202     /**
203     * Determine the types of nodes to which this pattern applies. Used for optimisation.
204     * For patterns that match nodes of several types, return Node.NODE
205     * @return the type of node matched by this pattern. e.g. Node.ELEMENT or Node.TEXT
206     */

207
208     public short getNodeType() {
209         return nodeTest.getNodeType();
210     }
211
212     /**
213     * Determine the fingerprint of nodes to which this pattern applies.
214     * Used for optimisation.
215     * @return the fingerprint of nodes matched by this pattern.
216     */

217
218     public int getFingerprint() {
219         return nodeTest.getFingerprint();
220     }
221
222     /**
223     * Determine if the pattern uses positional filters
224     * @return true if there is a numeric filter in the pattern, or one that uses the position()
225     * or last() functions
226     */

227
228     public boolean isRelative() throws XPathException {
229         if (filters==null) return false;
230         for (int i=0; i<numberOfFilters; i++) {
231             int type = filters[i].getDataType();
232             if (type==Value.NUMBER || type==Value.ANY) return true;
233             if ((filters[i].getDependencies() &
234                      (Context.POSITION | Context.LAST)) != 0) return true;
235         }
236         return false;
237     }
238 }
239
240 //
241
// The contents of this file are subject to the Mozilla Public License Version 1.0 (the "License");
242
// you may not use this file except in compliance with the License. You may obtain a copy of the
243
// License at http://www.mozilla.org/MPL/
244
//
245
// Software distributed under the License is distributed on an "AS IS" basis,
246
// WITHOUT WARRANTY OF ANY KIND, either express or implied.
247
// See the License for the specific language governing rights and limitations under the License.
248
//
249
// The Original Code is: all this file.
250
//
251
// The Initial Developer of the Original Code is
252
// Michael Kay of International Computers Limited (mhkay@iclway.co.uk).
253
//
254
// Portions created by (your name) are Copyright (C) (your legal entity). All Rights Reserved.
255
//
256
// Contributor(s): none.
257
//
258
Popular Tags