alvinalexander.com | career | drupal | java | mac | mysql | perl | scala | uml | unix  

Commons JXPath example source code file (EvalContext.java)

This example Commons JXPath source code file (EvalContext.java) is included in the DevDaily.com "Java Source Code Warehouse" project. The intent of this project is to help you "Learn Java by Example" TM.

Java - Commons JXPath tags/keywords

arraylist, arraylist, basicnodeset, evalcontext, evalcontext, hashset, iterator, list, nodepointer, nosuchelementexception, object, object, pointer, pointer, util

The Commons JXPath EvalContext.java source code

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 org.apache.commons.jxpath.ri;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;

import org.apache.commons.jxpath.BasicNodeSet;
import org.apache.commons.jxpath.ExpressionContext;
import org.apache.commons.jxpath.JXPathContext;
import org.apache.commons.jxpath.JXPathException;
import org.apache.commons.jxpath.NodeSet;
import org.apache.commons.jxpath.Pointer;
import org.apache.commons.jxpath.ri.axes.RootContext;
import org.apache.commons.jxpath.ri.model.NodePointer;
import org.apache.commons.jxpath.util.ReverseComparator;

/**
 * An XPath evaluation context.
 *
 * When  evaluating a path, a chain of EvalContexts is created, each context in
 * the chain representing a step of the path. Subclasses of EvalContext
 * implement behavior of various XPath axes: "child::", "parent::" etc.
 *
 * @author Dmitri Plotnikov
 * @version $Revision: 652845 $ $Date: 2008-05-02 12:46:46 -0500 (Fri, 02 May 2008) $
 */
public abstract class EvalContext implements ExpressionContext, Iterator {
    /** parent context */
    protected EvalContext parentContext;

    /** root context */
    protected RootContext rootContext;

    /** position */
    protected int position = 0;

    private boolean startedSetIteration = false;
    private boolean done = false;
    private boolean hasPerformedIteratorStep = false;
    private Iterator pointerIterator;

    /**
     * Create a new EvalContext.
     * @param parentContext parent context
     */
    public EvalContext(EvalContext parentContext) {
        this.parentContext = parentContext;
    }

    public Pointer getContextNodePointer() {
        return getCurrentNodePointer();
    }

    public JXPathContext getJXPathContext() {
        return getRootContext().getJXPathContext();
    }

    public int getPosition() {
        return position;
    }

    /**
     * Determines the document order for this context.
     *
     * @return 1 ascending order, -1 descending order,
     *  0 - does not require ordering
     */
    public int getDocumentOrder() {
        return parentContext != null && parentContext.isChildOrderingRequired() ? 1 : 0;
    }

    /**
     * Even if this context has the natural ordering and therefore does
     * not require collecting and sorting all nodes prior to returning them,
     * such operation may be required for any child context.
     * @return boolean
     */
    public boolean isChildOrderingRequired() {
        // Default behavior: if this context needs to be ordered,
        // the children need to be ordered too
        return getDocumentOrder() != 0;
    }

    /**
     * Returns true if there are mode nodes matching the context's constraints.
     * @return boolean
     */
    public boolean hasNext() {
        if (pointerIterator != null) {
            return pointerIterator.hasNext();
        }
        if (getDocumentOrder() != 0) {
            return constructIterator();
        }
        if (!done && !hasPerformedIteratorStep) {
            performIteratorStep();
        }
        return !done;
    }

    /**
     * Returns the next node pointer in the context
     * @return Object
     */
    public Object next() {
        if (pointerIterator != null) {
            return pointerIterator.next();
        }

        if (getDocumentOrder() != 0) {
            if (!constructIterator()) {
                throw new NoSuchElementException();
            }
            return pointerIterator.next();
        }
        if (!done && !hasPerformedIteratorStep) {
            performIteratorStep();
        }
        if (done) {
            throw new NoSuchElementException();
        }
        hasPerformedIteratorStep = false;
        return getCurrentNodePointer();
    }

    /**
     * Moves the iterator forward by one position
     */
    private void performIteratorStep() {
        done = true;
        if (position != 0 && nextNode()) {
            done = false;
        }
        else {
            while (nextSet()) {
                if (nextNode()) {
                    done = false;
                    break;
                }
            }
        }
        hasPerformedIteratorStep = true;
    }

    /**
     * Operation is not supported
     * @throws UnsupportedOperationException
     */
    public void remove() {
        throw new UnsupportedOperationException(
            "JXPath iterators cannot remove nodes");
    }

    /**
     * Construct an iterator.
     * @return whether the Iterator was constructed
     */
    private boolean constructIterator() {
        HashSet set = new HashSet();
        ArrayList list = new ArrayList();
        while (nextSet()) {
            while (nextNode()) {
                NodePointer pointer = getCurrentNodePointer();
                if (!set.contains(pointer)) {
                    set.add(pointer);
                    list.add(pointer);
                }
            }
        }
        if (list.isEmpty()) {
            return false;
        }

        sortPointers(list);

        pointerIterator = list.iterator();
        return true;
    }

    /**
     * Sort a list of pointers based on document order.
     * @param l the list to sort.
     */
    protected void sortPointers(List l) {
        switch (getDocumentOrder()) {
        case 1:
            Collections.sort(l);
            break;
        case -1:
            Collections.sort(l, ReverseComparator.INSTANCE);
            break;
        default:
        }
    }

    /**
     * Returns the list of all Pointers in this context for the current
     * position of the parent context.
     * @return List
     */
    public List getContextNodeList() {
        int pos = position;
        if (pos != 0) {
            reset();
        }
        List list = new ArrayList();
        while (nextNode()) {
            list.add(getCurrentNodePointer());
        }
        if (pos != 0) {
            setPosition(pos);
        }
        else {
            reset();
        }
        return list;
    }

    /**
     * Returns the list of all Pointers in this context for all positions
     * of the parent contexts.  If there was an ongoing iteration over
     * this context, the method should not be called.
     * @return NodeSet
     */
    public NodeSet getNodeSet() {
        if (position != 0) {
            throw new JXPathException(
                "Simultaneous operations: "
                    + "should not request pointer list while "
                    + "iterating over an EvalContext");
        }
        BasicNodeSet set = new BasicNodeSet();
        while (nextSet()) {
            while (nextNode()) {
                set.add((Pointer) getCurrentNodePointer().clone());
            }
        }

        return set;
    }

    /**
     * Typically returns the NodeSet by calling getNodeSet(),
     * but will be overridden for contexts that more naturally produce
     * individual values, e.g. VariableContext
     * @return Object
     */
    public Object getValue() {
        return getNodeSet();
    }

    public String toString() {
        Pointer ptr = getContextNodePointer();
        return ptr == null ? "Empty expression context" : "Expression context [" + getPosition()
                + "] " + ptr.asPath();
    }

    /**
     * Returns the root context of the path, which provides easy
     * access to variables and functions.
     * @return RootContext
     */
    public RootContext getRootContext() {
        if (rootContext == null) {
            rootContext = parentContext.getRootContext();
        }
        return rootContext;
    }

    /**
     * Sets current position = 0, which is the pre-iteration state.
     */
    public void reset() {
        position = 0;
    }

    /**
     * Get the current position.
     * @return int position.
     */
    public int getCurrentPosition() {
        return position;
    }

    /**
     * Returns the first encountered Pointer that matches the current
     * context's criteria.
     * @return Pointer
     */
    public Pointer getSingleNodePointer() {
        reset();
        while (nextSet()) {
            if (nextNode()) {
                return getCurrentNodePointer();
            }
        }
        return null;
    }

    /**
     * Returns the current context node. Undefined before the beginning
     * of the iteration.
     * @return NodePoiner
     */
    public abstract NodePointer getCurrentNodePointer();

    /**
     * Returns true if there is another sets of objects to interate over.
     * Resets the current position and node.
     * @return boolean
     */
    public boolean nextSet() {
        reset(); // Restart iteration within the set

        // Most of the time you have one set per parent node
        // First time this method is called, we should look for
        // the first parent set that contains at least one node.
        if (!startedSetIteration) {
            startedSetIteration = true;
            while (parentContext.nextSet()) {
                if (parentContext.nextNode()) {
                    return true;
                }
            }
            return false;
        }

        // In subsequent calls, we see if the parent context
        // has any nodes left in the current set
        if (parentContext.nextNode()) {
            return true;
        }

        // If not, we look for the next set that contains
        // at least one node
        while (parentContext.nextSet()) {
            if (parentContext.nextNode()) {
                return true;
            }
        }
        return false;
    }

    /**
     * Returns true if there is another object in the current set.
     * Switches the current position and node to the next object.
     * @return boolean
     */
    public abstract boolean nextNode();

    /**
     * Moves the current position to the specified index. Used with integer
     * predicates to quickly get to the n'th element of the node set.
     * Returns false if the position is out of the node set range.
     * You can call it with 0 as the position argument to restart the iteration.
     * @param position to set
     * @return boolean
     */
    public boolean setPosition(int position) {
        this.position = position;
        return true;
    }
}

Other Commons JXPath examples (source code examples)

Here is a short list of links related to this Commons JXPath EvalContext.java source code file:

... this post is sponsored by my books ...

#1 New Release!

FP Best Seller

 

new blog posts

 

Copyright 1998-2021 Alvin Alexander, alvinalexander.com
All Rights Reserved.

A percentage of advertising revenue from
pages under the /java/jwarehouse URI on this website is
paid back to open source projects.