Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

An expression parser #40

Open
satyasuman opened this Issue · 0 comments

1 participant

@satyasuman

Hi, while using JSON Select i had a requirement of being able to access a JSON object with expression like [uuid="123"].account_info.[full_name="Test"].city_state_zip which would select any node that had UUID as 123 and a object in that node with full_name as Test and then the value of city_state_zip in that object, so the sake of simplicity i took a simple example. For the above requirement i have written a parser, which will convert an expression as above to a JSON Select expression. Below is the code for the same.

var Parser = function () {
var SIMPLE_EXPRESSION = 0;
var COMPLEX_EXPRESSION = 1;
var SELECT_ALL_EXPRESSION = 2;
var ATTRIBUTE_SEPERATOR = "=";
var SQUARE_OPENER = "[";
var SQUARE_CLOSER = "]";
var EXPRESSION_SEPERATOR = ".";
var GLOBAL_SELECTOR = "*";

    function Expression(objName, attribute, exprType) {
        this.exprType = exprType;
        this.objName = objName;
        if(exprType != SIMPLE_EXPRESSION){
            var attributeArr = attribute.split(ATTRIBUTE_SEPERATOR);
            this.attributeName = attributeArr[0];
            this.attributeVal = attributeArr[1];
        }
        this.cssExpression = this.generateCSSExpression();
    }

    Expression.prototype = {
        generateCSSExpression: function(){
            if(this.cssExpression == undefined || this.cssExpression == null){
                var cssExpression = null;
                switch(this.exprType){
                    case COMPLEX_EXPRESSION:
                        cssExpression = "."+this.objName+" :has(."+this.attributeName+":expr(x="+this.attributeVal+"))";
                        break;
                    case SELECT_ALL_EXPRESSION:
                        cssExpression = ":has(:root > ."+ this.attributeName+ ":expr(x="+this.attributeVal+"))";
                        break;
                    case SIMPLE_EXPRESSION:
                        cssExpression =  "."+this.objName;
                        break;
                }
                this.cssExpression = cssExpression;
            }
            return this.cssExpression;
        }
    }

    function Parser() {

    }

    Parser.parse = function (expr) {
        return new Parser().parse(expr);
    };

    Parser.getExpressionStack = function (expr) {
        return new Parser().getExpressionStack(expr);
    };

    Parser.prototype = {
        getExpressionStack: function(expr){
            return this.parseExpression(expr, false);
        },
        parse: function (expr) {
            return this.parseExpression(expr, true);
        },
        parseExpression: function(expr, isString){
            this.expression = expr;
            this.expressionStack = [];
            this.pos = 0;
            var objectArray = this.expression.split(EXPRESSION_SEPERATOR);
            var self = this;
            /**
             * This function is used to parse a expression and generate a CSS expression out of it
             * Example expressions are
             * name_address[type='PRI'].email_address would generate a CSS Expression .name_address .type:val('PRI') ~ .email_address
             */
            $.each(objectArray, function(index, expr){
                var expression = null;
                var expressionType = self.getExpressionType(expr);
                switch(expressionType){
                    case COMPLEX_EXPRESSION:
                    case SELECT_ALL_EXPRESSION:
                        var exprArray = expr.replace(SQUARE_OPENER,"").split(SQUARE_CLOSER);
                        if(exprArray[1] === "" && exprArray.length == 2){
                            exprArray[1] = exprArray[0].replace("*","");
                        }
                        expression = new Expression(exprArray[0], exprArray[1], expressionType);
                        break;
                    case SIMPLE_EXPRESSION:
                        expression = new Expression(expr, null, expressionType);
                        break;
                }
                if(isString){
                    self.expressionStack.push(expression.cssExpression);
                } else {
                    self.expressionStack.push(expression);
                }

            });
            if(isString){
                return self.expressionStack.join(" ");
            }
            return this.expressionStack;
        },
        getExpressionType: function(expr){
            if(expr.indexOf(GLOBAL_SELECTOR) >= 0)
                return SELECT_ALL_EXPRESSION;
            if(expr.indexOf(SQUARE_OPENER) >= 0 && expr.indexOf(SQUARE_CLOSER) >= 0)
                return COMPLEX_EXPRESSION;
            return SIMPLE_EXPRESSION;
        }
    }
    return Parser;
}();

I am a newbie to Javascript, Please let me know if the above can be improved

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.