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

net.sf.saxon.expr.LastItemExpression Maven / Gradle / Ivy

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
// Copyright (c) 2018-2023 Saxonica Limited
// This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
// If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/.
// This Source Code Form is "Incompatible With Secondary Licenses", as defined by the Mozilla Public License, v. 2.0.
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

package net.sf.saxon.expr;

import net.sf.saxon.expr.elab.ItemEvaluator;
import net.sf.saxon.expr.elab.PullEvaluator;
import net.sf.saxon.expr.elab.Elaborator;
import net.sf.saxon.expr.elab.ItemElaborator;
import net.sf.saxon.expr.parser.ExpressionTool;
import net.sf.saxon.expr.parser.RebindingMap;
import net.sf.saxon.om.Item;
import net.sf.saxon.om.SequenceIterator;
import net.sf.saxon.trans.XPathException;
import net.sf.saxon.tree.iter.ReversibleIterator;

/**
 * A LastItemExpression returns the last item in the sequence returned by a given
 * base expression. The evaluation strategy is to read the input sequence with a one-item lookahead.
 */

public final class LastItemExpression extends SingleItemFilter {

    /**
     * Constructor
     *
     * @param base A sequence expression denoting sequence whose first item is to be returned
     */

    public LastItemExpression(Expression base) {
        super(base);
    }

    /**
     * Copy an expression. This makes a deep copy.
     *
     * @return the copy of the original expression
     * @param rebindings variables that need to be re-bound
     */

    /*@NotNull*/
    @Override
    public Expression copy(RebindingMap rebindings) {
        LastItemExpression exp = new LastItemExpression(getBaseExpression().copy(rebindings));
        ExpressionTool.copyLocationInfo(this, exp);
        return exp;
    }

    /**
     * An implementation of Expression must provide at least one of the methods evaluateItem(), iterate(), or process().
     * This method indicates which of these methods is provided directly. The other methods will always be available
     * indirectly, using an implementation that relies on one of the other methods.
     *
     * @return the implementation method, for example {@link #ITERATE_METHOD} or {@link #EVALUATE_METHOD} or
     * {@link #PROCESS_METHOD}
     */
    @Override
    public int getImplementationMethod() {
        return EVALUATE_METHOD;
    }

    /**
     * Evaluate the expression
     */

    /*@Nullable*/
    @Override
    public Item evaluateItem(XPathContext context) throws XPathException {
        SequenceIterator forwards = getBaseExpression().iterate(context);
        if (forwards instanceof ReversibleIterator) {
            return ((ReversibleIterator) forwards).getReverseIterator().next();
        } else {
            Item current = null;
            while (true) {
                Item item = forwards.next();
                if (item == null) {
                    return current;
                }
                current = item;
            }
        }
    }


    @Override
    public String getExpressionName() {
        return "lastOf";
    }

    /**
     * Make an elaborator for this expression
     *
     * @return a suitable elaborator
     */

    @Override
    public Elaborator getElaborator() {
        return new LastItemExprElaborator();
    }

    /**
     * Elaborator for a "last item expression" (typically {@code SEQ[last()]})
     */

    public static class LastItemExprElaborator extends ItemElaborator {

        public ItemEvaluator elaborateForItem() {

            final LastItemExpression expr = (LastItemExpression) getExpression();
            final PullEvaluator baseEval = expr.getBaseExpression().makeElaborator().elaborateForPull();

            return context -> getLast(baseEval.iterate(context));
        }

    }

    /**
     * Get the last item delivered by an iterator, or null if the iterator is empty
     * @param iter the supplied iterator (which may or may not be consumed)
     * @return the last item returned by the iterator, or null if there are none.
     */

    public static Item getLast(SequenceIterator iter) {
        if (iter instanceof ReversibleIterator) {
            return ((ReversibleIterator) iter).getReverseIterator().next();
        } else {
            Item current = null;
            while (true) {
                Item item = iter.next();
                if (item == null) {
                    return current;
                }
                current = item;
            }
        }
    }
}





© 2015 - 2025 Weber Informatics LLC | Privacy Policy