1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17 package org.apache.commons.jxpath.ri.axes;
18
19 import java.util.ArrayList;
20 import java.util.Collections;
21 import java.util.List;
22
23 import org.apache.commons.jxpath.JXPathException;
24 import org.apache.commons.jxpath.ri.Compiler;
25 import org.apache.commons.jxpath.ri.EvalContext;
26 import org.apache.commons.jxpath.ri.InfoSetUtil;
27 import org.apache.commons.jxpath.ri.QName;
28 import org.apache.commons.jxpath.ri.compiler.Expression;
29 import org.apache.commons.jxpath.ri.compiler.NameAttributeTest;
30 import org.apache.commons.jxpath.ri.compiler.NodeNameTest;
31 import org.apache.commons.jxpath.ri.compiler.NodeTest;
32 import org.apache.commons.jxpath.ri.compiler.Step;
33 import org.apache.commons.jxpath.ri.model.NodeIterator;
34 import org.apache.commons.jxpath.ri.model.NodePointer;
35 import org.apache.commons.jxpath.ri.model.beans.LangAttributePointer;
36 import org.apache.commons.jxpath.ri.model.beans.NullElementPointer;
37 import org.apache.commons.jxpath.ri.model.beans.NullPropertyPointer;
38 import org.apache.commons.jxpath.ri.model.beans.PropertyOwnerPointer;
39 import org.apache.commons.jxpath.ri.model.beans.PropertyPointer;
40
41
42
43
44
45
46
47
48
49
50
51 public class SimplePathInterpreter {
52
53
54
55
56
57
58
59 private static final QName QNAME_NAME = new QName(null, "name");
60 private static final int PERFECT_MATCH = 1000;
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78 public static NodePointer interpretSimpleLocationPath(
79 EvalContext context, NodePointer root, Step[] steps) {
80
81 NodePointer pointer = doStep(context, root, steps, 0);
82
83 return pointer;
84 }
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100 public static NodePointer interpretSimpleExpressionPath(
101 EvalContext context, NodePointer root,
102 Expression[] predicates, Step[] steps) {
103
104
105 NodePointer pointer =
106 doPredicate(context, root, steps, -1, predicates, 0);
107
108 return pointer;
109 }
110
111
112
113
114
115
116
117
118
119
120
121
122
123 private static NodePointer doStep(
124 EvalContext context, NodePointer parent,
125 Step[] steps, int currentStep) {
126 if (parent == null) {
127 return null;
128 }
129
130 if (currentStep == steps.length) {
131
132 return parent;
133 }
134
135
136 parent = valuePointer(parent);
137
138 Step step = steps[currentStep];
139 Expression[] predicates = step.getPredicates();
140
141
142
143
144
145
146
147
148
149
150
151
152 if (parent instanceof PropertyOwnerPointer) {
153 if (predicates == null || predicates.length == 0) {
154 return doStepNoPredicatesPropertyOwner(
155 context,
156 (PropertyOwnerPointer) parent,
157 steps,
158 currentStep);
159 }
160 return doStepPredicatesPropertyOwner(
161 context,
162 (PropertyOwnerPointer) parent,
163 steps,
164 currentStep);
165 }
166 if (predicates == null || predicates.length == 0) {
167 return doStepNoPredicatesStandard(
168 context,
169 parent,
170 steps,
171 currentStep);
172 }
173 return doStepPredicatesStandard(
174 context,
175 parent,
176 steps,
177 currentStep);
178 }
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194 private static NodePointer doStepNoPredicatesPropertyOwner(
195 EvalContext context, PropertyOwnerPointer parentPointer,
196 Step[] steps, int currentStep) {
197 Step step = steps[currentStep];
198 NodePointer childPointer =
199 createChildPointerForStep(parentPointer, step);
200
201 if (childPointer == null) {
202 return null;
203 }
204 if (!childPointer.isActual()) {
205
206 return createNullPointer(
207 context,
208 parentPointer,
209 steps,
210 currentStep);
211 }
212 if (currentStep == steps.length - 1) {
213
214 return childPointer;
215 }
216 if (childPointer.isCollection()) {
217
218
219
220 int bestQuality = 0;
221 childPointer = (NodePointer) childPointer.clone();
222 NodePointer bestMatch = null;
223 int count = childPointer.getLength();
224 for (int i = 0; i < count; i++) {
225 childPointer.setIndex(i);
226 NodePointer pointer =
227 doStep(context, childPointer, steps, currentStep + 1);
228 int quality = computeQuality(pointer);
229 if (quality == PERFECT_MATCH) {
230 return pointer;
231 }
232 else if (quality > bestQuality) {
233 bestQuality = quality;
234 bestMatch = (NodePointer) pointer.clone();
235 }
236 }
237 if (bestMatch != null) {
238 return bestMatch;
239 }
240
241 return createNullPointer(context, childPointer, steps, currentStep);
242 }
243
244 return doStep(context, childPointer, steps, currentStep + 1);
245 }
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260 private static NodePointer doStepNoPredicatesStandard(
261 EvalContext context, NodePointer parentPointer,
262 Step[] steps, int currentStep) {
263 Step step = steps[currentStep];
264
265 if (step.getAxis() == Compiler.AXIS_SELF) {
266 return doStep(context, parentPointer, steps, currentStep + 1);
267 }
268
269 int bestQuality = 0;
270 NodePointer bestMatch = null;
271 NodeIterator it = getNodeIterator(context, parentPointer, step);
272 if (it != null) {
273 for (int i = 1; it.setPosition(i); i++) {
274 NodePointer childPointer = it.getNodePointer();
275 if (steps.length == currentStep + 1) {
276
277 return childPointer;
278 }
279 NodePointer pointer = doStep(
280 context, childPointer, steps, currentStep + 1);
281 int quality = computeQuality(pointer);
282 if (quality == PERFECT_MATCH) {
283 return pointer;
284 }
285 if (quality > bestQuality) {
286 bestQuality = quality;
287 bestMatch = (NodePointer) pointer.clone();
288 }
289 }
290 }
291 return bestMatch != null ? bestMatch
292 : createNullPointer(context, parentPointer, steps, currentStep);
293 }
294
295
296
297
298
299
300
301
302
303
304
305 private static NodePointer doStepPredicatesPropertyOwner(
306 EvalContext context, PropertyOwnerPointer parentPointer,
307 Step[] steps, int currentStep) {
308 Step step = steps[currentStep];
309 Expression[] predicates = step.getPredicates();
310
311 NodePointer childPointer =
312 createChildPointerForStep(parentPointer, step);
313 if (!childPointer.isActual()) {
314
315 return createNullPointer(
316 context,
317 parentPointer,
318 steps,
319 currentStep);
320 }
321
322
323 return doPredicate(
324 context,
325 childPointer,
326 steps,
327 currentStep,
328 predicates,
329 0);
330 }
331
332
333
334
335
336
337
338 private static NodePointer createChildPointerForStep(
339 PropertyOwnerPointer parentPointer, Step step) {
340 int axis = step.getAxis();
341 if (axis == Compiler.AXIS_CHILD || axis == Compiler.AXIS_ATTRIBUTE) {
342 QName name = ((NodeNameTest) step.getNodeTest()).getNodeName();
343 if (axis == Compiler.AXIS_ATTRIBUTE && isLangAttribute(name)) {
344 return new LangAttributePointer(parentPointer);
345 }
346 if (parentPointer.isValidProperty(name)) {
347 NodePointer childPointer = parentPointer.getPropertyPointer();
348 ((PropertyPointer) childPointer).setPropertyName(
349 name.toString());
350 childPointer.setAttribute(axis == Compiler.AXIS_ATTRIBUTE);
351 return childPointer;
352 }
353
354 return null;
355 }
356 return parentPointer;
357 }
358
359
360
361
362
363
364
365
366
367
368
369 private static NodePointer doStepPredicatesStandard(
370 EvalContext context, NodePointer parent,
371 Step[] steps, int currentStep) {
372 Step step = steps[currentStep];
373 Expression[] predicates = step.getPredicates();
374
375 int axis = step.getAxis();
376 if (axis == Compiler.AXIS_SELF) {
377 return doPredicate(
378 context,
379 parent,
380 steps,
381 currentStep,
382 predicates,
383 0);
384 }
385
386 Expression predicate = predicates[0];
387
388
389
390
391
392
393 if (predicates.length == 1) {
394 NodeIterator it = getNodeIterator(context, parent, step);
395 NodePointer pointer = null;
396 if (it != null) {
397 if (predicate instanceof NameAttributeTest) {
398 String key = keyFromPredicate(context, predicate);
399 for (int i = 1; it.setPosition(i); i++) {
400 NodePointer ptr = it.getNodePointer();
401 if (isNameAttributeEqual(ptr, key)) {
402 pointer = ptr;
403 break;
404 }
405 }
406 }
407 else {
408 int index = indexFromPredicate(context, predicate);
409 if (it.setPosition(index + 1)) {
410 pointer = it.getNodePointer();
411 }
412 }
413 }
414 if (pointer != null) {
415 return doStep(context, pointer, steps, currentStep + 1);
416 }
417 }
418 else {
419 NodeIterator it = getNodeIterator(context, parent, step);
420 if (it != null) {
421 List list = new ArrayList();
422 for (int i = 1; it.setPosition(i); i++) {
423 list.add(it.getNodePointer());
424 }
425 NodePointer pointer =
426 doPredicatesStandard(
427 context,
428 list,
429 steps,
430 currentStep,
431 predicates,
432 0);
433 if (pointer != null) {
434 return pointer;
435 }
436 }
437 }
438 return createNullPointer(context, parent, steps, currentStep);
439 }
440
441
442
443
444
445
446
447
448
449
450
451
452 private static NodePointer doPredicate(
453 EvalContext context, NodePointer parent,
454 Step[] steps, int currentStep,
455 Expression[] predicates, int currentPredicate) {
456 if (currentPredicate == predicates.length) {
457 return doStep(context, parent, steps, currentStep + 1);
458 }
459
460 Expression predicate = predicates[currentPredicate];
461 if (predicate instanceof NameAttributeTest) {
462 return doPredicateName(
463 context,
464 parent,
465 steps,
466 currentStep,
467 predicates,
468 currentPredicate);
469 }
470
471 return doPredicateIndex(
472 context,
473 parent,
474 steps,
475 currentStep,
476 predicates,
477 currentPredicate);
478 }
479
480
481
482
483
484
485
486
487
488
489
490 private static NodePointer doPredicateName(
491 EvalContext context, NodePointer parent,
492 Step[] steps, int currentStep,
493 Expression[] predicates, int currentPredicate) {
494 Expression predicate = predicates[currentPredicate];
495 String key = keyFromPredicate(context, predicate);
496 NodePointer child = valuePointer(parent);
497 if (child instanceof PropertyOwnerPointer) {
498 PropertyPointer pointer =
499 ((PropertyOwnerPointer) child).getPropertyPointer();
500 pointer.setPropertyName(key);
501 if (pointer.isActual()) {
502 return doPredicate(
503 context,
504 pointer,
505 steps,
506 currentStep,
507 predicates,
508 currentPredicate + 1);
509 }
510 }
511 else if (child.isCollection()) {
512
513
514
515
516
517
518 NodePointer bestMatch = null;
519 int bestQuality = 0;
520 child = (NodePointer) child.clone();
521 int count = child.getLength();
522 for (int i = 0; i < count; i++) {
523 child.setIndex(i);
524 NodePointer valuePointer = valuePointer(child);
525 NodePointer pointer;
526 if ((valuePointer instanceof PropertyOwnerPointer)
527 || valuePointer.isCollection()) {
528 pointer =
529 doPredicateName(
530 context,
531 valuePointer,
532 steps,
533 currentStep,
534 predicates,
535 currentPredicate);
536 }
537 else if (isNameAttributeEqual(valuePointer, key)) {
538 pointer =
539 doPredicate(
540 context,
541 valuePointer,
542 steps,
543 currentStep,
544 predicates,
545 currentPredicate + 1);
546 }
547 else {
548 pointer = null;
549 }
550 if (pointer != null) {
551 int quality = computeQuality(pointer);
552 if (quality == PERFECT_MATCH) {
553 return pointer;
554 }
555 if (quality > bestQuality) {
556 bestMatch = (NodePointer) pointer.clone();
557 bestQuality = quality;
558 }
559 }
560 }
561 if (bestMatch != null) {
562 return bestMatch;
563 }
564 }
565 else {
566
567
568
569 NodePointer found =
570 doPredicatesStandard(
571 context,
572 Collections.singletonList(child),
573 steps,
574 currentStep,
575 predicates,
576 currentPredicate);
577 if (found != null) {
578 return found;
579 }
580 }
581
582 return createNullPointerForPredicates(
583 context,
584 child,
585 steps,
586 currentStep,
587 predicates,
588 currentPredicate);
589 }
590
591
592
593
594
595
596
597
598
599
600
601
602 private static NodePointer doPredicatesStandard(
603 EvalContext context, List parents,
604 Step[] steps, int currentStep,
605 Expression[] predicates, int currentPredicate) {
606 if (parents.size() == 0) {
607 return null;
608 }
609
610
611
612
613 if (currentPredicate == predicates.length) {
614 NodePointer pointer = (NodePointer) parents.get(0);
615 return doStep(context, pointer, steps, currentStep + 1);
616 }
617
618 Expression predicate = predicates[currentPredicate];
619 if (predicate instanceof NameAttributeTest) {
620 String key = keyFromPredicate(context, predicate);
621 List newList = new ArrayList();
622 for (int i = 0; i < parents.size(); i++) {
623 NodePointer pointer = (NodePointer) parents.get(i);
624 if (isNameAttributeEqual(pointer, key)) {
625 newList.add(pointer);
626 }
627 }
628 if (newList.size() == 0) {
629 return null;
630 }
631 return doPredicatesStandard(
632 context,
633 newList,
634 steps,
635 currentStep,
636 predicates,
637 currentPredicate + 1);
638 }
639 else {
640
641
642
643 int index = indexFromPredicate(context, predicate);
644 if (index < 0 || index >= parents.size()) {
645 return null;
646 }
647 NodePointer ptr = (NodePointer) parents.get(index);
648 return doPredicate(
649 context,
650 ptr,
651 steps,
652 currentStep,
653 predicates,
654 currentPredicate + 1);
655 }
656 }
657
658
659
660
661
662
663
664
665
666
667
668
669 private static NodePointer doPredicateIndex(
670 EvalContext context, NodePointer parent,
671 Step[] steps, int currentStep,
672 Expression[] predicates, int currentPredicate) {
673 Expression predicate = predicates[currentPredicate];
674 int index = indexFromPredicate(context, predicate);
675 NodePointer pointer = parent;
676 if (isCollectionElement(pointer, index)) {
677 pointer = (NodePointer) pointer.clone();
678 pointer.setIndex(index);
679 return doPredicate(
680 context,
681 pointer,
682 steps,
683 currentStep,
684 predicates,
685 currentPredicate + 1);
686 }
687 return createNullPointerForPredicates(
688 context,
689 parent,
690 steps,
691 currentStep,
692 predicates,
693 currentPredicate);
694 }
695
696
697
698
699
700
701
702
703 private static int indexFromPredicate(
704 EvalContext context,
705 Expression predicate) {
706 Object value = predicate.computeValue(context);
707 if (value instanceof EvalContext) {
708 value = ((EvalContext) value).getSingleNodePointer();
709 }
710 if (value instanceof NodePointer) {
711 value = ((NodePointer) value).getValue();
712 }
713 if (value == null) {
714 throw new JXPathException("Predicate value is null: " + predicate);
715 }
716
717 if (value instanceof Number) {
718 final double round = 0.5;
719 return (int) (InfoSetUtil.doubleValue(value) + round) - 1;
720 }
721 return InfoSetUtil.booleanValue(value) ? 0 : -1;
722 }
723
724
725
726
727
728
729
730
731 private static String keyFromPredicate(EvalContext context,
732 Expression predicate) {
733 Expression expr =
734 ((NameAttributeTest) predicate).getNameTestExpression();
735 return InfoSetUtil.stringValue(expr.computeValue(context));
736 }
737
738
739
740
741
742
743
744
745 private static int computeQuality(NodePointer pointer) {
746 int quality = PERFECT_MATCH;
747 while (pointer != null && !pointer.isActual()) {
748 quality--;
749 pointer = pointer.getImmediateParentPointer();
750 }
751 return quality;
752 }
753
754
755
756
757
758
759
760
761 private static boolean isNameAttributeEqual(
762 NodePointer pointer,
763 String name) {
764 NodeIterator it = pointer.attributeIterator(QNAME_NAME);
765 return it != null
766 && it.setPosition(1)
767 && name.equals(it.getNodePointer().getValue());
768 }
769
770
771
772
773
774
775
776
777 private static boolean isCollectionElement(
778 NodePointer pointer,
779 int index) {
780 return pointer.isActual()
781 && (index == 0
782 || (pointer.isCollection()
783 && index >= 0
784 && index < pointer.getLength()));
785 }
786
787
788
789
790
791
792
793 private static NodePointer valuePointer(NodePointer pointer) {
794 return pointer == null ? null : pointer.getValuePointer();
795 }
796
797
798
799
800
801
802
803
804
805
806
807 public static NodePointer createNullPointer(
808 EvalContext context, NodePointer parent, Step[] steps,
809 int currentStep) {
810 if (currentStep == steps.length) {
811 return parent;
812 }
813
814 parent = valuePointer(parent);
815
816 Step step = steps[currentStep];
817
818 int axis = step.getAxis();
819 if (axis == Compiler.AXIS_CHILD || axis == Compiler.AXIS_ATTRIBUTE) {
820 NullPropertyPointer pointer = new NullPropertyPointer(parent);
821 QName name = ((NodeNameTest) step.getNodeTest()).getNodeName();
822 pointer.setPropertyName(name.toString());
823 pointer.setAttribute(axis == Compiler.AXIS_ATTRIBUTE);
824 parent = pointer;
825 }
826
827
828 Expression[] predicates = step.getPredicates();
829 return createNullPointerForPredicates(
830 context,
831 parent,
832 steps,
833 currentStep,
834 predicates,
835 0);
836 }
837
838
839
840
841
842
843
844
845
846
847
848 private static NodePointer createNullPointerForPredicates(
849 EvalContext context, NodePointer parent,
850 Step[] steps, int currentStep,
851 Expression[] predicates, int currentPredicate) {
852 for (int i = currentPredicate; i < predicates.length; i++) {
853 Expression predicate = predicates[i];
854 if (predicate instanceof NameAttributeTest) {
855 String key = keyFromPredicate(context, predicate);
856 parent = valuePointer(parent);
857 NullPropertyPointer pointer = new NullPropertyPointer(parent);
858 pointer.setNameAttributeValue(key);
859 parent = pointer;
860 }
861 else {
862 int index = indexFromPredicate(context, predicate);
863 if (parent instanceof NullPropertyPointer) {
864 parent.setIndex(index);
865 }
866 else {
867 parent = new NullElementPointer(parent, index);
868 }
869 }
870 }
871
872 return createNullPointer(
873 context, parent, steps, currentStep + 1);
874 }
875
876
877
878
879
880
881
882
883 private static NodeIterator getNodeIterator(
884 EvalContext context,
885 NodePointer pointer,
886 Step step) {
887 if (step.getAxis() == Compiler.AXIS_CHILD) {
888 NodeTest nodeTest = step.getNodeTest();
889 QName qname = ((NodeNameTest) nodeTest).getNodeName();
890 String prefix = qname.getPrefix();
891 if (prefix != null) {
892 String namespaceURI = context.getJXPathContext()
893 .getNamespaceURI(prefix);
894 nodeTest = new NodeNameTest(qname, namespaceURI);
895 }
896 return pointer.childIterator(nodeTest, false, null);
897 }
898
899 if (!(step.getNodeTest() instanceof NodeNameTest)) {
900 throw new UnsupportedOperationException(
901 "Not supported node test for attributes: "
902 + step.getNodeTest());
903 }
904 return pointer.attributeIterator(
905 ((NodeNameTest) step.getNodeTest()).getNodeName());
906 }
907
908
909
910
911
912
913 private static boolean isLangAttribute(QName name) {
914 return name.getPrefix() != null
915 && name.getPrefix().equals("xml")
916 && name.getName().equals("lang");
917 }
918 }