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