Search in sources :

Example 1 with ParamType

use of com.jayway.jsonpath.internal.function.ParamType in project JsonPath by json-path.

the class PathCompiler method parseFunctionParameters.

/**
 * Parse the parameters of a function call, either the caller has supplied JSON data, or the caller has supplied
 * another path expression which must be evaluated and in turn invoked against the root document.  In this tokenizer
 * we're only concerned with parsing the path thus the output of this function is a list of parameters with the Path
 * set if the parameter is an expression.  If the parameter is a JSON document then the value of the cachedValue is
 * set on the object.
 *
 * Sequence for parsing out the parameters:
 *
 * This code has its own tokenizer - it does some rudimentary level of lexing in that it can distinguish between JSON block parameters
 * and sub-JSON blocks - it effectively regex's out the parameters into string blocks that can then be passed along to the appropriate parser.
 * Since sub-jsonpath expressions can themselves contain other function calls this routine needs to be sensitive to token counting to
 * determine the boundaries.  Since the Path parser isn't aware of JSON processing this uber routine is needed.
 *
 * Parameters are separated by COMMAs ','
 *
 * <pre>
 * doc = {"numbers": [1,2,3,4,5,6,7,8,9,10]}
 *
 * $.sum({10}, $.numbers.avg())
 * </pre>
 *
 * The above is a valid function call, we're first summing 10 + avg of 1...10 (5.5) so the total should be 15.5
 *
 * @return
 *      An ordered list of parameters that are to processed via the function.  Typically functions either process
 *      an array of values and/or can consume parameters in addition to the values provided from the consumption of
 *      an array.
 */
private List<Parameter> parseFunctionParameters(String funcName) {
    ParamType type = null;
    // Parenthesis starts at 1 since we're marking the start of a function call, the close paren will denote the
    // last parameter boundary
    Integer groupParen = 1, groupBracket = 0, groupBrace = 0, groupQuote = 0;
    Boolean endOfStream = false;
    char priorChar = 0;
    List<Parameter> parameters = new ArrayList<Parameter>();
    StringBuffer parameter = new StringBuffer();
    while (path.inBounds() && !endOfStream) {
        char c = path.currentChar();
        path.incrementPosition(1);
        // we're at the start of the stream, and don't know what type of parameter we have
        if (type == null) {
            if (isWhitespace(c)) {
                continue;
            }
            if (c == OPEN_BRACE || isDigit(c) || DOUBLE_QUOTE == c) {
                type = ParamType.JSON;
            } else if (isPathContext(c)) {
                // read until we reach a terminating comma and we've reset grouping to zero
                type = ParamType.PATH;
            }
        }
        switch(c) {
            case DOUBLE_QUOTE:
                if (priorChar != '\\' && groupQuote > 0) {
                    if (groupQuote == 0) {
                        throw new InvalidPathException("Unexpected quote '\"' at character position: " + path.position());
                    }
                    groupQuote--;
                } else {
                    groupQuote++;
                }
                break;
            case OPEN_PARENTHESIS:
                groupParen++;
                break;
            case OPEN_BRACE:
                groupBrace++;
                break;
            case OPEN_SQUARE_BRACKET:
                groupBracket++;
                break;
            case CLOSE_BRACE:
                if (0 == groupBrace) {
                    throw new InvalidPathException("Unexpected close brace '}' at character position: " + path.position());
                }
                groupBrace--;
                break;
            case CLOSE_SQUARE_BRACKET:
                if (0 == groupBracket) {
                    throw new InvalidPathException("Unexpected close bracket ']' at character position: " + path.position());
                }
                groupBracket--;
                break;
            // we've encountered a COMMA do the same
            case CLOSE_PARENTHESIS:
                groupParen--;
                if (0 != groupParen) {
                    parameter.append(c);
                }
            case COMMA:
                // to the parser
                if ((0 == groupQuote && 0 == groupBrace && 0 == groupBracket && ((0 == groupParen && CLOSE_PARENTHESIS == c) || 1 == groupParen))) {
                    endOfStream = (0 == groupParen);
                    if (null != type) {
                        Parameter param = null;
                        switch(type) {
                            case JSON:
                                // parse the json and set the value
                                param = new Parameter(parameter.toString());
                                break;
                            case PATH:
                                LinkedList<Predicate> predicates = new LinkedList<Predicate>();
                                PathCompiler compiler = new PathCompiler(parameter.toString(), predicates);
                                param = new Parameter(compiler.compile());
                                break;
                        }
                        if (null != param) {
                            parameters.add(param);
                        }
                        parameter.delete(0, parameter.length());
                        type = null;
                    }
                }
                break;
        }
        if (type != null && !(c == COMMA && 0 == groupBrace && 0 == groupBracket && 1 == groupParen)) {
            parameter.append(c);
        }
        priorChar = c;
    }
    if (0 != groupBrace || 0 != groupParen || 0 != groupBracket) {
        throw new InvalidPathException("Arguments to function: '" + funcName + "' are not closed properly.");
    }
    return parameters;
}
Also used : ArrayList(java.util.ArrayList) ParamType(com.jayway.jsonpath.internal.function.ParamType) InvalidPathException(com.jayway.jsonpath.InvalidPathException) LinkedList(java.util.LinkedList) Predicate(com.jayway.jsonpath.Predicate) Parameter(com.jayway.jsonpath.internal.function.Parameter)

Example 2 with ParamType

use of com.jayway.jsonpath.internal.function.ParamType in project JsonPath by jayway.

the class PathCompiler method parseFunctionParameters.

/**
 * Parse the parameters of a function call, either the caller has supplied JSON data, or the caller has supplied
 * another path expression which must be evaluated and in turn invoked against the root document.  In this tokenizer
 * we're only concerned with parsing the path thus the output of this function is a list of parameters with the Path
 * set if the parameter is an expression.  If the parameter is a JSON document then the value of the cachedValue is
 * set on the object.
 *
 * Sequence for parsing out the parameters:
 *
 * This code has its own tokenizer - it does some rudimentary level of lexing in that it can distinguish between JSON block parameters
 * and sub-JSON blocks - it effectively regex's out the parameters into string blocks that can then be passed along to the appropriate parser.
 * Since sub-jsonpath expressions can themselves contain other function calls this routine needs to be sensitive to token counting to
 * determine the boundaries.  Since the Path parser isn't aware of JSON processing this uber routine is needed.
 *
 * Parameters are separated by COMMAs ','
 *
 * <pre>
 * doc = {"numbers": [1,2,3,4,5,6,7,8,9,10]}
 *
 * $.sum({10}, $.numbers.avg())
 * </pre>
 *
 * The above is a valid function call, we're first summing 10 + avg of 1...10 (5.5) so the total should be 15.5
 *
 * @return
 *      An ordered list of parameters that are to processed via the function.  Typically functions either process
 *      an array of values and/or can consume parameters in addition to the values provided from the consumption of
 *      an array.
 */
private List<Parameter> parseFunctionParameters(String funcName) {
    ParamType type = null;
    // Parenthesis starts at 1 since we're marking the start of a function call, the close paren will denote the
    // last parameter boundary
    int groupParen = 1, groupBracket = 0, groupBrace = 0, groupQuote = 0;
    boolean endOfStream = false;
    char priorChar = 0;
    List<Parameter> parameters = new ArrayList<Parameter>();
    StringBuilder parameter = new StringBuilder();
    while (path.inBounds() && !endOfStream) {
        char c = path.currentChar();
        path.incrementPosition(1);
        // we're at the start of the stream, and don't know what type of parameter we have
        if (type == null) {
            if (isWhitespace(c)) {
                continue;
            }
            if (c == OPEN_BRACE || isDigit(c) || DOUBLE_QUOTE == c) {
                type = ParamType.JSON;
            } else if (isPathContext(c)) {
                // read until we reach a terminating comma and we've reset grouping to zero
                type = ParamType.PATH;
            }
        }
        switch(c) {
            case DOUBLE_QUOTE:
                if (priorChar != '\\' && groupQuote > 0) {
                    groupQuote--;
                } else {
                    groupQuote++;
                }
                break;
            case OPEN_PARENTHESIS:
                groupParen++;
                break;
            case OPEN_BRACE:
                groupBrace++;
                break;
            case OPEN_SQUARE_BRACKET:
                groupBracket++;
                break;
            case CLOSE_BRACE:
                if (0 == groupBrace) {
                    throw new InvalidPathException("Unexpected close brace '}' at character position: " + path.position());
                }
                groupBrace--;
                break;
            case CLOSE_SQUARE_BRACKET:
                if (0 == groupBracket) {
                    throw new InvalidPathException("Unexpected close bracket ']' at character position: " + path.position());
                }
                groupBracket--;
                break;
            // we've encountered a COMMA do the same
            case CLOSE_PARENTHESIS:
                groupParen--;
                // CS304 Issue link: https://github.com/json-path/JsonPath/issues/620
                if (0 > groupParen || priorChar == '(') {
                    parameter.append(c);
                }
            case COMMA:
                // to the parser
                if ((0 == groupQuote && 0 == groupBrace && 0 == groupBracket && ((0 == groupParen && CLOSE_PARENTHESIS == c) || 1 == groupParen))) {
                    endOfStream = (0 == groupParen);
                    if (null != type) {
                        Parameter param = null;
                        switch(type) {
                            case JSON:
                                // parse the json and set the value
                                param = new Parameter(parameter.toString());
                                break;
                            case PATH:
                                LinkedList<Predicate> predicates = new LinkedList<>();
                                PathCompiler compiler = new PathCompiler(parameter.toString(), predicates);
                                param = new Parameter(compiler.compile());
                                break;
                        }
                        if (null != param) {
                            parameters.add(param);
                        }
                        parameter.delete(0, parameter.length());
                        type = null;
                    }
                }
                break;
        }
        if (type != null && !(c == COMMA && 0 == groupBrace && 0 == groupBracket && 1 == groupParen)) {
            parameter.append(c);
        }
        priorChar = c;
    }
    if (0 != groupBrace || 0 != groupParen || 0 != groupBracket) {
        throw new InvalidPathException("Arguments to function: '" + funcName + "' are not closed properly.");
    }
    return parameters;
}
Also used : ArrayList(java.util.ArrayList) ParamType(com.jayway.jsonpath.internal.function.ParamType) InvalidPathException(com.jayway.jsonpath.InvalidPathException) LinkedList(java.util.LinkedList) Predicate(com.jayway.jsonpath.Predicate) Parameter(com.jayway.jsonpath.internal.function.Parameter)

Aggregations

InvalidPathException (com.jayway.jsonpath.InvalidPathException)2 Predicate (com.jayway.jsonpath.Predicate)2 ParamType (com.jayway.jsonpath.internal.function.ParamType)2 Parameter (com.jayway.jsonpath.internal.function.Parameter)2 ArrayList (java.util.ArrayList)2 LinkedList (java.util.LinkedList)2