1   /*
2    * SPDX-FileCopyrightText: none
3    * SPDX-License-Identifier: CC0-1.0
4    */
5   
6   package dev.metaschema.core.metapath.cst.items;
7   
8   import dev.metaschema.core.metapath.DynamicContext;
9   import dev.metaschema.core.metapath.IExpression;
10  import dev.metaschema.core.metapath.cst.AbstractBinaryExpression;
11  import dev.metaschema.core.metapath.cst.IExpressionVisitor;
12  import dev.metaschema.core.metapath.item.ISequence;
13  import dev.metaschema.core.util.CustomCollectors;
14  import dev.metaschema.core.util.ObjectUtils;
15  import edu.umd.cs.findbugs.annotations.NonNull;
16  
17  /**
18   * An implementation of the
19   * <a href="https://www.w3.org/TR/xpath-31/#id-map-operator">Simple Map Operator
20   * <code>!</code></a> supporting evaluating a right expression against every
21   * item in a sequence produced by a left expression.
22   */
23  public class SimpleMap
24      extends AbstractBinaryExpression<IExpression, IExpression> {
25  
26    /**
27     * Construct a simple map expression.
28     *
29     * @param text
30     *          the parsed text of the expression
31     * @param left
32     *          the expression used to generate the right sequence
33     * @param right
34     *          the expression used to evaluate each item in the right sequence
35     */
36    public SimpleMap(
37        @NonNull String text,
38        @NonNull IExpression left,
39        @NonNull IExpression right) {
40      super(text, left, right);
41    }
42  
43    @Override
44    protected ISequence<?> evaluate(DynamicContext dynamicContext, ISequence<?> focus) {
45      ISequence<?> leftResult = getLeft().accept(dynamicContext, focus);
46  
47      IExpression right = getRight();
48      return ObjectUtils.notNull(leftResult.stream()
49          .flatMap(item -> right.accept(dynamicContext, ISequence.of(item)).stream())
50          .collect(CustomCollectors.toSequence()));
51    }
52  
53    @Override
54    public <RESULT, CONTEXT> RESULT accept(IExpressionVisitor<RESULT, CONTEXT> visitor, CONTEXT context) {
55      return visitor.visitSimpleMap(this, context);
56    }
57  }