Resolving variables

In the original JsonLogic format, operators accessing data use a dot-like notation. With the following expression:

{"var": "some.var"}

and the following data:

{
    "some": {
        "var": 1
    }
}

the expression will evaluate to 1. However, this dot-like notation can be ambiguous:

  • As the empty string "" is special cased to refer to the entire data object, it is impossible to refer to 1 with the following data:

    {
        "": 1
    }
    

    as the reference "" would evaluate to {"": 1}, and "." could be parsed as a reference to {"": {"": 1}}.

  • There is no way to escape dots if present in data keys. The reference "some.var" could refer to both 1 and 2 with the following data:

    {
        "some": {
            "var": 1
        },
        "some.var": 2
    }
    

For this reason, an alternative format is proposed, based on the JSON Pointer standard (RFC 6901).

With the following data:

{
    "path": 1,
    "": 2,
    "": {"": 3},
    "path.to": 4,
    "path/": 5
}

this is how the references will evaluate:

{"var": "/path"} -> 1
{"var": ""} -> 2
{"var": "/"} -> whole object
{"var": "//"} -> 3
{"var": "/path.to"} -> 4
{"var": "/path~1"} -> 5

Variables scopes

The original JsonLogic format implicitly uses the notion of a scope in the implementation of some operators such as map:

{
    "map": [
        [1, 2],
        {"*": [{"var": ""}, 2]}
    ]
}

In this case, the variable reference "" will refer to each element of the array [1, 2]. This means that there is no way to access data from the top level object (say for example you wanted to multiply every element of the array with {"var": "some_const"} instead of 2).

The notion of scope is thus introduced, so that it is still possible to access data from the parent scope. This scope can be specified by appending @n at the end of the variable reference. The current scope starts at 0, so using "some_var@0" is equivalent to "some_var".

Using our previous map example, with the following data:

{
    "some_const": 2
}

the operator can be written as:

{
    "map": [
        [1, 2],
        {"*": [{"var": ""}, {"var": "some_const@1"}]}
    ]
}

and would evaluate to [2, 4].

For more details on resolving variables, you can refer to the API documentation: Evaluation.