Formal Description of Citeck Records Attribute Syntax
Terminology
Context — a region delimited by brackets or quotes
{},[],(),"",'', or not delimited at all (the root area or root context);Alias — a pseudonym for an attribute. Example: in the expression
someAlias:name, someAlias is the alias and a possible evaluation result issomeAlias:"Contract No. 2";Character escaping — prefixing a character with
\. Required when a special character must be treated as a regular character;Special character — a character that has a special meaning in a given context.
Scalar — a terminal attribute that cannot contain nested attributes. Can be one of
?id,?str,?disp,?num,?assoc,?localId,?bool,?json.
Note
Escaping special characters is only required in the current context and is not needed in nested contexts.
Description
General form of an attribute:
path0[].path1{INNER}|proc0(arg0,arg1)|proc1(arg0,arg1) (1)
path0[].path1 — a path of attributes. Path elements are joined by a dot. If a dot is part of an attribute name, it must be escaped.
All attributes in the path except the last have exactly one inner attribute without post-processors or an alias. The last attribute in the path can have any number of nested attributes but has no alias. All attributes in the path except the first have no post-processors. The first attribute in the path can have any number of post-processors, specified at the end after {INNER}. Any element in the attribute path can have a [] suffix, which when present means the attribute is multiple.
{INNER} contains nested attributes with aliases, separated by commas. The alias is optional. If absent, the first name in the attribute path is used for the result.
Example value of {INNER}:
{alias0:attribute0,alias1:attribute1,attribute2}
In aliasN, the special characters are , and :. Instead of attributeN, syntax (1) is allowed but with commas , escaped, and if no alias is present, : must also be escaped (see Note 1). If the alias equals the first element in the attribute path, it is equivalent to having no alias.
Instead of {INNER}, when there is only one nested attribute with no alias or processors, notation without curly braces is allowed. In that case, if the nested attribute is not a scalar, a dot is prepended. Nothing is prepended before a scalar since it already contains the separator character ?.
Examples:
name?str == name{?str}
name.title?str == name{title{?str}}
If the attribute ends with the scalar ?disp (att0?disp or att0{?disp}), the ?disp suffix may be omitted since it is the default scalar.
Example:
name?disp == name
When describing an attribute, post-processors are allowed; they are called with the result of the attribute evaluation:
proc0(arg0,arg1)
procN — post-processor name;
argN — arguments separated from each other by commas. Values analogous to the JSON format are allowed — https://www.json.org/json-en.html — but with the option to use single quotes instead of double quotes for strings;
Post-processors are chained using the | symbol and executed from left to right, analogous to a Unix pipeline. Post-processors can be part of any attribute at any nesting level.
For the “or” type post-processor, additional syntax using ! is available. Possible values after !:
A value in double or single quotes means a constant string; (
some!'constant' == some|or('constant'))When no value is present, the parser selects the appropriate argument based on the scalar before the
!sign:
?bool! ->
false?json! ->
{};?num! ->
0;otherwise ->
"".
null means an empty value; (
some!null == some|or(null))true or false — a boolean value; (
some!true == some|or(true))If the first character is a digit — a numeric value; (
some!123 == some|or(123))If none of the above options matched, it is assumed that an attribute name is specified, which should be returned if the result of evaluating the attribute before
!is null; (some!other == some|or('a:other'))
Between parts of an attribute (alias, path, nested attributes, post-processors, arguments), any number of whitespace characters (\n, \t, \r, ) are allowed.
Attribute model:
SchemaAtt {
alias: String,
name: String,
multiple: Boolean,
inner: List<SchemaAtt>,
processors: List<AttProcDef>
}
Post-processor model:
AttProcDef {
type: String,
arguments: List<DataValue>
}
DataValue — any JSON type — https://www.json.org/json-en.html