ObjectPath Reference

The scope of ObjectPath

ObjectPath is a query language similar to XPath or JSONPath, but much more powerful thanks to embedded arithmetic calculations, comparison mechanisms and built-in functions. This makes the language more like SQL in terms of expressiveness, but it works over JSON documents rather than relations. ObjectPath can be considered a full-featured expression language. Besides selector mechanism there is also boolean logic, type system and string concatenation available. On top of that, the language implementations (Python at the moment; Javascript is in beta!) are secure and relatively fast.

Types

ObjectPath manipulates JSON documents and inherits all types from the format introducing some modifications:

  • JSON's number is split into integer and float:
    • integer is fast and small integer number
    • float is slow and very accurate real number
  • Strings are encoded in UTF-8,
  • Added the datetime, date and time types to handle dates,
  • Boolean types and null are case insensitive and can be written in several ways:
    • true can be written as: t, true (or trUe),
    • false as: f and false,
    • null as: n, none, null, nil.
  • Negative are: false, null, 0, "", [], {}. Any other value is positive.

Dates are stored as datetime objects. Operations on dates should be performed on UTC dates to avoid locale and DST (daylight saving time) nuances. There are also date and time objects which provide support for date and time manipulation. Datetime, date and time objects support year, month, day, hour, minute, second and microsecond attributes eg. now().year -> 2011.

Arrays and objects can be defined in the language by issuing:

[val1,val2,...,valN]

and:

{"atr1":val1,"atr2":val2,...,"atrN":valN}
{atr1:val1,atr2:val2,...,atrN:valN}

Attribute names can be string or expression which results in string. When expression returns value other than string it will be casted to a string. Names can be written without quotes, but in that case they cannot start with an operator. ObjectPath interpreter will raise an exception if name is not valid.

Operators

Arithmetic operators

Operator Description Example Notes
+ addition 2 + 3 -> 5 Alternate usage is concatenation
- subtraction 2 - 3 -> -1  
* multiplication 2 * 3 -> 6 Alternate usage is select all objects from array
/ division 2/3 -> 0.6666666666666666,
float(2)/3 -> 0.6666666666666666
Integer division results in floating point number. Use int() built-in function to make it integer again.
% modulo 10%3 -> 1  

Boolean logic operators

Operator Description Example Notes
not negation not 3 -> false not always casts result to boolean type
and conjunction false and true -> false and evaluates left expression, if negative it is returned and right expression is not evaluated.
or alternation true or false ->true or evaluates left expression if positive it is returned and right expression is not evaluated.

Comparison operators

All comparison operators try to cast right expression result to type of left expression result type. Sometimes it fails so the best practice is to use casting functions when types may be different.

WARNING! The comparison operators are not chainable so 1<2<2 will compare 2 with result of 1<2 which is true and return true. Use 1<2 and 2<3 instead.

Operator Description Example Notes
is equality '3' is 3 -> true right expression result is casted to type of left expression result and then compared
is not equality negation 3 is not 3 -> false  
>, >=, <, <= grater than, grater than or equal, less than, less than or equal 1>0 ->true WARNING! if these operators are used inside BLSL XML container characters < and > must be escaped to &lt; and &gt; respectively. Alternate option is to wrap whole expression in CDATA section.

Membership tests

Operator Description Example Notes
in Checks if left expression result is in array, object or string 3 in [1,2,4] -> false,
"ia" in "Adrian" -> true
In objects, keys will be matched.
not in Opposite behavior to in; Faster equivalent to not expr in array 1 not in [1,2,3] -> false  

Concatenation operator +

Beside standard addition of numbers, + concatenates strings, arrays and objects. Left and right expression results must be of the same type (concatenating e.g. string and list yields an error).

If two arrays are concatenated, right array elements are added to the end of left array.

Objects are merged so that right object overwrites existing elements of left object. Object concatenation is not deep. It means that only direct child elements of root element are overwritten rather than leaf nodes.

[1,2,4] + [3,5] -> [1,2,4,3,5]
{"a":1,"b":2} + {"a":2,"c":3} -> {"a":2,"b":2,"c":3}

Built-in functions

Casting functions

Casting is done by passing arguments to Python functions of the same name.

Function Example Notes
str(any) str(11) -> '11'  
int(numberOrString) int(123.45) -> 123  
float(numberOrString) float(‘123.45’) -> 123.45  
array(any) array(now()) -> [2011,4,8,13,3,55,747070]  

Arithmetic functions

Function Example Notes
sum(array) sum([1,2,3,4]) -> '10' Argument is a list of numbers. If there are float numbers in the list, sum() returns float.
max(array) max([2,4,1,3]) -> 4  
min(array) min([2,4,1,3]) -> 1  
avg(array) avg([2,4,1,3]) -> 2.5 equivalent to sum(array)/len(array)
round(float, integer) round(0.55,1) -> 0.5 Returns always float. Second argument defines the precision of round.

String functions

Function Example Notes
replace(string, toReplace, replacement) replace('abcd','b','a') -> 'aacd'  
escape(string) escape('') -> '' The / character escapes ' because it is reserved as end of string sign.
unescape(string) unescape('') -> '' Reverse to the escape.
upper(string) upper('AaA') -> 'AAA'  
lower(string) lower('AaA') -> 'aaa'  
capitalize(string) capitalize('AaA') -> 'Aaa'  
title(string) title('aaa bbb') -> 'Aaa Bbb'  
split(string[, sep]) split('aaa bbb') -> ['aaa','bbb'],
split('aaa,bbb','.') -> ['aaa','bbb']
 

Array functions

Function Example Notes
sort(array[, key]) sort(['c','b','a']) -> ['a','b','c'],
sort([{v:'c',x:1},{v:'b',x:2},{v:'a',x:3}],'v') -> [{v:'a',x:3},{v:'b',x:2},{v:'c',x:1}]
If key is provided, will sort array of objects by key.
reverse(array) reverse([1,2,3]) -> [3,2,1]  
count(array), len(array) count([1,2,3]) -> 3 Reverse to the escape.
join(array[, joiner]) join(['c','b','a']) -> 'cba',
join(['c','b','a'],'.') -> 'c.b.a',
 

Date and time functions

All date and time functions are manipulating datetime objects. The default (and the only!) timezone is UTC.

Function Example Notes
now() now() -> '2011-04-08 13:03:55.747070' Gets current UTC time.
date(arg) date() -> '2011-04-08',
date([2011,4,8]) -> '2011-04-08',
date(now()) -> '2011-04-08'
arg can be array of structure [yyyy,mm,dd] or datetime object . If no arg is specified then date() defaults to current UTC date.
time(arg) time() -> '13:03:55.747070',
time([13,3,55,747070]) -> '13:03:55.747070',
time(now()) -> '13:03:55.747070'
arg can be array of structure [hh,mm,ss,mmmmmm] where only hour is required, or datetime object . If no arg is specified then time() defaults to current UTC time.
dateTime(args) dateTime(now()) -> '2011-04-08 13:03:55.747070',
dateTime([2011,4.8,13,3,55,747070]) -> '2011-04-08 13:03:55.747070',
dateTime(date(),time()) -> '2011-04-08 13:03:55.747070',
dateTime([2011,4.8],time()) -> '2011-04-08 13:03:55.747070'
args: if one argument is specified then it need to be datetime object or [yyyy,mm,dd,hh,mm,ss,mmmmmm] where year, month, day, hour and minute are required. If two arguments are specified, the first argument can be date object or [yyyy,mm,dd] array, second can be time object or [hh,mm,ss,mmmmmm] array where only hour is required.
age(time) age(sometime) -> [1, 'week'] Counts how old the provided time is and prettyprints it.
toMillis(time)   Counts milliseconds since epoch.

Misc functions

Function Example Notes
type(any) type([1,3,2,5]) -> 'array' Tool helpful in debugging expressions.
count(any), len(any) count("abcd") -> 4 Counts elements in a given argument. If element is not countable, it is returned unmodified.
sort(array) sort([1,3,2,2,5]) -> [1,2,2,3,5] Sorts elements in an array.
WARNING! Sort might be very slow for large data.
reverse(array) reverse([1,3,2,2,5]) -> [5,2,2,3,1] Since ACR 1.1.
WARNING! Reverse might be very slow for large data.
generateID()   Generates unique ID. Since ACR 1.0.4
objectID(oidString), ObjectId(oidString)   MongoDB helper function.

Localize function

Localize() function tries to localize an argument. Now it works only for dates and times, but it is meant to support numbers and currencies.

It is good idea to store UTC times in the database and show localized time to the user. To show localized current time in Warsaw, Poland use localize() function as following:

localize(now(),'Europe/Warsaw')

Paths

ObjectPath aims to follow the JSONPath specification, but instead copying behavior one to one, language adds its own selector syntax to significantly extend expressiveness of the language. By not relying on JavaScript, selectors are more human readable than in JSONPath.

Paths uses dot notation (JSONPath bracket-notation is dropped):

$.attributeName[selector].attributeName2

where $ is root element, ns is optional and defaults to local namespace (request storage in AC Runtime), . selects all direct child elements from node, attributeName restricts these elements to those containing attribute of name attributeName and [] contains selector expression which restrict results even more. attributeName2 selects child elements from results of previous computation.

Complete syntax

Following table contains complete syntax of paths (near identical to the JSONPath table):

Operator Description
$ the root object/element
@ the current object/element
. child/property operator
.. recursive descent. ObjectPath borrows this syntax from E4X (and JSONPath).
* wildcard. All objects/elements regardless their names.
[] selector operator. Full documentation is available in next chapter.
[start:end:step] NOT IMPLEMENTED YET array slice operator borrowed from ES4.

Selectors

Selector selects array elements that are satisfying expression. Expression are not restricted so one can nest paths or use comparison operators.

Selectors are written inside the [] operator.

If selector returns N integer number, N+1th element will be returned:

$.*[1] -> second element from array

If selector contains a string, its behavior is similar to dot operator:

$..*['string'] is $..string -> true

Selector can use comparison operators to find elements:

$..*[@.'attribute' is 'ok']

and boolean operators to handle more than one condition:

$..*[@.'attribute' is 'ok' or len(@.*[1]) is 2]

@ operator matches current element. Selector iterates over left expression result (which is array). @ will match the element currently checked against expression.

WARNING! @ operator is slow! Try using or/and operators in conjunction with simple expression that should match some elements or other optimization techniques.

Plans to extend ObjectPath

Most important enhancements:

  • provide date and time manipulation built-in functions,
  • distinguish regex functions and string functions - regexes are slow and not necessary in most cases,
  • add regex matching to selectors,

Optimization plans

  • make $..*[1] faster - generator will help,
  • replace operator names with numbers.
comments powered by Disqus

© Copyright Asyncode Ltd. All Rights Reserved Home | Contact
Powered by Asyncode CMS