1   /*
2    * SPDX-FileCopyrightText: none
3    * SPDX-License-Identifier: CC0-1.0
4    */
5   
6   package dev.metaschema.core.metapath.cst.path;
7   
8   import java.util.function.Function;
9   import java.util.stream.Stream;
10  
11  import dev.metaschema.core.metapath.StaticMetapathException;
12  import dev.metaschema.core.metapath.item.node.INodeItem;
13  import dev.metaschema.core.util.ObjectUtils;
14  import edu.umd.cs.findbugs.annotations.NonNull;
15  
16  /**
17   * An implementation of <a href="https://www.w3.org/TR/xpath-31/#axes">Metapath
18   * axes</a>.
19   */
20  public enum Axis {
21    /**
22     * The {@code self::} axis, referring to the current context node.
23     */
24    SELF(Stream::of),
25    /**
26     * The {@code parent::} axis, referring to the current context node's parent.
27     *
28     * @see INodeItem#getParentNodeItem()
29     */
30    PARENT(focus -> Stream.ofNullable(focus.getParentNodeItem())),
31    /**
32     * The {@code flag::} axis, referring to the current context node's flags.
33     *
34     * @see INodeItem#getFlags()
35     */
36    FLAG(INodeItem::flags),
37    /**
38     * The {@code ancestor::} axis, referring to the current context node's
39     * parentage.
40     *
41     * @see INodeItem#ancestor()
42     */
43    ANCESTOR(INodeItem::ancestor),
44    /**
45     * The {@code ancestor-or-self::} axis, referring to the current context node
46     * and its parentage.
47     *
48     * @see INodeItem#ancestorOrSelf()
49     */
50    ANCESTOR_OR_SELF(INodeItem::ancestorOrSelf),
51    /**
52     * The {@code children::} axis, referring to the current context node's direct
53     * children.
54     *
55     * @see INodeItem#modelItems()
56     */
57    CHILDREN(INodeItem::modelItems),
58    /**
59     * The {@code descendant::} axis, referring to all of the current context node's
60     * descendants (i.e., the children, the children of the children, etc).
61     *
62     * @see INodeItem#descendant()
63     */
64    DESCENDANT(INodeItem::descendant),
65    /**
66     * The {@code descendant-or-self::} axis, referring to the current context node
67     * and all of the current context node's descendants (i.e., the children, the
68     * children of the children, etc).
69     *
70     * @see INodeItem#descendantOrSelf()
71     */
72    DESCENDANT_OR_SELF(INodeItem::descendantOrSelf),
73    /**
74     * The {@code following-sibling::} axis, referring to those children of the
75     * context node's parent that occur after the context node in
76     * <a href="https://www.w3.org/TR/xpath-31/#dt-document-order">document
77     * order</a>.
78     */
79    FOLLOWING_SIBLING(INodeItem::followingSibling),
80    /**
81     * The {@code preceding-sibling::} axis, referring to those children of the
82     * context node's parent that occur before the context node in
83     * <a href="https://www.w3.org/TR/xpath-31/#dt-document-order">document
84     * order</a>.
85     */
86    PRECEDING_SIBLING(INodeItem::precedingSibling),
87    /**
88     * The {@code preceding-sibling::} axis, referring to all nodes that are
89     * descendants of the root of the tree in which the context node is found, are
90     * not descendants of the context node, and occur after the context node in
91     * <a href="https://www.w3.org/TR/xpath-31/#dt-document-order">document
92     * order</a>.
93     */
94    FOLLOWING(INodeItem::following),
95    /**
96     * The {@code preceding-sibling::} axis, referring to all nodes that are
97     * descendants of the root of the tree in which the context node is found, are
98     * not ancestors of the context node, and occur before the context node in
99     * <a href="https://www.w3.org/TR/xpath-31/#dt-document-order">document
100    * order</a>.
101    */
102   PRECEDING(INodeItem::preceding),
103   /**
104    * This axis is not supported.
105    */
106   NAMESPACE(focus -> {
107     throw new StaticMetapathException(
108         StaticMetapathException.AXIS_NAMESPACE_UNSUPPORTED,
109         "The 'namespace' axis is not supported");
110   });
111 
112   @NonNull
113   private final Function<INodeItem, Stream<? extends INodeItem>> action;
114 
115   Axis(@NonNull Function<INodeItem, Stream<? extends INodeItem>> action) {
116     this.action = action;
117   }
118 
119   /**
120    * Execute the axis operation on the provided {@code focus}.
121    *
122    * @param focus
123    *          the node to operate on
124    * @return the result of the axis operation
125    */
126   @NonNull
127   public Stream<? extends INodeItem> execute(@NonNull INodeItem focus) {
128     return ObjectUtils.notNull(action.apply(focus));
129   }
130 }