Package org.apache.commons.jxpath.ri.compiler

Source Code of org.apache.commons.jxpath.ri.compiler.CoreFunction

/*
* $Header: /home/cvspublic/jakarta-commons/jxpath/src/java/org/apache/commons/jxpath/ri/compiler/CoreFunction.java,v 1.5 2002/06/08 22:47:25 dmitri Exp $
* $Revision: 1.5 $
* $Date: 2002/06/08 22:47:25 $
*
* ====================================================================
* The Apache Software License, Version 1.1
*
*
* Copyright (c) 1999-2001 The Apache Software Foundation.  All rights
* reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
*    notice, this list of conditions and the following disclaimer.
*
* 2. Redistributions in binary form must reproduce the above copyright
*    notice, this list of conditions and the following disclaimer in
*    the documentation and/or other materials provided with the
*    distribution.
*
* 3. The end-user documentation included with the redistribution, if
*    any, must include the following acknowlegement:
*       "This product includes software developed by the
*        Apache Software Foundation (http://www.apache.org/)."
*    Alternately, this acknowlegement may appear in the software itself,
*    if and wherever such third-party acknowlegements normally appear.
*
* 4. The names "The Jakarta Project", "Commons", and "Apache Software
*    Foundation" must not be used to endorse or promote products derived
*    from this software without prior written permission. For written
*    permission, please contact apache@apache.org.
*
* 5. Products derived from this software may not be called "Apache"
*    nor may "Apache" appear in their names without prior written
*    permission of the Apache Group.
*
* THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED.  IN NO EVENT SHALL THE APACHE SOFTWARE FOUNDATION OR
* ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
* USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
* ====================================================================
*
* This software consists of voluntary contributions made by many
* individuals on behalf of the Apache Software Foundation and was
* originally based on software copyright (c) 2001, Plotnix, Inc,
* <http://www.plotnix.com/>.
* For more information on the Apache Software Foundation, please see
* <http://www.apache.org/>.
*/
package org.apache.commons.jxpath.ri.compiler;

import org.apache.commons.jxpath.JXPathContext;
import org.apache.commons.jxpath.JXPathException;
import org.apache.commons.jxpath.ri.Compiler;
import org.apache.commons.jxpath.ri.InfoSetUtil;
import org.apache.commons.jxpath.ri.EvalContext;
import org.apache.commons.jxpath.ri.model.NodePointer;
import org.apache.commons.jxpath.ri.model.beans.NullPointer;

import java.util.Collection;

/**
* An element of the compile tree representing one of built-in functions
* like "position()" or "number()".
*
* @author Dmitri Plotnikov
* @version $Revision: 1.5 $ $Date: 2002/06/08 22:47:25 $
*/
public class CoreFunction extends Operation {

    private static final Double ZERO = new Double(0);
    private int functionCode;

    public CoreFunction(int functionCode, Expression args[]){
        super(Expression.OP_CORE_FUNCTION, args);
        this.functionCode = functionCode;
    }

    public int getFunctionCode(){
        return functionCode;
    }

    public Expression getArg1(){
        return args[0];
    }

    public Expression getArg2(){
        return args[1];
    }

    public Expression getArg3(){
        return args[2];
    }

    public int getArgumentCount(){
        if (args == null){
            return 0;
        }
        return args.length;
    }

    /**
     * Returns true if any argument is context dependent or if
     * the function is last(), position(), boolean(), local-name(),
     * name(), string(), lang(), number().
     */
    public boolean computeContextDependent(){
        if (super.computeContextDependent()){
            return true;
        }

        switch(functionCode){
            case Compiler.FUNCTION_LAST:
            case Compiler.FUNCTION_POSITION:
                return true;

            case Compiler.FUNCTION_BOOLEAN:
            case Compiler.FUNCTION_LOCAL_NAME:
            case Compiler.FUNCTION_NAME:
            case Compiler.FUNCTION_NAMESPACE_URI:
            case Compiler.FUNCTION_STRING:
            case Compiler.FUNCTION_LANG:
            case Compiler.FUNCTION_NUMBER:
                return args == null || args.length == 0;

            case Compiler.FUNCTION_COUNT:
            case Compiler.FUNCTION_ID:
            case Compiler.FUNCTION_CONCAT:
            case Compiler.FUNCTION_STARTS_WITH:
            case Compiler.FUNCTION_CONTAINS:
            case Compiler.FUNCTION_SUBSTRING_BEFORE:
            case Compiler.FUNCTION_SUBSTRING_AFTER:
            case Compiler.FUNCTION_SUBSTRING:
            case Compiler.FUNCTION_STRING_LENGTH:
            case Compiler.FUNCTION_NORMALIZE_SPACE:
            case Compiler.FUNCTION_TRANSLATE:
            case Compiler.FUNCTION_NOT:
            case Compiler.FUNCTION_TRUE:
            case Compiler.FUNCTION_FALSE:
            case Compiler.FUNCTION_SUM:
            case Compiler.FUNCTION_FLOOR:
            case Compiler.FUNCTION_CEILING:
            case Compiler.FUNCTION_ROUND:
                return false;
        }

        return false;
    }

    protected String opCodeToString(){
        String function = null;
        switch(functionCode){
            case Compiler.FUNCTION_LAST:             function = "last"; break;
            case Compiler.FUNCTION_POSITION:         function = "position"; break;
            case Compiler.FUNCTION_COUNT:            function = "count"; break;
            case Compiler.FUNCTION_ID:               function = "id"; break;
            case Compiler.FUNCTION_LOCAL_NAME:       function = "local-name"; break;
            case Compiler.FUNCTION_NAMESPACE_URI:    function = "namespace-uri"; break;
            case Compiler.FUNCTION_NAME:             function = "name"; break;
            case Compiler.FUNCTION_STRING:           function = "string"; break;
            case Compiler.FUNCTION_CONCAT:           function = "concat"; break;
            case Compiler.FUNCTION_STARTS_WITH:      function = "starts-with"; break;
            case Compiler.FUNCTION_CONTAINS:         function = "contains"; break;
            case Compiler.FUNCTION_SUBSTRING_BEFORE: function = "substring-before"; break;
            case Compiler.FUNCTION_SUBSTRING_AFTER:  function = "substring-after"; break;
            case Compiler.FUNCTION_SUBSTRING:        function = "substring"; break;
            case Compiler.FUNCTION_STRING_LENGTH:    function = "string-length"; break;
            case Compiler.FUNCTION_NORMALIZE_SPACE:  function = "normalize-space"; break;
            case Compiler.FUNCTION_TRANSLATE:        function = "translate"; break;
            case Compiler.FUNCTION_BOOLEAN:          function = "boolean"; break;
            case Compiler.FUNCTION_NOT:              function = "not"; break;
            case Compiler.FUNCTION_TRUE:             function = "true"; break;
            case Compiler.FUNCTION_FALSE:            function = "false"; break;
            case Compiler.FUNCTION_LANG:             function = "lang"; break;
            case Compiler.FUNCTION_NUMBER:           function = "number"; break;
            case Compiler.FUNCTION_SUM:              function = "sum"; break;
            case Compiler.FUNCTION_FLOOR:            function = "floor"; break;
            case Compiler.FUNCTION_CEILING:          function = "ceiling"; break;
            case Compiler.FUNCTION_ROUND:            function = "round"; break;
            case Compiler.FUNCTION_KEY:              function = "key"; break;
        }
        return super.opCodeToString() + ':' + function;
    }

    public Object compute(EvalContext context){
        return computeValue(context);
    }

    /**
     * Computes a built-in function
     */
    public Object computeValue(EvalContext context){
        switch(functionCode){
            case Compiler.FUNCTION_LAST:                return functionLast(context);
            case Compiler.FUNCTION_POSITION:            return functionPosition(context);
            case Compiler.FUNCTION_COUNT:               return functionCount(context);
            case Compiler.FUNCTION_LANG:                return functionLang(context);
            case Compiler.FUNCTION_ID:                  return functionID(context);
            case Compiler.FUNCTION_LOCAL_NAME:          return functionLocalName(context);
            case Compiler.FUNCTION_NAMESPACE_URI:       return functionNamespaceURI(context);
            case Compiler.FUNCTION_NAME:                return functionName(context);
            case Compiler.FUNCTION_STRING:              return functionString(context);
            case Compiler.FUNCTION_CONCAT:              return functionConcat(context);
            case Compiler.FUNCTION_STARTS_WITH:         return functionStartsWith(context);
            case Compiler.FUNCTION_CONTAINS:            return functionContains(context);
            case Compiler.FUNCTION_SUBSTRING_BEFORE:    return functionSubstringBefore(context);
            case Compiler.FUNCTION_SUBSTRING_AFTER:     return functionSubstringAfter(context);
            case Compiler.FUNCTION_SUBSTRING:           return functionSubstring(context);
            case Compiler.FUNCTION_STRING_LENGTH:       return functionStringLength(context);
            case Compiler.FUNCTION_NORMALIZE_SPACE:     return functionNormalizeSpace(context);
            case Compiler.FUNCTION_TRANSLATE:           return functionTranslate(context);
            case Compiler.FUNCTION_BOOLEAN:             return functionBoolean(context);
            case Compiler.FUNCTION_NOT:                 return functionNot(context);
            case Compiler.FUNCTION_TRUE:                return functionTrue(context);
            case Compiler.FUNCTION_FALSE:               return functionFalse(context);
            case Compiler.FUNCTION_NULL:                return functionNull(context);
            case Compiler.FUNCTION_NUMBER:              return functionNumber(context);
            case Compiler.FUNCTION_SUM:                 return functionSum(context);
            case Compiler.FUNCTION_FLOOR:               return functionFloor(context);
            case Compiler.FUNCTION_CEILING:             return functionCeiling(context);
            case Compiler.FUNCTION_ROUND:               return functionRound(context);
            case Compiler.FUNCTION_KEY:                 return functionKey(context);
        }
        return null;
    }

    protected Object functionLast(EvalContext context){
        assertArgCount(0);
        // Move the position to the beginning and iterate through
        // the context to count nodes.
        int old = context.getCurrentPosition();
        context.reset();
        int count = 0;
        while(context.nextNode()){
            count++;
        }

        // Restore the current position.
        if (old != 0){
            context.setPosition(old);
        }
        return new Double(count);
    }

    protected Object functionPosition(EvalContext context){
        assertArgCount(0);
        return new Integer(context.getCurrentPosition());
    }

    protected Object functionCount(EvalContext context){
        assertArgCount(1);
        Expression arg1 = getArg1();
        int count = 0;
        Object value = arg1.compute(context);
        if (value instanceof NodePointer){
            value = ((NodePointer)value).getValue();
        }
        if (value instanceof EvalContext){
            EvalContext ctx = (EvalContext)value;
            while(ctx.hasNext()){
                ctx.next();
                count++;
            }
        }
        else if (value instanceof Collection){
            count = ((Collection)value).size();
        }
        else if (value == null){
            count = 0;
        }
        else {
            count = 1;
        }
        return new Double(count);
    }

    protected Object functionLang(EvalContext context){
        assertArgCount(1);
        String lang = InfoSetUtil.stringValue(getArg1().computeValue(context));
        NodePointer pointer = (NodePointer)context.getSingleNodePointer();
        if (pointer == null){
            return Boolean.FALSE;
        }
        return pointer.isLanguage(lang) ? Boolean.TRUE: Boolean.FALSE;
    }

    protected Object functionID(EvalContext context){
        assertArgCount(1);
        String id = InfoSetUtil.stringValue(getArg1().computeValue(context));
        JXPathContext jxpathContext = context.getJXPathContext();
        NodePointer pointer = (NodePointer)jxpathContext.getContextPointer();
        return pointer.getPointerByID(jxpathContext, id);
    }

    protected Object functionKey(EvalContext context){
        assertArgCount(2);
        String key = InfoSetUtil.stringValue(getArg1().computeValue(context));
        String value = InfoSetUtil.stringValue(getArg2().computeValue(context));
        JXPathContext jxpathContext = context.getJXPathContext();
        NodePointer pointer = (NodePointer)jxpathContext.getContextPointer();
        return pointer.getPointerByKey(jxpathContext, key, value);
    }

    protected Object functionNamespaceURI(EvalContext context){
        if (getArgumentCount() == 0){
            return context.getCurrentNodePointer();
        }
        assertArgCount(1);
        Object set = getArg1().compute(context);
        if (set instanceof EvalContext){
            EvalContext ctx = (EvalContext)set;
            if (ctx.hasNext()){
                ctx.next();
                String str = ctx.getCurrentNodePointer().getNamespaceURI();
                return str == null ? "" : str;
            }
        }
        return "";
    }

    protected Object functionLocalName(EvalContext context){
        if (getArgumentCount() == 0){
            return context.getCurrentNodePointer();
        }
        assertArgCount(1);
        Object set = getArg1().compute(context);
        if (set instanceof EvalContext){
            EvalContext ctx = (EvalContext)set;
            if (ctx.hasNext()){
                ctx.next();
                return ctx.getCurrentNodePointer().getName().getName();
            }
        }
        return "";
    }

    protected Object functionName(EvalContext context){
        if (getArgumentCount() == 0){
            return context.getCurrentNodePointer();
        }
        assertArgCount(1);
        Object set = getArg1().compute(context);
        if (set instanceof EvalContext){
            EvalContext ctx = (EvalContext)set;
            if (ctx.hasNext()){
                ctx.next();
                return ctx.getCurrentNodePointer().getExpandedName().toString();
            }
        }
        return "";
    }

    protected Object functionString(EvalContext context){
        if (getArgumentCount() == 0){
            return InfoSetUtil.stringValue(context.getCurrentNodePointer());
        }
        assertArgCount(1);
        return InfoSetUtil.stringValue(getArg1().computeValue(context));
    }

    protected Object functionConcat(EvalContext context){
        if (getArgumentCount() < 2){
            assertArgCount(2);
        }
        StringBuffer buffer = new StringBuffer();
        Expression args[] = getArguments();
        for (int i = 0; i < args.length; i++){
            buffer.append(InfoSetUtil.stringValue(args[i].compute(context)));
        }
        return buffer.toString();
    }

    protected Object functionStartsWith(EvalContext context){
        assertArgCount(2);
        String s1 = InfoSetUtil.stringValue(getArg1().computeValue(context));
        String s2 = InfoSetUtil.stringValue(getArg2().computeValue(context));
        return s1.startsWith(s2) ? Boolean.TRUE : Boolean.FALSE;
    }

    protected Object functionContains(EvalContext context){
        assertArgCount(2);
        String s1 = InfoSetUtil.stringValue(getArg1().computeValue(context));
        String s2 = InfoSetUtil.stringValue(getArg2().computeValue(context));
        return s1.indexOf(s2) != -1 ? Boolean.TRUE : Boolean.FALSE;
    }

    protected Object functionSubstringBefore(EvalContext context){
        assertArgCount(2);
        String s1 = InfoSetUtil.stringValue(getArg1().computeValue(context));
        String s2 = InfoSetUtil.stringValue(getArg2().computeValue(context));
        int index = s1.indexOf(s2);
        if (index == -1){
            return "";
        }
        return s1.substring(0, index);
    }

    protected Object functionSubstringAfter(EvalContext context){
        assertArgCount(2);
        String s1 = InfoSetUtil.stringValue(getArg1().computeValue(context));
        String s2 = InfoSetUtil.stringValue(getArg2().computeValue(context));
        int index = s1.indexOf(s2);
        if (index == -1){
            return "";
        }
        return s1.substring(index + s2.length());
    }

    protected Object functionSubstring(EvalContext context){
        int ac = getArgumentCount();
        if (ac != 2 && ac != 3){
            assertArgCount(2);
        }

        String s1 = InfoSetUtil.stringValue(getArg1().computeValue(context));
        double from = InfoSetUtil.doubleValue(getArg2().computeValue(context));
        if (Double.isNaN(from)){
            return "";
        }

        from = Math.round(from);
        if (ac == 2){
            if (from < 1){
                from = 1;
            }
            return s1.substring((int)from - 1);
        }
        else {
            double length = InfoSetUtil.doubleValue(getArg3().computeValue(context));
            length = Math.round(length);
            if (length < 0){
                return "";
            }

            double to = from + length;
            if (to < 1){
                return "";
            }

            if (to > s1.length() + 1){
                if (from < 1){
                    from = 1;
                }
                return s1.substring((int)from - 1);
            }

            if (from < 1){
                from = 1;
            }
            return s1.substring((int)from - 1, (int)(to - 1));
        }
    }

    protected Object functionStringLength(EvalContext context){
        String s;
        if (getArgumentCount() == 0){
            s = InfoSetUtil.stringValue(context.getCurrentNodePointer());
        }
        else {
            assertArgCount(1);
            s = InfoSetUtil.stringValue(getArg1().computeValue(context));
        }
        return new Double(s.length());
    }

    protected Object functionNormalizeSpace(EvalContext context){
        assertArgCount(1);
        String s = InfoSetUtil.stringValue(getArg1().computeValue(context));
        char chars[] = s.toCharArray();
        int out = 0;
        int phase = 0;
        for (int in = 0; in < chars.length; in++){
            switch(chars[in]){
                case 0x20:
                case 0x9:
                case 0xD:
                case 0xA:
                    if (phase == 0){      // beginning
                        ;
                    }
                    else if (phase == 1){ // non-space
                        phase = 2;
                        chars[out++] = ' ';
                    }
                    break;
                default:
                    chars[out++] = chars[in];
                    phase = 1;
            }
        }
        if (phase == 2){ // trailing-space
            out--;
        }
        return new String(chars, 0, out);
    }

    protected Object functionTranslate(EvalContext context){
        assertArgCount(3);
        String s1 = InfoSetUtil.stringValue(getArg1().computeValue(context));
        String s2 = InfoSetUtil.stringValue(getArg2().computeValue(context));
        String s3 = InfoSetUtil.stringValue(getArg3().computeValue(context));
        char chars[] = s1.toCharArray();
        int out = 0;
        for (int in = 0; in < chars.length; in++){
            char c = chars[in];
            int inx = s2.indexOf(c);
            if (inx != -1){
                if (inx < s3.length()){
                    chars[out++] = s3.charAt(inx);
                }
            }
            else {
                chars[out++] = c;
            }
        }
        return new String(chars, 0, out);
    }

    protected Object functionBoolean(EvalContext context){
        assertArgCount(1);
        return InfoSetUtil.booleanValue(getArg1().computeValue(context)) ? Boolean.TRUE : Boolean.FALSE;
    }

    protected Object functionNot(EvalContext context){
        assertArgCount(1);
        return InfoSetUtil.booleanValue(getArg1().computeValue(context)) ? Boolean.FALSE : Boolean.TRUE;
    }

    protected Object functionTrue(EvalContext context){
        assertArgCount(0);
        return Boolean.TRUE;
    }

    protected Object functionFalse(EvalContext context){
        assertArgCount(0);
        return Boolean.FALSE;
    }

    protected Object functionNull(EvalContext context){
        assertArgCount(0);
        return new NullPointer(null, context.getRootContext().getCurrentNodePointer().getLocale());
    }

    protected Object functionNumber(EvalContext context){
        if (getArgumentCount() == 0){
            return InfoSetUtil.number(context.getCurrentNodePointer());
        }
        assertArgCount(1);
        return InfoSetUtil.number(getArg1().computeValue(context));
    }

    protected Object functionSum(EvalContext context){
        assertArgCount(1);
        Object v = getArg1().compute(context);
        if (v == null){
            return ZERO;
        }
        else if (v instanceof EvalContext){
            double sum = 0.0;
            EvalContext ctx = (EvalContext)v;
            while (ctx.nextSet()){
                while (ctx.nextNode()){
                    sum += InfoSetUtil.doubleValue(ctx.getCurrentNodePointer());
                }
            }
            return new Double(sum);
        }
        throw new JXPathException("Invalid argument type for 'sum': "
            + v.getClass().getName());
    }

    protected Object functionFloor(EvalContext context){
        assertArgCount(1);
        double v = InfoSetUtil.doubleValue(getArg1().computeValue(context));
        return new Double(Math.floor(v));
    }

    protected Object functionCeiling(EvalContext context){
        assertArgCount(1);
        double v = InfoSetUtil.doubleValue(getArg1().computeValue(context));
        return new Double(Math.ceil(v));
    }

    protected Object functionRound(EvalContext context){
        assertArgCount(1);
        double v = InfoSetUtil.doubleValue(getArg1().computeValue(context));
        return new Double(Math.round(v));
    }

    private void assertArgCount(int count){
        if (getArgumentCount() != count){
            throw new JXPathException("Incorrect number of argument: " + this);
        }
    }
}
TOP

Related Classes of org.apache.commons.jxpath.ri.compiler.CoreFunction

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.