Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migration of unmigrated content due to installation of a new plugin

Summary

Design

Introduction

The A-path language is the result of an effort to provide syntax and semantics for querying objects of the openEHR reference model, specially archetypes, templates and compositions. A-path is entirely based on the XPath language (query language for XML documents). It also provides basic facilities for manipulation of lists, strings, numbers and booleans.

A-path is part of the zilics-models project, currently hosted in the OpenEhr svn sandbox area (svn url = http://www.openehr.org/svn/ref_impl_java/SANDBOX/zilics-models)

Basic Types

The primary syntactic construct in A-path is the expression (syntactic rule: expr ). An expression syntactically consists of a list of single expressions (syntactic rule: exprSingle ) separated by commas ',' .

Grammatically speakin, we have the following definition of expr :

expr: exprSingle ( ',' exprSingle ) *
;

Each single expression is evaluated to yield a ListValue . A ListValue is a list of SingleValues , and a SingleValue has one of the following five basic types:

...

In the end, all the ListValues generated by each single expression are merged together in another ListValue , which is the value of the expression. For example, the expression '1, 2, 3, 4, 5' consists of 5 single expressions separated by commas. The full expression yields aListValue containing a list of 5 SingleValues of basic type Number, because each single expression yields an atomic ListValue consisting of only one SingleValue . On the other hand, the expression '1, (2, 3)' is an expression composed by 2 single expressions (syntactically), but when it is evaluated, it yields a ListValue containing 3 SingleValues . Another example: the expression '/' yields a ListValue containing a list of oneSingleValue of basic type RMObject (actually it is the root value of the evaluation context).

The context

Every evaluation occurs with respect to a context (called PathEvaluationContext). The PathEvaluationContext consists of:

...

The function library consists of a mapping from function names to functions. Each function takes zero or more arguments (each argument being a ListValue ) and returns a ListValue . For example, in the expression 'myfunc ((1, 2), 4)' , the function 'myfunc' is being invoked with 2 arguments: the first is the ListValue '(1, 2)' and the second is the ListValue '4' (which actually contains only one SingleValue ).

Some expressions

One important kind of expression is a path expression (syntactic rule: pathExpr ). A path expression selects a set of values relative to the context item. The result of evaluating an expression that is a path one is the ListValue containing the SingleValues selected by the path. Path expressions can recursively contain filter expressions (syntactic rule: filterExpr ) that are used to filter ListValues or it can contains basic axes (syntactic rule: axisStep ) for selecting values.

The grammar for pathExpr is:
pathExpr: '/' relativePathExpr
        | '//' relativePathExpr
        | relativePathExpr
        | '/'
        ;

relativePathExpr: stepExpr '/' stepExpr
                | stepExpr '//' stepExpr
                ;

stepExpr: filterExpr
        | axisStep
        ;

The slash '/' operator is called the PathFollow operator. In the expression 'A/B' , where 'A' and 'B' are expressions, first we evaluate the expression 'A' (and it yields a ListValue ). Then for each SingleValue in 'A' , we perform:

...

The double slashed '//' operator is a contract form of '/descendant-of-self::*/' , which will be explained later.

Basic navigation

The axis step is an expression which operates on RMObject s. To operate on them, first, we define a standard name for each RMObject . For objects of the Archetype Model, it is very easy to define a name, because we can adopt the rmAttributeName of the parent CAttribute as the standard name of an CObject . In the case of the Reference Model, it is possible to adopt the name of the field that contains the object (parent) as the standard name.

...

The grammar for axisStep is:

axisStep: (reverseStep | forwardStep ) predicateList
        ;

forwardStep: forwardAxis '::' valueTest
           | abbrevForwardStep
           ;

abbrevForwardStep: ('@')? valueTest
                 ;

forwardAxis: 'child'
           | 'descendant'
           | 'self'
           | 'metadata'
           | 'descendant-or-self'
           ;

reverseStep: reverseAxis '::' valueTest
           | abbrevReverseStep
           ;

reverseAxis: 'parent'
           | 'ancestor'
           | 'ancestor-or-self'
           ;

abbrevReverseStep: '..'
                 ;

valueTest: Identifier
         | '*'
         ;

Filtering results

Filter expressions are used to filter elements of ListValues , removing unwanted ones. Filtering is accomplished by using the '[' ']' operator. In the expression 'A[B]' , where 'A' and 'B' are expressions, first we evaluate the expression 'A' (and it yields a ListValue ). Then for eachSingleValue in 'A' , we perform:

...

The grammar of filterExpr expressions is:

filterExpr: primaryExpr predicateList
          ;

predicateList: ( predicate ) *
             ;

predicate: '[' ATCode ']'
         | '[' expr ']'
         ;

The Boolean value

ListValue is considered "true" if:

...

  1. '()'
  2. '(2, 3)'
  3. '(false)'
  4. '(0)'

Primary expressions

Primary expressions have basically 5 types: literals, variable references, parenthesized expressions, the context item expression ('.' ) and function calls.

The grammar for primaryExpr is:

primaryExpr: literal
           | varRef
           | parenthesizedExpr
           | contextItemExpr
           | functionCall
           ;

literal: IntegerLiteral
       | DoubleLiteral
       | StringLiteral
       ;

varRef: '$' varName
      ;

varName: Identifier
       ;

contextItemExpr: '.'
               ;

parenthesizedExpr: '(' expr ? ')'
                 ;

functionCall: Identifier '(' ( exprSingle (',' exprSingle )* )? ')'
            ;
Example of primary expressions:

  1. '$var' - a reference to a variable 'var'
  2. '12' - an integer literal
  3. '"string"' - an string literal
  4. '.' - the context item expression
  5. 'fatorial(5)' - a function call

Single expresions

There are several possibilities while building a single expression (syntactic rule: exprSingle ), for example for expressions or if expressions or quantified expressions.

Grammar for exprSingle :

exprSingle: forExpr
          | quantifiedExpr
          | ifExpr
          | orExpr
          ;

For expression

for expression looks like 'for $var1 in E1, $var2 in E2, ..., $varn in En return E' , where 'E' , 'E1' , 'E2' , ... , 'En' are single expressions and '$var1' , '$var2' , ..., '$varn' are variables.

Grammar for forExpr :

forExpr: 'for' '$' varName 'in' exprSingle (',' '$' varName 'in' exprSingle ) * 'return' exprSingle
       ;

When we have two or more variables in the for expression, the innermost variable is the one which changes the most. For example in 'for $i in (1 to 3), $j in (1 to 3) return ($i + 10 * $j)' , the result of the previous expression is '(11, 21, 31, 12, 22, 32, 13, 23, 33)' and not{{'(11, 12, 13, 21, 22, 23, 31, 32, 33)'}} .

If expression

An if expression is very simple and it has the form: 'if (C) then ET else EF' , where 'ET' , 'EF' are primary expressions and 'C' is an expression (called condition). The return value of an if expression is the value of 'ET' when 'C' yields a true ListValue and it is the value of{{'EF'}} when 'C' yields a false ListValue .

The grammar for ifExpr is:

ifExpr: 'if' '(' expr ')' 'then' exprSingle 'else' exprSingle
      ;

Quantified expressions

Also, we have 2 types of quantified expressions: the some and the every expressions. They have similar semantics and they test if a condition holds for some (or every ) variable values.

The syntactic form for quantifiedExpr is:

quantifiedExpr: ('some' | 'every') '$' varName 'in' exprSingle (',' '$' varName 'in' exprSingle ) * 'satisfies' exprSingle
              ;

For example in the quantified expression 'every $x in (1 to 4) satisfies ($x < 5)' , clearly for every value of '$x' in '(1 to 4)' , it satisfies the condition '($x < 5)' , so the final value of the every expression is true . On the other hand, the quantified expression 'some $x in (1 to 4) satisfies ($x> 5)' clearly yields a false value, because none of the values of '$x' satisfies '($x> 5)' .

Logical operators

It is possible to build up logical expressions with the operators and and or , and that is what is described bellow.

...

andExpr: comparisonExpr ( 'and' comparisonExpr ) *
;

Common expressions

A comparison expression (syntactic rule: comparisonExpr ) is used to compare numeric values (integer or doubles), and its syntactic form is comparisonExpr :

comparisonExpr: rangeExpr ( ( '=' | '!=' | '<' | '<=' | '>' | '>=' ) rangeExpr) ?
              ;
The range operator "to" is used to build lists of numeric values ranging from one value to another, such as in the expression '10 to 100'. The grammar form is:

rangeExpr: additiveExpr  ( 'to' additiveExpr ) ?
         ;
It is possible to perform some basic math operations like '+' , '-' , '*' , 'div' and 'mod' (or remainder ).

additiveExpr: multiplicativeExpr ( ('+' | '-') multiplicativeExpr ) *
            ;

multiplicativeExpr: unionExpr ( ( '*' | 'mod' | 'div' ) unionExpr) *
                  ;
To merge two or more ListValues , we use the union operator. To intersect the values of two or more ListValues we use the intersect operator.

unionExpr: intersectExceptExpr ( ('union' | '|') intersectExceptExpr ) *
         ;

intersectExceptExpr: instanceofExpr ( 'intersect' instanceofExpr ) *
                   ;
To check if a given object is an instance of some class, use:

instanceofExpr: unaryExpr ( 'instance' 'of' Identifier ) ?
              ;

unaryExpr: ('-' | '+') valueExpr
         | valueExpr
         ;

valueExpr: pathExpr
         ;

Internal functions:

All internal functions are implemented in StandardFunctions

  1. *position()*The current context position of the context item
  2. *last()*The context size
  3. *toXml()*Transform the context value into XML
  4. *define()*Define a function. Examples: 'define(("fatorial", "n"), if ($n> 0) then $n * fatorial($n-1) else 1)'
  5. new()*Instantiate a class that implements *br.com.zilics.archetypes.models.rm.utils.path.model.ObjectValue.
    Examples: '(1 to 5)/new("SomeClass", .)' , where:

        public class SomeClass implements ObjectValue {
                private final Integer i;
                public SomeClass(Integer i) {
                        this.i = i;
                }
               
                public Integer getI() {
                        return this.i;
                }
        }

User defined functions

To define a new function simply implement the interface PathFunction

public interface PathFunction {
        public ListValue evaluate(List<TreeNode> nodes, PathEvaluationContext context) throws PathEvaluationException;
{color:#0000cc}}


The evaluate() passes a list of TreeNode s as arguments to the function (that is, arguments could be lazy evaluated because TreeNode represents the abstract syntax tree of the argument). An utility class PathEagerFunction could be used to evaluate the arguments before calling evaluate() of the function itself.

public abstract class PathEagerFunction implements PathFunction {
        public abstract ListValue evaluate(PathEvaluationContext context, List<ListValue> params) throws PathEvaluationException;

        /**

Wiki Markup
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; * {@inheritDoc}

         */
        public final ListValue evaluate(List<TreeNode> nodes, PathEvaluationContext context) throws PathEvaluationException {
                List<ListValue> params = new ArrayList<ListValue>();
                for(TreeNode node : nodes) {
                        // Evaluate the arguments
                        params.add(node.evaluate(context));
                }
                return evaluate(context, params);
        }
{color:#0000cc}}



h2. Examples:

...

Result: Eval function "function" with parameters (1, 2).

Related Classes/Test Cases

Classes:

  1. br.com.zilics.archetypes.models.rm.utils.path.*;
  2. br.com.zilics.archetypes.models.rm.utils.path.context.*;
  3. br.com.zilics.archetypes.models.rm.utils.path.model.*;
  4. br.com.zilics.archetypes.models.rm.utils.path.parsed.*;
  5. br.com.zilics.archetypes.models.am.utils.path.*;
  6. The grammar br.com.zilics.archetypes.models.rm.utils.path.ArchPath.g

...