org.apache.cocoon.components.expression.jxpath.JXPathExpression.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.cocoon.components.expression.jxpath.JXPathExpression.java

Source

/*
 * Copyright 1999-2005 The Apache Software Foundation.
 * 
 * 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 org.apache.cocoon.components.expression.jxpath;

import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;

import org.apache.cocoon.components.expression.Expression;
import org.apache.cocoon.components.expression.ExpressionContext;
import org.apache.cocoon.components.expression.ExpressionException;
import org.apache.cocoon.components.expression.jexl.JSIntrospector;
import org.apache.cocoon.util.jxpath.NamespacesTablePointer;
import org.apache.commons.jxpath.CompiledExpression;
import org.apache.commons.jxpath.JXPathContext;
import org.apache.commons.jxpath.Pointer;
import org.apache.commons.jxpath.Variables;
import org.mozilla.javascript.NativeArray;
import org.w3c.dom.Node;

/**
 * @version SVN $Id: JXPathExpression.java 325986 2005-10-17 21:35:18Z lgawron $
 */
public class JXPathExpression implements Expression {
    private final String language;
    private final String expression;
    private final CompiledExpression compiledExpression;
    private boolean lenient = false;

    public static final String LENIENT = "lenient";

    public JXPathExpression(String language, String expression) throws ExpressionException {
        this.language = language;
        this.expression = expression;
        this.compiledExpression = JXPathContext.compile(expression);
    }

    public Object evaluate(ExpressionContext context) throws ExpressionException {
        return this.compiledExpression.getValue(getContext(context));
    }

    public Iterator iterate(ExpressionContext context) throws ExpressionException {
        final JXPathContext jxpathContext = getContext(context);
        Object val = this.compiledExpression.getPointer(jxpathContext, this.expression).getNode();
        // FIXME: workaround for JXPath bug
        if (val instanceof NativeArray)
            return new JSIntrospector.NativeArrayIterator((NativeArray) val);
        else
            return new Iterator() {
                Iterator iter = compiledExpression.iteratePointers(jxpathContext);

                public boolean hasNext() {
                    return iter.hasNext();
                }

                public Object next() {
                    return ((Pointer) iter.next()).getNode();
                }

                public void remove() {
                    iter.remove();
                }
            };
    }

    public void assign(ExpressionContext context, Object value) throws ExpressionException {
        this.compiledExpression.setValue(getContext(context), value);
    }

    public String getExpression() {
        return this.expression;
    }

    public String getLanguage() {
        return this.language;
    }

    public void setProperty(String property, Object value) {
        if (LENIENT.equals(property))
            this.lenient = ((Boolean) value).booleanValue();
    }

    // Hack: try to prevent JXPath from converting result to a String
    public Object getNode(ExpressionContext context) throws ExpressionException {
        Iterator iter = this.compiledExpression.iteratePointers(getContext(context));
        if (iter.hasNext()) {
            Pointer first = (Pointer) iter.next();
            if (iter.hasNext()) {
                List result = new LinkedList();
                result.add(first.getNode());
                boolean dom = (first.getNode() instanceof Node);
                while (iter.hasNext()) {
                    Object obj = ((Pointer) iter.next()).getNode();
                    dom = dom && (obj instanceof Node);
                    result.add(obj);
                }
                Object[] arr;
                if (dom) {
                    arr = new Node[result.size()];
                } else {
                    arr = new Object[result.size()];
                }
                result.toArray(arr);
                return arr;
            }
            return first.getNode();
        }
        return null;
    }

    private JXPathContext getContext(ExpressionContext context) {
        // This could be made more efficient by caching the
        // JXPathContext within the Context object.
        JXPathContext jxcontext = JXPathContext.newContext(context.getContextBean());
        jxcontext.setVariables(new VariableAdapter(context));
        jxcontext.setLenient(this.lenient);
        jxcontext.setNamespaceContextPointer(new NamespacesTablePointer(context.getNamespaces()));
        return jxcontext;
    }

    private static class VariableAdapter implements Variables {
        private ExpressionContext context;

        public VariableAdapter(ExpressionContext context) {
            this.context = context;
        }

        public void declareVariable(String name, Object value) {
            this.context.put(name, value);
        }

        public Object getVariable(String name) {
            return this.context.get(name);
        }

        public boolean isDeclaredVariable(String name) {
            return this.context.containsKey(name);
        }

        public void undeclareVariable(String name) {
            throw new UnsupportedOperationException("Operation undeclareVariable is not supported");
        }
    }
}