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

What this is

This file 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.

Other links

The source code

/*
 * Copyright 1999-2004 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.commons.jxpath.ri.compiler;

import java.text.DecimalFormat;
import java.text.DecimalFormatSymbols;
import java.text.NumberFormat;
import java.util.Collection;
import java.util.Locale;

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.EvalContext;
import org.apache.commons.jxpath.ri.InfoSetUtil;
import org.apache.commons.jxpath.ri.model.NodePointer;

/**
 * An element of the compile tree representing one of built-in functions
 * like "position()" or "number()".
 *
 * @author Dmitri Plotnikov
 * @version $Revision: 1.16 $ $Date: 2004/04/01 02:53:45 $
 */
public class CoreFunction extends Operation {

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

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

    public int getFunctionCode() {
        return functionCode;
    }
    
    protected String getFunctionName() {
        switch (functionCode) {
            case Compiler.FUNCTION_LAST :
                return "last";
            case Compiler.FUNCTION_POSITION :
                return "position";
            case Compiler.FUNCTION_COUNT :
                return "count";
            case Compiler.FUNCTION_ID :
                return "id";
            case Compiler.FUNCTION_LOCAL_NAME :
                return "local-name";
            case Compiler.FUNCTION_NAMESPACE_URI :
                return "namespace-uri";
            case Compiler.FUNCTION_NAME :
                return "name";
            case Compiler.FUNCTION_STRING :
                return "string";
            case Compiler.FUNCTION_CONCAT :
                return "concat";
            case Compiler.FUNCTION_STARTS_WITH :
                return "starts-with";
            case Compiler.FUNCTION_CONTAINS :
                return "contains";
            case Compiler.FUNCTION_SUBSTRING_BEFORE :
                return "substring-before";
            case Compiler.FUNCTION_SUBSTRING_AFTER :
                return "substring-after";
            case Compiler.FUNCTION_SUBSTRING :
                return "substring";
            case Compiler.FUNCTION_STRING_LENGTH :
                return "string-length";
            case Compiler.FUNCTION_NORMALIZE_SPACE :
                return "normalize-space";
            case Compiler.FUNCTION_TRANSLATE :
                return "translate";
            case Compiler.FUNCTION_BOOLEAN :
                return "boolean";
            case Compiler.FUNCTION_NOT :
                return "not";
            case Compiler.FUNCTION_TRUE :
                return "true";
            case Compiler.FUNCTION_FALSE :
                return "false";
            case Compiler.FUNCTION_LANG :
                return "lang";
            case Compiler.FUNCTION_NUMBER :
                return "number";
            case Compiler.FUNCTION_SUM :
                return "sum";
            case Compiler.FUNCTION_FLOOR :
                return "floor";
            case Compiler.FUNCTION_CEILING :
                return "ceiling";
            case Compiler.FUNCTION_ROUND :
                return "round";
            case Compiler.FUNCTION_KEY :
                return "key";
            case Compiler.FUNCTION_FORMAT_NUMBER:
                return "format-number";
        }
        return "unknownFunction" + 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;
                
            case Compiler.FUNCTION_FORMAT_NUMBER:
                return args != null && args.length == 2;                             
        }

        return false;
    }
    
    public String toString() {
        StringBuffer buffer = new StringBuffer();
        buffer.append(getFunctionName());
        buffer.append('(');
        Expression args[] = getArguments();
        if (args != null) {
            for (int i = 0; i < args.length; i++) {
                if (i > 0) {
                    buffer.append(", ");
                }
                buffer.append(args[i]);
            }
        }
        buffer.append(')');
        return buffer.toString();
    }

    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);
            case Compiler.FUNCTION_FORMAT_NUMBER :
                return functionFormatNumber(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) {
            NodePointer ptr = context.getCurrentNodePointer();
            String str = ptr.getNamespaceURI();
            return str == null ? "" : str;
        }
        assertArgCount(1);
        Object set = getArg1().compute(context);
        if (set instanceof EvalContext) {
            EvalContext ctx = (EvalContext) set;
            if (ctx.hasNext()) {
                NodePointer ptr = (NodePointer) ctx.next();
                String str = ptr.getNamespaceURI();
                return str == null ? "" : str;
            }
        }
        return "";
    }

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

    protected Object functionName(EvalContext context) {
        if (getArgumentCount() == 0) {
            NodePointer ptr = context.getCurrentNodePointer();
            return ptr.getName().toString();
        }
        assertArgCount(1);
        Object set = getArg1().compute(context);
        if (set instanceof EvalContext) {
            EvalContext ctx = (EvalContext) set;
            if (ctx.hasNext()) {
                NodePointer ptr = (NodePointer) ctx.next();
                return ptr.getName().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 null;
    }

    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.hasNext()) {
                NodePointer ptr = (NodePointer) ctx.next();
                sum += InfoSetUtil.doubleValue(ptr);
            }
            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 Object functionFormatNumber(EvalContext context) {
        int ac = getArgumentCount();
        if (ac != 2 && ac != 3) {
            assertArgCount(2);
        }

        double number =
            InfoSetUtil.doubleValue(getArg1().computeValue(context));
        String pattern =
            InfoSetUtil.stringValue(getArg2().computeValue(context));

        DecimalFormatSymbols symbols = null;
        if (ac == 3) {
            String symbolsName =
                InfoSetUtil.stringValue(getArg3().computeValue(context));
            symbols =
                context.getJXPathContext().getDecimalFormatSymbols(symbolsName);
        }
        else {
            NodePointer pointer = context.getCurrentNodePointer();
            Locale locale;
            if (pointer != null) {
                locale = pointer.getLocale();
            }
            else {
                locale = context.getJXPathContext().getLocale();
            }
            symbols = new DecimalFormatSymbols(locale);
        }
        
        DecimalFormat format = (DecimalFormat) NumberFormat.getInstance();
        format.setDecimalFormatSymbols(symbols);
        format.applyLocalizedPattern(pattern);
        return format.format(number);
    }

    private void assertArgCount(int count) {
        if (getArgumentCount() != count) {
            throw new JXPathException("Incorrect number of argument: " + this);
        }
    }
}
... 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.