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
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.Node;
import com.github.simy4.xpath.util.FilteringIterator;
import com.github.simy4.xpath.util.Function;
import com.github.simy4.xpath.util.Predicate;
import com.github.simy4.xpath.util.TransformingIterator;
import com.github.simy4.xpath.view.IterableNodeView;
import com.github.simy4.xpath.view.NodeSetView;
import com.github.simy4.xpath.view.NodeView;
import com.github.simy4.xpath.view.View;
import com.github.simy4.xpath.view.ViewContext;

import java.util.Iterator;

public class AxisStepExpr implements StepExpr {

    private final AxisResolver axisResolver;
    private final Iterable predicates;

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

    @Override
    public final  IterableNodeView resolve(ViewContext context) throws XmlBuilderException {
        IterableNodeView result = axisResolver.resolveAxis(context);
        for (Expr predicate : predicates) {
            result = resolvePredicate(context, result, predicate);
        }
        return result;
    }

    private  IterableNodeView resolvePredicate(final ViewContext context,
                                                                  final IterableNodeView filtered,
                                                                  final Expr predicate) throws XmlBuilderException {
        final PredicateContext predicateContext = new PredicateContext();
        IterableNodeView result = new NodeSetView(new Iterable>() {
            @Override
            public Iterator> iterator() {
                final Iterator> iterator = filtered.iterator();
                return new FilteringIterator>(
                        new TransformingIterator, NodeView>(iterator, predicateContext),
                        new PredicateResolver(context, iterator, predicate));
            }
        });
        if (context.isGreedy() && !context.hasNext() && !result.toBoolean()) {
            final NodeView last = predicateContext.last;
            final int position = predicateContext.position;
            final NodeView newNode;
            final ViewContext newContext;
            if (null != last && last.isNew()) {
                newNode = last;
                newContext = new ViewContext(context.getNavigator(), last, true, false, position);
            } else {
                newNode = axisResolver.createAxisNode(context);
                newContext = new ViewContext(context.getNavigator(), newNode, true, false, position + 1);
            }
            final View resolve = predicate.resolve(newContext);
            if (!resolve.toBoolean()) {
                throw new XmlBuilderException("Unable to satisfy expression predicate: " + predicate);
            }
            result = newNode;
        }
        return result;
    }

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

    private static final class PredicateResolver implements Predicate> {

        private final ViewContext parentContext;
        private final Iterator> iterator;
        private final Expr predicate;
        private int position = 1;

        private PredicateResolver(ViewContext parentContext, Iterator> iterator, Expr predicate) {
            this.parentContext = parentContext;
            this.iterator = iterator;
            this.predicate = predicate;
        }

        @Override
        public boolean test(NodeView view) {
            final ViewContext context = new ViewContext(parentContext.getNavigator(), view, false,
                    iterator.hasNext(), position++);
            return predicate.resolve(context).toBoolean();
        }

    }

    private static final class PredicateContext implements Function, NodeView> {

        private NodeView last;
        private int position;

        @Override
        public NodeView apply(NodeView view) {
            if (null == last || !last.isNew()) {
                last = view;
                position++;
            }
            return view;
        }

    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy