KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > commons > jxpath > ri > axes > SimplePathInterpreter


1 /*
2  * Copyright 1999-2004 The Apache Software Foundation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */

16 package org.apache.commons.jxpath.ri.axes;
17
18 import java.util.ArrayList JavaDoc;
19 import java.util.Collections JavaDoc;
20 import java.util.List JavaDoc;
21
22 import org.apache.commons.jxpath.JXPathException;
23 import org.apache.commons.jxpath.ri.Compiler;
24 import org.apache.commons.jxpath.ri.EvalContext;
25 import org.apache.commons.jxpath.ri.InfoSetUtil;
26 import org.apache.commons.jxpath.ri.QName;
27 import org.apache.commons.jxpath.ri.compiler.Expression;
28 import org.apache.commons.jxpath.ri.compiler.NameAttributeTest;
29 import org.apache.commons.jxpath.ri.compiler.NodeNameTest;
30 import org.apache.commons.jxpath.ri.compiler.NodeTest;
31 import org.apache.commons.jxpath.ri.compiler.Step;
32 import org.apache.commons.jxpath.ri.model.NodeIterator;
33 import org.apache.commons.jxpath.ri.model.NodePointer;
34 import org.apache.commons.jxpath.ri.model.beans.LangAttributePointer;
35 import org.apache.commons.jxpath.ri.model.beans.NullElementPointer;
36 import org.apache.commons.jxpath.ri.model.beans.NullPropertyPointer;
37 import org.apache.commons.jxpath.ri.model.beans.PropertyOwnerPointer;
38 import org.apache.commons.jxpath.ri.model.beans.PropertyPointer;
39
40 /**
41  * An evaluation mechanism for simple XPaths, which
42  * is much faster than the usual process. It is only used for
43  * xpaths which have no context-dependent parts, consist entirely of
44  * <code>child::name</code> and <code>self::node()</code> steps with
45  * predicates that either integer or have the form <code>[@name = ...]</code>.
46  *
47  * @author Dmitri Plotnikov
48  * @version $Revision: 1.10 $ $Date: 2002/04/24 04:05:40 $
49  */

50 public class SimplePathInterpreter {
51
52     // Because of the complexity caused by the variety of situations
53
// that need to be addressed by this class, we attempt to break up
54
// the class into individual methods addressing those situations
55
// individually. The names of the methods are supposed to
56
// give brief descriptions of those situations.
57

58     private static final QName QNAME_NAME = new QName(null, "name");
59     private static final int PERFECT_MATCH = 1000;
60
61     // Uncomment this variable and the PATH = ... lines in
62
// the two following methods in order to be able to print the
63
// currently evaluated path for debugging of this class
64
// private static String PATH; // Debugging
65

66     /**
67      * Interpret a simple path that starts with the given root and
68      * follows the given steps. All steps must have the axis "child::"
69      * and a name test. They can also optionally have predicates
70      * of type [@name=expression] or simply [expression] interpreted
71      * as an index.
72      */

73     public static NodePointer interpretSimpleLocationPath(
74             EvalContext context, NodePointer root, Step steps[])
75     {
76 // PATH = createNullPointer(context, root, steps, 0).toString(); // Dbg
77
NodePointer pointer = doStep(context, root, steps, 0);
78 // return valuePointer(pointer);
79
return pointer;
80     }
81
82     /**
83      * Interpret the steps of a simple expression path that
84      * starts with the given root, which is the result of evaluation
85      * of the root expression of the expression path, applies the
86      * given predicates to it and then follows the given steps.
87      * All steps must have the axis "child::" or "attribute::"
88      * and a name test. They can also optionally have predicates
89      * of type [@name=...] or simply [...] interpreted as an index.
90      */

91     public static NodePointer interpretSimpleExpressionPath(
92                 EvalContext context, NodePointer root,
93                 Expression predicates[], Step[] steps)
94     {
95 // PATH = createNullPointerForPredicates(context, root,
96
// steps, -1, predicates, 0).toString(); // Debugging
97
NodePointer pointer =
98             doPredicate(context, root, steps, -1, predicates, 0);
99 // return valuePointer(pointer);
100
return pointer;
101     }
102
103     /**
104      * Recursive evaluation of a path. The general plan is:
105      * Look at the current step,
106      * find nodes that match it,
107      * iterate over those nodes and
108      * for each of them call doStep again for subsequent steps.
109      */

110     private static NodePointer doStep(
111             EvalContext context, NodePointer parent,
112             Step steps[], int currentStep)
113     {
114         if (parent == null) {
115             return null;
116         }
117
118         if (currentStep == steps.length) {
119             // We have reached the end of the list of steps
120
return parent;
121         }
122
123         // Open all containers
124
parent = valuePointer(parent);
125         
126         Step step = steps[currentStep];
127         Expression predicates[] = step.getPredicates();
128
129         // Divide and conquer: the process is broken out into
130
// four major use cases.
131
// 1. Current step has no predicates and
132
// the root is a property owner (e.g. bean or map)
133
// 2. Current step has predicates and
134
// the root is a property owner (e.g. bean or map)
135
// 3. Current step has no predicates and
136
// the root is an InfoSet standard node (e.g. DOM Node)
137
// 4. Current step has predicates and
138
// the root is an InfoSet standard node (e.g. DOM Node)
139

140         if (parent instanceof PropertyOwnerPointer) {
141             if (predicates == null || predicates.length == 0) {
142                 return doStepNoPredicatesPropertyOwner(
143                     context,
144                     (PropertyOwnerPointer) parent,
145                     steps,
146                     currentStep);
147             }
148             else {
149                 return doStepPredicatesPropertyOwner(
150                     context,
151                     (PropertyOwnerPointer) parent,
152                     steps,
153                     currentStep);
154             }
155         }
156         else {
157             if (predicates == null || predicates.length == 0) {
158                 return doStepNoPredicatesStandard(
159                     context,
160                     parent,
161                     steps,
162                     currentStep);
163             }
164             else {
165                 return doStepPredicatesStandard(
166                     context,
167                     parent,
168                     steps,
169                     currentStep);
170             }
171         }
172     }
173
174     /**
175      * We have a step that starts with a property owner (bean, map, etc) and has
176      * no predicates. The name test of the step may map to a scalar property
177      * or to a collection. If it is a collection, we should apply the tail of
178      * the path to each element until we find a match. If we don't find
179      * a perfect match, we should return the "best quality" pointer, which
180      * has the longest chain of steps mapping to existing nodes and the shortes
181      * tail of Null* pointers.
182      */

183     private static NodePointer doStepNoPredicatesPropertyOwner(
184                 EvalContext context, PropertyOwnerPointer parentPointer,
185                 Step[] steps, int currentStep)
186     {
187         Step step = steps[currentStep];
188         NodePointer childPointer =
189             createChildPointerForStep(parentPointer, step);
190
191         if (!childPointer.isActual()) {
192             // The property does not exist - create a null pointer.
193
return createNullPointer(
194                 context,
195                 parentPointer,
196                 steps,
197                 currentStep);
198         }
199         else if (currentStep == steps.length - 1) {
200             // If this is the last step - we are done, we found it
201
return childPointer;
202         }
203         else if (childPointer.isCollection()) {
204             // Iterate over all values and
205
// execute remaining steps for each node,
206
// looking for the best quality match
207
int bestQuality = 0;
208             childPointer = (NodePointer) childPointer.clone();
209             NodePointer bestMatch = null;
210             int count = childPointer.getLength();
211             for (int i = 0; i < count; i++) {
212                 childPointer.setIndex(i);
213                 NodePointer pointer =
214                     doStep(context, childPointer, steps, currentStep + 1);
215                 int quality = computeQuality(pointer);
216                 if (quality == PERFECT_MATCH) {
217                     return pointer;
218                 }
219                 else if (quality > bestQuality) {
220                     bestQuality = quality;
221                     bestMatch = (NodePointer) pointer.clone();
222                 }
223             }
224             if (bestMatch != null) {
225                 return bestMatch;
226             }
227             // This step did not find anything - return a null pointer
228
return createNullPointer(context, childPointer, steps, currentStep);
229         }
230         else {
231             // Evaluate subsequent steps
232
return doStep(context, childPointer, steps, currentStep + 1);
233         }
234     }
235
236     /**
237      * A path that starts with a standard InfoSet node (e.g. DOM Node) and
238      * has no predicates. Get a child iterator and apply the tail of
239      * the path to each element until we find a match. If we don't find
240      * a perfect match, we should return the "best quality" pointer, which
241      * has the longest chain of steps mapping to existing nodes and the shortes
242      * tail of Null* pointers.
243      */

244     private static NodePointer doStepNoPredicatesStandard(
245                 EvalContext context, NodePointer parentPointer,
246                 Step[] steps, int currentStep)
247     {
248         Step step = steps[currentStep];
249
250         if (step.getAxis() == Compiler.AXIS_SELF) {
251             return doStep(context, parentPointer, steps, currentStep + 1);
252         }
253
254         int bestQuality = 0;
255         NodePointer bestMatch = null;
256         NodeIterator it = getNodeIterator(context, parentPointer, step);
257         if (it != null) {
258             for (int i = 1; it.setPosition(i); i++) {
259                 NodePointer childPointer = it.getNodePointer();
260                 if (steps.length == currentStep + 1) {
261                     // If this is the last step - we are done, we found it
262
return childPointer;
263                 }
264                 NodePointer pointer = doStep(
265                         context, childPointer, steps, currentStep + 1);
266                 int quality = computeQuality(pointer);
267                 if (quality == PERFECT_MATCH) {
268                     return pointer;
269                 }
270                 else if (quality > bestQuality) {
271                     bestQuality = quality;
272                     bestMatch = (NodePointer) pointer.clone();
273                 }
274             }
275         }
276
277         if (bestMatch != null) {
278             return bestMatch;
279         }
280
281         return createNullPointer(
282                 context, parentPointer, steps, currentStep);
283     }
284
285     /**
286      * A path that starts with a property owner. The method evaluates
287      * the first predicate in a special way and then forwards to
288      * a general predicate processing method.
289      */

290     private static NodePointer doStepPredicatesPropertyOwner(
291             EvalContext context, PropertyOwnerPointer parentPointer,
292             Step[] steps, int currentStep)
293     {
294         Step step = steps[currentStep];
295         Expression predicates[] = step.getPredicates();
296
297         NodePointer childPointer =
298             createChildPointerForStep(parentPointer, step);
299         if (!childPointer.isActual()) {
300             // Property does not exist - return a null pointer
301
return createNullPointer(
302                 context,
303                 parentPointer,
304                 steps,
305                 currentStep);
306         }
307
308         // Evaluate predicates
309
return doPredicate(
310             context,
311             childPointer,
312             steps,
313             currentStep,
314             predicates,
315             0);
316     }
317
318     private static NodePointer createChildPointerForStep(
319                 PropertyOwnerPointer parentPointer, Step step)
320     {
321         int axis = step.getAxis();
322         if (axis == Compiler.AXIS_CHILD || axis == Compiler.AXIS_ATTRIBUTE) {
323             NodePointer childPointer;
324             QName name = ((NodeNameTest) step.getNodeTest()).getNodeName();
325             if (axis == Compiler.AXIS_ATTRIBUTE && isLangAttribute(name)) {
326                 childPointer = new LangAttributePointer(parentPointer);
327             }
328             else {
329                 childPointer = parentPointer.getPropertyPointer();
330                 ((PropertyPointer) childPointer).setPropertyName(
331                     name.toString());
332                 childPointer.setAttribute(axis == Compiler.AXIS_ATTRIBUTE);
333             }
334             return childPointer;
335         }
336         else {
337             return parentPointer;
338         }
339     }
340
341     /**
342      * A path that starts with a standard InfoSet node, e.g. a DOM Node.
343      * The method evaluates the first predicate in a special way and
344      * then forwards to a general predicate processing method.
345      */

346     private static NodePointer doStepPredicatesStandard(
347             EvalContext context, NodePointer parent,
348             Step[] steps, int currentStep)
349     {
350         Step step = steps[currentStep];
351         Expression predicates[] = step.getPredicates();
352
353         int axis = step.getAxis();
354         if (axis == Compiler.AXIS_SELF) {
355             return doPredicate(
356                 context,
357                 parent,
358                 steps,
359                 currentStep,
360                 predicates,
361                 0);
362         }
363
364         Expression predicate = predicates[0];
365
366         // Optimize for a single predicate to avoid building a list
367
// and to allow the direct access to the index'th element
368
// in the case of a simple subscript predecate
369
// It is a very common use case, so it deserves individual
370
// attention
371
if (predicates.length == 1) {
372             NodeIterator it = getNodeIterator(context, parent, step);
373             NodePointer pointer = null;
374             if (it != null) {
375                 if (predicate instanceof NameAttributeTest) { // [@name = key]
376
String JavaDoc key = keyFromPredicate(context, predicate);
377                     for (int i = 1; it.setPosition(i); i++) {
378                         NodePointer ptr = it.getNodePointer();
379                         if (isNameAttributeEqual(ptr, key)) {
380                             pointer = ptr;
381                             break;
382                         }
383                     }
384                 }
385                 else {
386                     int index = indexFromPredicate(context, predicate);
387                     if (it.setPosition(index + 1)) {
388                         pointer = it.getNodePointer();
389                     }
390                 }
391             }
392             if (pointer != null) {
393                 return doStep(context, pointer, steps, currentStep + 1);
394             }
395         }
396         else {
397             NodeIterator it = getNodeIterator(context, parent, step);
398             if (it != null) {
399                 List JavaDoc list = new ArrayList JavaDoc();
400                 for (int i = 1; it.setPosition(i); i++) {
401                     list.add(it.getNodePointer());
402                 }
403                 NodePointer pointer =
404                     doPredicatesStandard(
405                         context,
406                         list,
407                         steps,
408                         currentStep,
409                         predicates,
410                         0);
411                 if (pointer != null) {
412                     return pointer;
413                 }
414             }
415         }
416         return createNullPointer(context, parent, steps, currentStep);
417     }
418
419     /**
420      * Evaluates predicates and proceeds with the subsequent steps
421      * of the path.
422      */

423     private static NodePointer doPredicate(
424                 EvalContext context, NodePointer parent,
425                 Step[] steps, int currentStep,
426                 Expression predicates[], int currentPredicate)
427     {
428         if (currentPredicate == predicates.length) {
429             return doStep(context, parent, steps, currentStep + 1);
430         }
431
432         Expression predicate = predicates[currentPredicate];
433         if (predicate instanceof NameAttributeTest) { // [@name = key1]
434
return doPredicateName(
435                 context,
436                 parent,
437                 steps,
438                 currentStep,
439                 predicates,
440                 currentPredicate);
441         }
442         else { // [index]
443
return doPredicateIndex(
444                 context,
445                 parent,
446                 steps,
447                 currentStep,
448                 predicates,
449                 currentPredicate);
450         }
451     }
452
453     private static NodePointer doPredicateName(
454             EvalContext context, NodePointer parent,
455             Step[] steps, int currentStep,
456             Expression[] predicates, int currentPredicate)
457     {
458         Expression predicate = predicates[currentPredicate];
459         String JavaDoc key = keyFromPredicate(context, predicate);
460         NodePointer child = valuePointer(parent);
461         if (child instanceof PropertyOwnerPointer) {
462             PropertyPointer pointer =
463                 ((PropertyOwnerPointer) child).getPropertyPointer();
464             pointer.setPropertyName(key);
465             if (pointer.isActual()) {
466                 return doPredicate(
467                     context,
468                     pointer,
469                     steps,
470                     currentStep,
471                     predicates,
472                     currentPredicate + 1);
473             }
474         }
475         else if (child.isCollection()) {
476             // For each node in the collection, perform the following:
477
// if the node is a property owner, apply this predicate to it;
478
// if the node is a collection, apply this predicate to each elem.;
479
// if the node is not a prop owner or a collection,
480
// see if it has the attribute "name" with the right value,
481
// if so - proceed to the next predicate
482
NodePointer bestMatch = null;
483             int bestQuality = 0;
484             child = (NodePointer) child.clone();
485             int count = child.getLength();
486             for (int i = 0; i < count; i++) {
487                 child.setIndex(i);
488                 NodePointer valuePointer = valuePointer(child);
489                 NodePointer pointer;
490                 if ((valuePointer instanceof PropertyOwnerPointer)
491                     || valuePointer.isCollection()) {
492                     pointer =
493                         doPredicateName(
494                             context,
495                             valuePointer,
496                             steps,
497                             currentStep,
498                             predicates,
499                             currentPredicate);
500                 }
501                 else if (isNameAttributeEqual(valuePointer, key)) {
502                     pointer =
503                         doPredicate(
504                             context,
505                             valuePointer,
506                             steps,
507                             currentStep,
508                             predicates,
509                             currentPredicate + 1);
510                 }
511                 else {
512                     pointer = null;
513                 }
514                 if (pointer != null) {
515                     int quality = computeQuality(pointer);
516                     if (quality == PERFECT_MATCH) {
517                         return pointer;
518                     }
519                     if (quality > bestQuality) {
520                         bestMatch = (NodePointer) pointer.clone();
521                         bestQuality = quality;
522                     }
523                 }
524             }
525             if (bestMatch != null) {
526                 return bestMatch;
527             }
528         }
529         else {
530             // If the node is a standard InfoSet node (e.g. DOM Node),
531
// employ doPredicates_standard, which will iterate through
532
// the node's children and apply all predicates
533
NodePointer found =
534                 doPredicatesStandard(
535                     context,
536                     Collections.singletonList(child),
537                     steps,
538                     currentStep,
539                     predicates,
540                     currentPredicate);
541             if (found != null) {
542                 return found;
543             }
544         }
545         // If nothing worked - return a null pointer
546
return createNullPointerForPredicates(
547             context,
548             child,
549             steps,
550             currentStep,
551             predicates,
552             currentPredicate);
553     }
554
555     /**
556      * Called exclusively for standard InfoSet nodes, e.g. DOM nodes
557      * to evaluate predicate sequences like [@name=...][@name=...][index].
558      */

559     private static NodePointer doPredicatesStandard(
560                 EvalContext context, List JavaDoc parents,
561                 Step[] steps, int currentStep,
562                 Expression predicates[], int currentPredicate)
563     {
564         if (parents.size() == 0) {
565             return null;
566         }
567
568         // If all predicates have been processed, take the first
569
// element from the list of results and proceed to the
570
// remaining steps with that element.
571
if (currentPredicate == predicates.length) {
572             NodePointer pointer = (NodePointer) parents.get(0);
573             return doStep(context, pointer, steps, currentStep + 1);
574         }
575
576         Expression predicate = predicates[currentPredicate];
577         if (predicate instanceof NameAttributeTest) {
578             String JavaDoc key = keyFromPredicate(context, predicate);
579             List JavaDoc newList = new ArrayList JavaDoc();
580             for (int i = 0; i < parents.size(); i++) {
581                 NodePointer pointer = (NodePointer) parents.get(i);
582                 if (isNameAttributeEqual(pointer, key)) {
583                     newList.add(pointer);
584                 }
585             }
586             if (newList.size() == 0) {
587                 return null;
588             }
589             return doPredicatesStandard(
590                 context,
591                 newList,
592                 steps,
593                 currentStep,
594                 predicates,
595                 currentPredicate + 1);
596         }
597         else {
598             // For a subscript, simply take the corresponding
599
// element from the list of results and
600
// proceed to the remaining predicates with that element
601
int index = indexFromPredicate(context, predicate);
602             if (index < 0 || index >= parents.size()) {
603                 return null;
604             }
605             NodePointer ptr = (NodePointer) parents.get(index);
606             return doPredicate(
607                 context,
608                 ptr,
609                 steps,
610                 currentStep,
611                 predicates,
612                 currentPredicate + 1);
613         }
614     }
615
616     /**
617      * Evaluate a subscript predicate: see if the node is a collection and
618      * if the index is inside the collection
619      */

620     private static NodePointer doPredicateIndex(
621             EvalContext context, NodePointer parent,
622             Step[] steps, int currentStep,
623             Expression[] predicates, int currentPredicate)
624     {
625         Expression predicate = predicates[currentPredicate];
626         int index = indexFromPredicate(context, predicate);
627         NodePointer pointer = parent;
628         if (isCollectionElement(pointer, index)) {
629             pointer = (NodePointer) pointer.clone();
630             pointer.setIndex(index);
631             return doPredicate(
632                 context,
633                 pointer,
634                 steps,
635                 currentStep,
636                 predicates,
637                 currentPredicate + 1);
638         }
639         return createNullPointerForPredicates(
640             context,
641             parent,
642             steps,
643             currentStep,
644             predicates,
645             currentPredicate);
646     }
647
648     /**
649      * Extract an integer from a subscript predicate. The returned index
650      * starts with 0, even though the subscript starts with 1.
651      */

652     private static int indexFromPredicate(
653         EvalContext context,
654         Expression predicate)
655     {
656         Object JavaDoc value = predicate.computeValue(context);
657         if (value instanceof EvalContext) {
658             value = ((EvalContext) value).getSingleNodePointer();
659         }
660         if (value instanceof NodePointer) {
661             value = ((NodePointer) value).getValue();
662         }
663         if (value == null) {
664             throw new JXPathException("Predicate value is null");
665         }
666
667         if (value instanceof Number JavaDoc) {
668             return (int) (InfoSetUtil.doubleValue(value) + 0.5) - 1;
669         }
670         else if (InfoSetUtil.booleanValue(value)) {
671             return 0;
672         }
673
674         return -1;
675     }
676
677     /**
678      * Extracts the string value of the expression from a predicate like
679      * [@name=expression].
680      */

681     private static String JavaDoc keyFromPredicate(EvalContext context,
682                 Expression predicate)
683     {
684         Expression expr =
685             ((NameAttributeTest) predicate).getNameTestExpression();
686         return InfoSetUtil.stringValue(expr.computeValue(context));
687     }
688
689     /**
690      * For a pointer that matches an actual node, returns 0.
691      * For a pointer that does not match an actual node, but whose
692      * parent pointer does returns -1, etc.
693      */

694     private static int computeQuality(NodePointer pointer) {
695         int quality = PERFECT_MATCH;
696         while (pointer != null && !pointer.isActual()) {
697             quality--;
698             pointer = pointer.getImmediateParentPointer();
699         }
700         return quality;
701     }
702
703     /**
704      * Returns true if the pointer has an attribute called "name" and
705      * its value is equal to the supplied string.
706      */

707     private static boolean isNameAttributeEqual(
708         NodePointer pointer,
709         String JavaDoc name)
710     {
711         NodeIterator it = pointer.attributeIterator(QNAME_NAME);
712         return it != null
713             && it.setPosition(1)
714             && name.equals(it.getNodePointer().getValue());
715     }
716
717     /**
718      * Returns true if the pointer is a collection and the index is
719      * withing the bounds of the collection.
720      */

721     private static boolean isCollectionElement(
722         NodePointer pointer,
723         int index)
724     {
725         return pointer.isActual()
726             && (index == 0
727                 || (pointer.isCollection()
728                     && index >= 0
729                     && index < pointer.getLength()));
730     }
731
732     /**
733      * For an intermediate pointer (e.g. PropertyPointer, ContainerPointer)
734      * returns a pointer for the contained value.
735      */

736     private static NodePointer valuePointer(NodePointer pointer) {
737         return pointer == null ? null : pointer.getValuePointer();
738     }
739
740     /**
741      * Creates a "null pointer" that
742      * a) represents the requested path and
743      * b) can be used for creation of missing nodes in the path.
744      */

745     public static NodePointer createNullPointer(
746             EvalContext context, NodePointer parent, Step[] steps,
747             int currentStep)
748     {
749         if (currentStep == steps.length) {
750             return parent;
751         }
752
753         parent = valuePointer(parent);
754
755         Step step = steps[currentStep];
756
757         int axis = step.getAxis();
758         if (axis == Compiler.AXIS_CHILD || axis == Compiler.AXIS_ATTRIBUTE) {
759             NullPropertyPointer pointer = new NullPropertyPointer(parent);
760             QName name = ((NodeNameTest) step.getNodeTest()).getNodeName();
761             pointer.setPropertyName(name.toString());
762             pointer.setAttribute(axis == Compiler.AXIS_ATTRIBUTE);
763             parent = pointer;
764         }
765         // else { it is self::node() }
766

767         Expression predicates[] = step.getPredicates();
768         return createNullPointerForPredicates(
769             context,
770             parent,
771             steps,
772             currentStep,
773             predicates,
774             0);
775     }
776
777     /**
778      * Creates a "null pointer" that starts with predicates.
779      */

780     private static NodePointer createNullPointerForPredicates(
781             EvalContext context, NodePointer parent,
782             Step[] steps, int currentStep,
783             Expression predicates[], int currentPredicate)
784     {
785         for (int i = currentPredicate; i < predicates.length; i++) {
786             Expression predicate = predicates[i];
787             if (predicate instanceof NameAttributeTest) {
788                 String JavaDoc key = keyFromPredicate(context, predicate);
789                 parent = valuePointer(parent);
790                 NullPropertyPointer pointer = new NullPropertyPointer(parent);
791                 pointer.setNameAttributeValue(key);
792                 parent = pointer;
793             }
794             else {
795                 int index = indexFromPredicate(context, predicate);
796                 if (parent instanceof NullPropertyPointer) {
797                     parent.setIndex(index);
798                 }
799                 else {
800                     parent = new NullElementPointer(parent, index);
801                 }
802             }
803         }
804         // Proceed with the remaining steps
805
return createNullPointer(
806                     context, parent, steps, currentStep + 1);
807     }
808
809     private static NodeIterator getNodeIterator(
810         EvalContext context,
811         NodePointer pointer,
812         Step step)
813     {
814         if (step.getAxis() == Compiler.AXIS_CHILD) {
815             NodeTest nodeTest = step.getNodeTest();
816             QName qname = ((NodeNameTest) nodeTest).getNodeName();
817             String JavaDoc prefix = qname.getPrefix();
818             if (prefix != null) {
819                 String JavaDoc namespaceURI = context.getJXPathContext()
820                         .getNamespaceURI(prefix);
821                 nodeTest = new NodeNameTest(qname, namespaceURI);
822
823             }
824             return pointer.childIterator(nodeTest, false, null);
825         }
826         else { // Compiler.AXIS_ATTRIBUTE
827
if (!(step.getNodeTest() instanceof NodeNameTest)) {
828                 throw new UnsupportedOperationException JavaDoc(
829                     "Not supported node test for attributes: "
830                         + step.getNodeTest());
831             }
832             return pointer.attributeIterator(
833                 ((NodeNameTest) step.getNodeTest()).getNodeName());
834         }
835     }
836
837     private static boolean isLangAttribute(QName name) {
838         return name.getPrefix() != null
839             && name.getPrefix().equals("xml")
840             && name.getName().equals("lang");
841     }
842 }
Popular Tags