Things you need to know about properties and ATML3 containers and properties

Sep 24 2015

To understand how properties and containers in ATML3 interact, we first need to look at their features and functions.


A property is similar to a global variable in a regular programming language. A property stands for three different kinds of values:

  • truth value,
  • mapping value,
  • vocabularies.

The truth value of a property is a Boolean value that indicates if the property's mapping value and vocabularies are valid or not. The truth value is defined by the property's truth expression. A truth expression may never return a value besides Boolean.

The mapping value of a property is a non-Boolean value that maps data to the property. This data can be used in a text or in other properties. The data types available in ATML3 are "string", "numeric", "list" and "object". The mapping value is defined by the mapping expression. The mapping process is only executed if the truth value of the property is true.

The vocabularies are a constructed natural language value of a property - in linguistic terms: a noun phrase. Possible are simple NPs, complex PPs and even complete sentences. The vocabularies contain one or multiple noun-adjective combinations in one or more languages.

A property may have no mapping value (which means that the mapping expression is empty or not stated at all) and may have no vocabulary (which means that there are no vocabularies defined for one, multiple or all languages). This can be useful if the property is only used for drawing logical conclusions or as a trigger for a product group or sentence.

In this document, it is discussed how properties and ATML3 containers interact with each other. To understand those interactions you need to know about truth values, mapping values and vocabularies since different containers will access different parts of a property.

Examples for properties: "DATA" properties

It is recommended to name a property that is used to map input data from my-ax as "DATA_xyz", for example:

  • "DATA_name",
  • "truthExpression: #name != "" ",
  • "mappingExpression: #name",
  • "vocabulary (de-DE): noun: [DATA_name.value()]".

What's happening here is a very basic use case. When accessing something in your input data, you usually mark the key in your input JSON with a "#". So, "#name" will map the value for "name" of your input JSON.
The expression "#name != "" " will check if the value of the input key returns an empty string, the relational operator "!=" makes the expression Boolean.
The vocabulary for this property contains one element for German and returns the result of the mapping expression as a noun. This element is called a value container, an ATML3 element that renders the value of a property. More about this will be discussed later (see "Value Container").

"DATA" examples that will be used with the stated property return these example results:


  • The truth value is true (because "Couch" != "").
  • The mapping value is "Couch" (type: "string").
  • The vocabulary renders the word "Couch" for German.
  • The vocabulary renders nothing for English.

Data: { "name": "" } or { "name": null} or

  • The truth value is false (because null or nonexisting keys are the same as empty strings).
  • The mapping value is not present because the property is not true.
  • The vocabulary does not render anything because the truth value is false.

Examples for properties: DATA Properties (II)

  • "DATA_price"
  • truthExpression: "#flight_price != \"\" and #hotel_price != \"\""
  • mappingExpression: "numeric(#flight_price) + numeric(#hotel_price)"
  • vocabulary (de-DE): "noun: [DATA_price.value()] EUR"

Two fields from the input are used as a numeric value and are added up. In ATML3, it is mandatory to explicitly cast the input values because their data types can not be predetermined. This is the case because the JSON input is dynamically typed and types of JSON keys can not be enforced.

Imagine the formula in our mapping expression were "#flight_price + #hotel_price". This could lead to an incorrect use of data types.


The result would be 410.0 – a number.


The result would be "150.0260" – a string. In most dynamic languages, the "+" operator results in a concatenation when the left operand is a string. If the left operand is a number, the "+" operator leads to an addition. This inherent behaviour contains a great risk of misunderstandings and incorrect usage.

Solution: Static typing through explicit casting

For this reason, the best practice in ATML3 is to explicitly cast the correct data types. Our explicit formula would look like this: "numeric(#flight_price) + numeric(#hotel_price)". The resulting value, 410, would be generated by adding up the two clearly indicated numeric values for both data samples.

Examples for properties: "VOC" properties

We recommend to name a property used to generate some kind of vocabulary with the prefix "VOC_". Such properties can be used to render adjective and noun combinations (or noun phrases etc.) in sentences. They can interact with other properties.

  • "VOC_hotel_with_adjective"
  • truthExpression: "#hotel_adjective != "" "
  • mappingExpression: "#hotel_adjective"
  • vocabulary (de-DE): "noun: Hotel, adjective: [VOC_hotel_with_adjective.value()]"

In this case we are using the value of the property for rendering the adjective.


The vocabulary renders something like "schönes Hotel" or "schöne Hotels" or "den schönen Hotels", depending on the grammatical context of the noun phrase (see "Phrase Container").

Examples for properties: "GROUP" properties

We recommend to name properties containing a list of things or properties as group properties. Group properties should be used to render enumerations of things like the properties of a product.

  • "GROUP_flavor"
  • truthExpression: "count(list(#flavors)) != 0"
  • mappingExpression: "list(#flavors)"

In this case, the property contains a list of flavors taken from the input, if the list at this point has more than 0 elements.


Calling this group would render "kiwi, pear, apple". This can be modified to something like "kiwi, apple and banana" by modifying the parameters of the group container. This will be further explained later (see "Group Container").

Data: { "flavors": [] } or

Renders nothing because the truth value becomes false.

Sentences and Containers

In this part, we will use what we have learned about properties to use data input in sentences. In a previous tutorial, we have learned how to create a sentence with a variant. So let's just skip to the actual ATML3 code.

Data: { "flavors": [ "mango", "pea", "apple" ], "name": "tea" }

  • Properties:
  • "GROUP_flavor"
  • truthExpression: "count(list(#flavors)) != 0"
  • mappingExpression: "list(#flavors)"

  • "VOC_Flavor_new"

  • truthExpression: "true"
  • vocabulary (en-US): "noun: flavor, adjective: new"

  • "VOC_name"

  • truthExpression: "#name != "" "
  • mappingExpression: "#name"
  • vocabulary (en-US): "noun: [VOC_name.value()]"

Sentence: "With [VOC_Flavor_new,det=def,adj=yes,grammar-from=flavors] [GROUP_flavor.Best(2),conj=and,id=flavors], this [VOC_name] is a great product."

Basically, this would render a sentence like: "With the new flavors mango and pea, this tea is a great product".

An in-depth explanation about this sentence will be given in the next chapter.

Basics for Containers

A container in a sentence is marked by square brackets.
There are different types of containers, for example: * Value Container, * Phrase Container, * Text Container, * Group Container, * Grammar Container, * Appeal Container.

All of these containers will be explained in detail in later tutorials. This section contains some general information about the mechanisms of containers in ATML3.

At first glance, a container includes a sequence of commands. Those commands are separated by semicola (;) and each command can have a parameter added, separated by a comma. A general example of an ATML3 container using the aforementioned sequence of commands is the following:

"[GROUP_flavor.Best(2),conj=and,id=flavors;On,LOGIC_name_flavors=true;Alt:many flavors]"

This container consists of three commands: * "GROUP_flavor.Best(2),conj=and,id=flavors", * "On,LOGIC_name_flavors=true", * "Alt:many flavors", which mean: * render "GROUP_flavor"'s first two entries, * when "LOGIC_name_flavors" is not true, nothing will be rendered, * if there is no current rendering result, render "many flavors".

Explaining our Example

Mechanisms behind the above sentence with the group and the phrase container:

Group Container: "[GROUP_flavor.Best(2),conj=and,id=flavors]"

This container is rendered first because it is not referenced by any "grammar-from" reference and can thus be directly executed.
The "Best(2)" operation means that the first two elements of the group that can be rendered (because of a true truth expression) will be rendered. If the group would e.g. contain a list of properties instead of plain strings, a property that was false would be skipped, selecting the best two. Possible operations for group containers are: * Best(n): first n elements, * Last(n): last n elements, * All(): all elements, * AllRandom(): all elements, but in random order, * Range(n,m): render from element n to m and leave out those that cannot be rendered.

The parameter "conj" sets the conjunction "and" between the last two elements. If this parameter is not given, the last conjunction will be a comma ("apple, peach, mango" instead of "apple, peach and mango").

The parameter "id" names the container so that it can be referenced by other containers to inherit its grammatical properties. Grammatical properties inherited from a group container are singular or plural, depending on the amount of items that were actually rendered.

Phrase Container: "[VOC_Flavor_new,det=def,adj=yes,grammar-from=flavors]"

This container is rendered after the group container because it needs the grammatical information (singular or plural). So, the container will be rendered as "new flavor" if only one element is rendered by the group container or as "new flavors" if the group container rendered multiple items.

As you probably guessed, "grammar-from" defines the container name from which this container should get its grammatical information.

"adj=yes" will enable rendering of the noun phrase with an adjective. Without this, it would only be "the flavor" instead of "the new flavor".

"det=def" sets the determiner of the noun phrase to a definite determiner ("the"). In this case, leaving out "det=def" would give you "new flavor" instead of "the new flavor". "det=indef" would give you "a new flavor". A few possible values for determiners are: * none: default * def: definite * indef: indefinite * your: your

Phrase Container: "[VOC_name]"

Basically the same as "VOC_Flavor_new" but without any parameters.

Value Container: "[VOC_name.value()]"

A value container is usually a container without parameters that is used to render a value. Value containers are often used in vocabularies or to print out numerics. From a value container rendering a numeric grammatical information about singular or plural ("== +/- 1" and "!= +/- 1") can be inherited.
In our case, the value container just renders the noun and directly renders the data from the input without any modification.


You have learned a lot about properties in this tutorial and learned about three types of containers, the group container the phrase container and the value container.

Category: ATML3 Tagged: tech atml3 tutorial