All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.simy4.xpath.expr.AxisStepExpr Maven / Gradle / Ivy

There is a newer version: 2.3.9
Show newest version
/*
 * Copyright 2017-2021 Alex Simkin
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.github.simy4.xpath.expr;

import com.github.simy4.xpath.XmlBuilderException;
import com.github.simy4.xpath.expr.axis.AxisResolver;
import com.github.simy4.xpath.navigator.Navigator;
import com.github.simy4.xpath.navigator.Node;
import com.github.simy4.xpath.util.Function;
import com.github.simy4.xpath.view.IterableNodeView;
import com.github.simy4.xpath.view.NodeSetView;
import com.github.simy4.xpath.view.NodeView;

import java.io.Serializable;
import java.util.Collection;

public class AxisStepExpr implements StepExpr, Serializable {

  private static final long serialVersionUID = 1L;

  private final AxisResolver axisResolver;
  private final Collection predicates;

  public AxisStepExpr(AxisResolver axisResolver, Collection predicates) {
    this.axisResolver = axisResolver;
    this.predicates = predicates;
  }

  @Override
  public final  IterableNodeView resolve(
      Navigator navigator, NodeView view, boolean greedy) throws XmlBuilderException {
    final boolean newGreedy = !view.hasNext() && greedy;
    final IterableNodeView result = axisResolver.resolveAxis(navigator, view, newGreedy);
    return resolvePredicates(navigator, view, result, newGreedy);
  }

  private  IterableNodeView resolvePredicates(
      Navigator navigator, NodeView view, IterableNodeView axis, boolean greedy)
      throws XmlBuilderException {
    IterableNodeView result = axis;
    if (!predicates.isEmpty()) {
      NodeSupplier nodeSupplier = new AxisNodeSupplier(navigator, axisResolver, view);
      for (Expr predicate : predicates) {
        final PredicateExpr predicateExpr = new PredicateExpr(predicate);
        final PredicateResolver predicateResolver =
            new PredicateResolver(navigator, nodeSupplier, predicateExpr, greedy);
        result = result.flatMap(predicateResolver);
        nodeSupplier = predicateResolver;
      }
    }
    return result;
  }

  @Override
  public String toString() {
    final StringBuilder stringBuilder = new StringBuilder(axisResolver.toString());
    for (Expr predicate : predicates) {
      stringBuilder.append(predicate);
    }
    return stringBuilder.toString();
  }

  private interface NodeSupplier {

    NodeView apply(int position) throws XmlBuilderException;
  }

  private static final class AxisNodeSupplier implements NodeSupplier {

    private final Navigator navigator;
    private final AxisResolver axisResolver;
    private final NodeView parent;

    private AxisNodeSupplier(
        Navigator navigator, AxisResolver axisResolver, NodeView parent) {
      this.navigator = navigator;
      this.axisResolver = axisResolver;
      this.parent = parent;
    }

    @Override
    public NodeView apply(int position) throws XmlBuilderException {
      return axisResolver.createAxisNode(navigator, parent, position);
    }
  }

  private static final class PredicateResolver
      implements NodeSupplier, Function, IterableNodeView> {

    private final Navigator navigator;
    private final NodeSupplier parentNodeSupplier;
    private final Expr predicate;
    private final boolean greedy;
    private boolean resolved;

    private PredicateResolver(
        Navigator navigator,
        NodeSupplier parentNodeSupplier,
        Expr predicate,
        boolean greedy) {
      this.navigator = navigator;
      this.parentNodeSupplier = parentNodeSupplier;
      this.predicate = predicate;
      this.greedy = greedy;
    }

    @Override
    public NodeView apply(int position) throws XmlBuilderException {
      final NodeView newNode = parentNodeSupplier.apply(position);
      if (!predicate.resolve(navigator, newNode, true).toBoolean()) {
        throw new XmlBuilderException("Unable to satisfy expression predicate: " + predicate);
      }
      return newNode;
    }

    @Override
    public IterableNodeView apply(NodeView view) {
      final IterableNodeView result;
      final boolean check = predicate.resolve(navigator, view, false).toBoolean();
      if (check) {
        result = view;
      } else if ((view.isNew() || view.isMarked()) && greedy) {
        if (!predicate.resolve(navigator, view, true).toBoolean()) {
          throw new XmlBuilderException("Unable to satisfy expression predicate: " + predicate);
        }
        result = view;
      } else if (!view.hasNext() && !resolved && greedy) {
        result = apply(view.getPosition() + 1);
      } else {
        result = NodeSetView.empty();
      }
      resolved |= check;
      return result;
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy