1
2
3
4
5
6 package dev.metaschema.core.metapath.cst.path;
7
8 import java.util.List;
9
10 import dev.metaschema.core.metapath.DynamicContext;
11 import dev.metaschema.core.metapath.IExpression;
12 import dev.metaschema.core.metapath.cst.AbstractExpression;
13 import dev.metaschema.core.metapath.cst.ExpressionUtils;
14 import dev.metaschema.core.metapath.cst.IExpressionVisitor;
15 import dev.metaschema.core.metapath.item.IItem;
16 import dev.metaschema.core.metapath.item.ISequence;
17 import dev.metaschema.core.metapath.item.ItemUtils;
18 import dev.metaschema.core.metapath.item.node.INodeItem;
19 import dev.metaschema.core.util.CollectionUtil;
20 import dev.metaschema.core.util.ObjectUtils;
21 import edu.umd.cs.findbugs.annotations.NonNull;
22 import edu.umd.cs.findbugs.annotations.Nullable;
23
24
25
26
27
28
29 public class Step
30 extends AbstractExpression {
31
32 @NonNull
33 private final Axis axisExpression;
34 @Nullable
35 private final INodeTestExpression stepExpression;
36 @NonNull
37 private final Class<? extends IItem> staticResultType;
38
39
40
41
42
43
44
45
46
47 public Step(@NonNull String text, @NonNull Axis axis) {
48 this(text, axis, null);
49 }
50
51
52
53
54
55
56
57
58
59
60
61
62 public Step(@NonNull String text, @NonNull Axis axis, @Nullable INodeTestExpression step) {
63 super(text);
64 this.axisExpression = axis;
65 this.stepExpression = step;
66 this.staticResultType = ExpressionUtils.analyzeStaticResultType(IItem.class, step == null
67 ? CollectionUtil.emptyList()
68 : CollectionUtil.singletonList(step));
69 }
70
71
72
73
74
75
76 @NonNull
77 public Axis getAxis() {
78 return axisExpression;
79 }
80
81
82
83
84
85
86 @Nullable
87 public INodeTestExpression getStep() {
88 return stepExpression;
89 }
90
91 @Override
92 public Class<? extends IItem> getStaticResultType() {
93 return staticResultType;
94 }
95
96 @Override
97 public List<? extends IExpression> getChildren() {
98 IExpression step = getStep();
99 return step == null ? CollectionUtil.emptyList() : CollectionUtil.singletonList(step);
100 }
101
102 @Override
103 public <RESULT, CONTEXT> RESULT accept(IExpressionVisitor<RESULT, CONTEXT> visitor, CONTEXT context) {
104 return visitor.visitStep(this, context);
105 }
106
107 @Override
108 protected ISequence<?> evaluate(DynamicContext dynamicContext, ISequence<?> focus) {
109 Axis axis = getAxis();
110
111 ISequence<? extends INodeItem> axisResult;
112 if (focus.isEmpty()) {
113 axisResult = ISequence.empty();
114 } else {
115 axisResult = ISequence.of(ObjectUtils.notNull(focus.stream()
116 .map(item -> ItemUtils.checkItemIsNodeItem(dynamicContext, item))
117 .flatMap(item -> {
118 assert item != null;
119 return axis.execute(item);
120 }).distinct()));
121 }
122
123 IExpression step = getStep();
124 return step == null ? axisResult : step.accept(dynamicContext, axisResult);
125 }
126
127 @SuppressWarnings("null")
128 @Override
129 public String toCSTString() {
130 return String.format("%s[axis=%s]",
131 getClass().getName(),
132 getAxis().name());
133 }
134 }