NAV

Introduction

Welcome to the realms of ATML3

This site describes the basic functions and commands of the ATML3 programming language. With this handy expression language, you can train an artificial intelligence to write your stuff. All of it. Just feed it structured data and the ATML3 engine will promptly churn it into a meaningful text in almost no time. But first off, you will need to tell the text-engine how to text for you. And that is what you do in an ATML3 training.

Sounds cool, but what can I actually do with it?

Your training contains reasoning: It will tell the text engine how to analyze and map your data. Once trained, the engine can draw conclusions from your data and build a text about them. You can define rules to influence wording, word construction and the appearance of many other aspects in the text (Properties & Methods). You can also tell the ATML3 engine in what way to mention the information it has concluded from your data (Sentences). Once you have your information planned and pinned down, you can do the fine-tuning and have grammar and apply to it (Containers & Container Parameters). Don’t forget microplanning and textplanning. That is also an aspect of ATML3 (Story Types).

What else do I need to work with ATML3?

First, you need an account at my.ax-semantics.com to work with ATML3. Don’t worry, it comes for free. Once you have an account, log in, go to your profile page and retrieve your API token there. You will also need your account unlocked for editing ATML3 and using our wizards. At the moment, you will have to contact us via Live-Chat: just click the speech bubble icon on my.ax-semantics.com and leave us a message. Alternatively you can send us an account request via Service Desk. Second, you will need one of our editors for ATML3. Choose one among the options at atml3.rocks. Further, you will need structured data about your topic. If you want to know how to integrate your data into AX, use the API documentation at apidocs.ax-semantics.com.

Properties

Let’s take an example, assume following JSON data set is given:

{
    "animal": "DOG",
    "color": "brown",
    "legs": 4,
    "breed": ""
}

Now we create four properties which check if the given fields are actually filled (truthExpression) and contain its values (mappingExpression):

{
    "DATA_animal": {
        "truthExpression": "str(#animal) != \"\"",
        "mappingExpression": "str(#animal)"
    },
    "DATA_color": {
        "truthExpression": "str(#color) != \"\"",
        "mappingExpression": "str(#color)"
    },
    "DATA_legs": {
        "truthExpression": "numeric(#legs) != 0",
        "mappingExpression": "numeric(#legs)"
    },
    "DATA_breed": {
        "truthExpression": "str(#breed) != \"\"",
        "mappingExpression": "str(#breed)"
    }
}

After that, we add a vocabulary to each property to set the content if a container is called. If you want to use the content of the property itself, just paste [property_name.value()] in the noun field of the vocabulary:

{
    "DATA_animal": {
        "truthExpression": "str(#animal) != \"\"",
        "mappingExpression": "str(#animal)",
        "voc": {
            "en-US": [{
                "noun": "[DATA_animal.value()]",
                "adjective": "",
                "headnoun": ""
            }]
        }
    },
    "DATA_color": {
        "truthExpression": "str(#color) != \"\"",
        "mappingExpression": "str(#color)",
        "voc": {
            "en-US": [{
                "noun": "[DATA_color.value()]",
                "adjective": "",
                "headnoun": ""
            }]
        }
    },
    "DATA_legs": {
        "truthExpression": "numeric(#legs) != 0",
        "mappingExpression": "numeric(#legs)",
        "voc": {
            "en-US": [{
                "noun": "[DATA_legs.value()]",
                "adjective": "",
                "headnoun": ""
            }]
        }
    },
    "DATA_breed": {
        "truthExpression": "str(#breed) != \"\"",
        "mappingExpression": "str(#breed)",
        "voc": {
            "en-US": [{
                "noun": "[DATA_breed.value()]",
                "adjective": "",
                "headnoun": ""
            }]
        }
    }
}

Maybe you have noticed it already, the data set contains a field which can be used as an adjective (color)! So now, we can just paste the DATA_color property as an adjective of the DATA_animal property.

{
    "DATA_animal": {
        "truthExpression": "str(#animal) != \"\"",
        "mappingExpression": "str(#animal)",
        "voc": {
            "en-US": [{
                "noun": "[DATA_animal.value()]",
                "adjective": "[DATA_color.value()]",
                "headnoun": ""
            }]
        }
    },
    "DATA_color": {
        "truthExpression": "str(#color) != \"\"",
        "mappingExpression": "str(#color)",
        "voc": {
            "en-US": [{
                "noun": "[DATA_color.value()]",
                "adjective": "",
                "headnoun": ""
            }]
        }
    },
    "DATA_legs": {
        "truthExpression": "numeric(#legs) != 0",
        "mappingExpression": "numeric(#legs)",
        "voc": {
            "en-US": [{
                "noun": "[DATA_legs.value()]",
                "adjective": "",
                "headnoun": ""
            }]
        }
    },
    "DATA_breed": {
        "truthExpression": "str(#breed) != \"\"",
        "mappingExpression": "str(#breed)",
        "voc": {
            "en-US": [{
                "noun": "[DATA_breed.value()]",
                "adjective": "",
                "headnoun": ""
            }]
        }
    }
}

That’s it for now, we have already created four valid properties with truth/mapping expressions and vocabularies! However, these properties are still pretty basic. If you want to see the true power of properties, just take a look at the next section “Methods”.

With properties, you can define truth and mapping conditions and vocabularies which refer to your data.

Thus a single property consists of three parts:

## Characters Please keep names of objects (like Property names) within valid characters. Allowed characters are “a-z, A-Z, 0-9, ö, ä, ü, Ö, Ä, Ü, ß, &, and _.”

Methods

With methods you can modify and format your own data to implement perfectly good stories.

Methods are used in mapping or truth expressions of properties and return following data types:

String methods

capitalize(string)

    capitalize("STRING")
        returns "String"

This method converts a string to its capitalized form.

convert_comma(input, divisor, lowerUnit, upperUnit)

    convert_comma(5300, 1000, "m", "km")
        returns "5,3 km"

    convert_comma(900, 1000, "m", "km")
        returns "900 m"

    convert_comma(120, 60, "Minuten", "Stunden")
        returns "2 Minuten"

This method takes a numeric value and converts it to a distance or time value.

convert_count(input, divisor, lowerUnit, upperUnit[, conjunction])

    convert_count(145, 60, "Minuten", "Stunden")
        returns "2 Stunden 25 Minuten"

    convert_count(45, 60, "Minuten", "Stunden")
        returns "45 Minuten"

    convert_count(350, 100, "Cent", "Euro")
        returns "3 Euro 50 Cent"

    convert_count(350, 100, "Cent", "Euro", "und")
        returns "3 Euro und 50 Cent"

This method takes a numeric value and converts it to a currency or date value. Optionally, a conjunction can be given.

cur_lang()

    cur_lang()
        returns "de", "es" or "en" or whatever language is currently used.

This method returns the current language in the current text generation process as an ISO 2-letter code.

currency(double)

    currency(2.1)
        returns the string "2.10"

    currency(1000000)
        returns the string "1,000,000.00"

    (culture: en-US)

This function converts a double to a currency string, depending on the current culture.

date_add(date, number, type)

    date_add("16.05.1983", 3, "years")
        returns "16.05.1986"

This method adds a time value to a given date and returns that new date. These types of times can be added:

date_convert(date, format)

Date:

    date_convert("16.05.1983", "yyyy-MM-dd")
        returns "1983-05-16"

Unix Time Stamp:

    date_convert("1478713441480", "yyyy-MM-dd")
        returns "2016-11-09"

This method converts a date value to a specific format and returns it as a string.

date_format(date)

    date_format("16.05.1983")
        returns "dd.MM.yyyy"

Returns a format string of a date value.

date_now([format])

    date_now()
        returns "13.06.2015"

    date_now("yyyy-MM-dd")
        returns "2015-06-13"

This method returns the current date.

Optionally, it is possible to set the format.

Default format: dd.MM.yyyy

format_number(number, decimal_place)

    format_number(2, 2)
        returns for example "2.00" (english) or "2,00" (german)

This method formats a number to enforce a certain number of decimal digits and converts it to the correct locale.

join(list[, delimiter])

    join([1, 2, 3, 4, 5])
        returns "12345"

    join([1, 2, 3, 4, 5], ", ")
        returns "1, 2, 3, 4, 5"

This method joins all elements of a list into a string.

Optionally, it is possible to set a delimiter.

lookup(entry, lookup_table_name)

    lookup("summer", "reifen_art")
        Looks up the entry "summer" in the lookup table "reifen_art" (of the current language) and
        returns its value as a string. If nothing is found, an empty string is returned.

Performs a lookup for fitting entries in a known lookup table.

Note: This method only return the noun as a string. For getting a whole vocabulary, use split_lookup() (see list methods).

lower(string)

    lower("STRING")
        returns "string"

This method converts a string to its lowercase form.

replace(string, old, new[, max])

    replace("old old old old", "old", "new")
        returns "new new new new"

    replace("old old old old", "old", "new", 2)
        returns "new new old old"

This method replaces all occurrences of a substring with a new stated substring.

Optionally, it is possible to set the number of times of replacements.

replace_last(string, old, new)

    replace("1, 2, 3, 4", ",", " and")
        returns "1, 2, 3 and 4"

This method replaces the last occurrence of a substring with a new stated substring.

re_get(list, pattern, direction, position)

    re_get([1, 2, 3], ".*", "l", 0)
        returns "1"

    re_get([1, 2, 3], ".*", "r", 0)
        returns "3"

    re_get([1, 2, 3], "4", "l", 0)
        returns an empty string

    re_get([1, 2, 3], ".*", "l", 1)
        returns "2"

This method searches for a regex pattern in a list of string elements and returns the string if there is a match at the specified position.

re_find(list, pattern, direction, position)

    re_find([1, 2, 30], "3.*", "l", 0)
        returns "30"

    re_find([10, 2, 3], "1.*", "r", 0)
        returns "10"

    re_find([1, 2, 3], "4", "l", 0)
        returns ""

This method searches for a regex pattern in a list of string elements and returns the string if there is a match. Otherwise an empty string is returned.

re_group(pattern, string[, i])

    re_group("String1(.*)String3", "String1String2String3")
        returns "String2"

    re_group("^.*(String2).*$", "STRING1STRING2STRING3", "i")
        returns "STRING2"

This method returns an existing group match within a string.

Optionally, it is also possible to set an ignoreCase flag (“i”).

Note: With this method, you can only extract one group.

re_replace(string, old, new)

    re_replace("old Old old Old", "(o|O)ld", "new")
        returns "new new new new"

This method searches for a regex pattern and replaces it with a new substring.

substring(string, index, length)

    substring("Hello world", 0, 1)
        Returns the substring "H" from the string "Hello world",
        which is the substring from index 0 with a length of 1 character.

    substring("Hello world", 5, 3)
        Returns the substring "wor" from the string "Hello world",
        which is the substring from index 5 (the w) with a length of 3 characters.

    substring("Hello world", 5)
        Returns the substring "world" from the string "Hello world",
        which is from position 5 to the end of the string.

This method extracts a substring from a string with a given index and length.

trim(string)

    trim("hallo welt")
        returns "hallo welt" (unchanged)

    trim("  hallo welt")
        returns "hallo welt" (stripped whitespace from the beginning)

    trim("hallo welt   ")
        returns "hallo welt" (stripped whitespace from the end)

    trim("  hallo welt   ")
        returns "hallo welt" (stripped whitespace from the beginning and the end)

this method cuts away trailing and preceding whitespaces from a string.

upper(string)

    upper("string")
        returns "STRING"

Converts a string to uppercase.

Numeric methods

count(list)

    count([1, 2, 10, 12, 14])
        returns 5

This method can be used to count the elements in a list.

date_day_of_year(date)

    date_day_of_year("31.12.2010")
        returns 365

    date_day_of_year("this_is_not_a_valid_date")
        returns 0

This method returns the day of the year of a given date as a numeric.

date_difference(date, date)

    date_difference("16.05.1983", "19.05.1983")
        returns 3

    date_difference("19.05.1983", "16.05.1983")
        returns -3

This method returns the difference between two dates as an integer number of days. The expected time format is dd.MM.yyyy.

len(type)

    len("string")
        returns 6

    len(1234567890)
        returns 10

Calculates the length of the string representation of a value.

list_pos(list, search_string)

    list_pos([$property1, $property2, $property3], "$property3")
        if truth($property3) is true:
            returns 2, because property3 is the third element in the list
        if truth($property3) is false:
            returns -1

    list_pos([$property1, $property2, $property3], "$property4")
        returns -1

    list_pos(["hallo", "welt"], "hallo")
        returns 0, because "hallo" is in the first position of the list

    list_pos(["hallo", "welt"], "ciaosen")
        returns -1, because the searched string "ciaosen" was not found in the list

This method finds the position of a property in a list. This one needs context. A list of properties (also called a group) may contain properties that evaluate to false while rendering, thus making the list shorter. To find out, at what position our property of interest is in the list, we can use this method.

max(list)

    max([1,2,3,6,4,5])
        returns 6

Extracts the maximum number from a list of numerics.

min(list)

    min([1,2,3,4,5,6])
        returns 1

This method returns the lowest number of a list of numerics.

month_no(month)

    month_no("Januar")
        returns 0, because january is the first month in a year

    month_no("February")
        returns 1, because february is the second month of a year

This method can be used to convert a month into a numerical representation

Note: This method only supports the german and english notation of months.

rnd_int(left_bound, right_bound)

    rnd_int(0, 10)
        returns a numeric between 0 and 10

This method returns a random integer number.

It requires a left bound as well as a right bound statement.

round(double[, decimals])

    round(0.6)
        returns 1

    round(0.144743575, 2)
        returns 0.14

This method rounds a numeric value. There’s an optional parameter to set the decimals to round to.

Note: The behavior of round() for doubles can be surprising: For example, round(2.675, 2) gives 2.67 instead of the expected 2.68. This is not a bug: It’s a result of the fact that most decimal fractions can’t be represented exactly as a doubles.

weekday_int(days)

    weekday_int(1)
        returns the integer 2 (Tuesday), if today is a monday

    weekday_int(5)
        returns the integer 6 (Saturday), if today is a monday

This method takes a numeric n between 1 and 7. It returns a numeric representation of the weekday of today + n days. The returned numeric is to be interpreted as follows:

Weekday Numeric
Monday 1
Tuesday 2
Wednesday 3
Thursday 4
Friday 5
Saturday 6
Sunday 7

weekday_no(day)

    weekday_no("Dienstag")
        returns number 2, because tuesday is the second day in a week

    weekday_no("monday")
        returns number 1, because monday is the first day of the week

This method can be used to convert a weekday into a numerical representation.

Note: This method only supports the german and english notation of weekdays.

Boolean methods

contains(type, list)

    contains(2, [1, 2, 3, 4, 5])
        returns true

    contains("welt", ["hallo", "welt", "!"])
        returns true

    contains("5555", ["hallo", "welt", "!"])
        returns false

    contains("hellblau", ["rot", "grün", "Blau"], "substring")
        returns true

    contains("hellblau", ["rot", "grün", "blau"])
        returns false because substring search is not active.

This method can be used to check if an element is inside a list.

has_entry(type, entry)

    has_entry("noun", "tire")
        returns true

    has_entry("noun", "thisIsNotAWord")
        returns false

This method checks if an entry contains as lemma in the lexicon in the given language.

in_range(number, left_bound, right_bound)

    in_range(6, 5, 10)
        returns true

    in_range(12, 5, 10)
        returns false

Checks if a numeric value lies between two other values.

is_date(string)

    is_date("16.05.1983")
        returns true

    is_date("string")
        returns false

This method checks if a string value is in a correct date format.

re_match(pattern, string[, i])

    re_match("String\d", "String1String2")
        returns true

    re_match("String\d", "STRING1STRING2", "i")
        returns true

    re_match("String2", "String1String2")
        returns false

This method returns true, if a string starts with a defined pattern.

Optionally, it is also possible to set an ignoreCase flag (“i”).

re_search(pattern, string[, i])

    re_search("String\d", "String1String2")
        returns true

    re_search("String\d", "STRING1STRING2", "i")
        returns true

    re_search("String2", "String1String2")
        returns true

This method returns true, if a string contains a defined pattern.

Optionally, it is also possible to set an ignoreCase flag (“i”).

List methods

collect(list, fieldname)

    collect([{ name: "gerät 1" }, { name: "gerät 3" }, { name: "gerät 2" }], "name")
        returns ["gerät 1", "gerät 2", "gerät 3"]

Takes a field from all objects in a list and returns those field values as a list.

count_uniques(list)

    count_uniques(["cat", "dog", "cat"])
        returns [{"value": "cat", "count": 2}, {"value": "dog", "count": 1}]

Returns a list with objects which contain following fields:

Supported types:

Values with other types will be ignored.

filter(list, object/lambda_expression)

Example list:

    [
        { "type": "goal", "team": "host", "score": "1-0" },
        { "type": "yellowcard", "team": "guest" },
        { "type": "goal", "team": "guest", "score": "1-1" },
        { "type": "redcard", "team": "host" },
        { "type": "goal", "team": "host", "score": "2-1" }
    ]

Example method calls:

    filter(list($list), { "type": "goal", "team": "host" })
        returns a list that includes the objects from the given input list that contain entries having type=goal and team=host,
        in our case entries with number one and five of the original list.

    filter(list($list), { "type": "yellowcard" })
        returns a list with entries that have type=yellowcard,
        in our example entry two of the original list.

    filter(list($list), [entry -> #entry.type == "yellowcard" ])
        returns the same thing as the last example but uses a lambda expression to match the object.
        In this example the entry variable of the lambda expression contains the complete object to be matched.

Filters a list of objects for the elements that match a given filter or lambda expression.

first(list, number)

    first([ 1, 2, 3, 4, 5 ], 3)
        returns [1, 2, 3]

    first([ 1, 2, 3, 4, 5 ], 5)
        returns [1, 2, 3, 4, 5]

    first([ 1, 2, 3, 4, 5 ], 6)
        returns also [1, 2, 3, 4, 5]

    first([ 1, 2, 3, 4, 5 ], -3)
        returns [3, 4, 5]

Gets n elements from a list, starting left.

intersection(list, list)

    intersection([1, 2, 3], [1, 2, 4])
        returns [1, 2]

Returns elements of two lists that are present in both lists.

map(list, lambda_expression[, context])

    map([1, 2, 3], [entry -> numeric(#entry) * 2])
        returns [2, 4, 6]

    map([{"score": "1-0", "player": "Dennis"}, {"score": "1-1", "player": "Baris"}, {"score": "2-1", "player": "Niki"}], [entry -> #entry.player])
        returns ["Dennis", "Baris", "Niki"]

    map([{"score": "1-0", "player": "Dennis"}, {"score": "1-1", "player": "Baris"}, {"score": "2-1", "player": "Niki"}], [entry, index, context -> #entry.player + " (" + #index + ") [" + #context + "]"], "context" )
        returns ["Dennis (0) [context]", "Baris (1) [context]", "Niki (2) [context]"]

    map(["Niki", "Sandro"], [entry, index, context -> #entry + \" (\" + #context[#index] + \".)\"], [5, 90])
        returns ["Niki (5.)", "Sandro (90.)"]

Applies a method to all elements of a list and returns a list of objects with the result of applying the lambda.

random_el(list, number)

    random_el([1, 2, 3, 4, 5], 2)
        returns for example [3, 5, 2]

    random_el(list($list), 5)
        returns for example [5, 3, 1, 2, 4]

This method gets random elements from a list.

range(list, index, count)

    range(["dog", "cat", "fish", "bear", "frog"], 3, 2)
        returns ["bear", "frog"]

    range(["dog", "cat", "fish", "bear", "frog"], 5, 2)
        returns an empty list

    range(["dog", "cat", "fish", "bear", "frog"], 3, 5)
        returns ["bear", "frog"]

    range(["dog", "cat", "fish", "bear", "frog"], 4, 1)
        returns ["frog"]

    range(["dog", "cat", "fish", "bear", "frog"], -1, 2)
        returns ["dog"]

    range(["dog", "cat", "fish", "bear", "frog"], 3, -2)
        returns ["fish", "bear"]

    range(["dog", "cat", "fish", "bear", "frog"], -10, -1)
        returns an empty list

This method returns a list with elements in a given range.

re_keep(list, pattern, direction[, position])

    re_keep(["xyz1", "abc", "xyz2"], "xyz.")
        returns ["xyz1", "xyz2"]

    re_keep(["xyz1", "abc", "xyz2"], "xyz.", "l", 1)
        returns ["xyz2"]

    re_keep(["xyz1", "abc", "xyz2"], "xyz.", "r", 1)
        returns ["xyz1"]

This method searches for a regex pattern in a list and returns a list of all matched elements. Optionally, a starting postition and a search direction can be given.

re_remove(list, pattern, direction[, position])

    re_remove(["xyz1", "abc", "xyz2"], "abc")
        returns ["xyz1", "xyz2"]

    re_remove(["xyz1", "abc", "xyz2"], "abc", "l", 1)
        returns ["xyz1", "xyz2"]

    re_remove(["xyz1", "abc", "xyz2"], "xyz.", "r", 1)
        returns ["xyz1", "abc"]

This method searches for a regex pattern in a list and returns a list of all elements that do not contain matched elements. Optionally, a starting postition and a search direction can be given.

sort(list[, fieldname/lambda_expression])

    sort([5, 4, 3, 2, 1])
        returns [1, 2, 3, 4, 5]

    sort([ {"type": "tor3", "minute": 80}, {"type": "tor1", "minute": 60}, {"type": "gelb", "minute": 10} ], "minute")
        returns a sorted list with original elements sorted by the minute key in them, thus ["gelb", "tor1", "tor3"]

    sort([ {"type": "tor3", "minute": 80}, {"type": "tor1", "minute": 60}, {"type": "gelb", "minute": 10} ], [a, b -> int(#a.minute) - int(#b.minute)])
        returns the same output but now by a lambda expression

Sorts a list numerically, a list of objects by a given field or by a lambda expression that compares the objects contained in the list.

split(string[, delimiter])

    split("string1 string2 string3")
        returns ["string1", "string2", "string3"]

    split("string1, string2, string3", ", ")
        returns ["string1", "string2", "string3"]

This method returns a splitted string as a list.

Optionally, it is possible to set a delimiter. The default delimiter is “ ”.

split_lookup(entry/entry_list[, delimiter], lookup_table_name)

    split_lookup("summer, winter", ", ", "reifen_art")
        splits the entry string at ", " and  looks up the entries "summer" and "winter" in the lookup table (of the current language) "reifen_art" and
        returns its value as a vocabulary list. If nothing is found, an empty list is returned.

    split_lookup( ["summer", "winter"], "reifen_art")
        returns the same output, only implemented with a list instead of a string and a delimiter.

Performs a lookup for fitting entries in a known lookup table.

Note: This method returns the result as a vocabulary list. For getting only the noun as a string, use lookup() (see string methods).

unique(list)

    unique([1, 2, 3, 1, 2])
        returns [1, 2, 3]

Returns a list with unique elements.

JSON object methods

next_event()

Searches in a list the next element from an index. Assume the following list:

    [
        { "id":"1", "type": "goal", "team": "host", "score": "1-0" },
        { "id":"2", "type": "yellowcard", "team": "guest" },
        { "id":"3", "type": "goal", "team": "guest", "score": "1-1" },
        { "id":"4", "type": "redcard", "team": "host" },
        { "id":"5", "type": "goal", "team": "host", "score": "2-1" }
    ]
   next_event( list($list), 2, { "type": "goal" } )
     - searches from index 2 (id = 3) the next event with type = "goal", which in this case is the element with id = 5 (index 4).

Parameters:

The method prev_event searches in the other direction. Is no event found, an empty object is returned.

prev_event()

Searches for the last occurrence of an element in a list before a given index. Assume the list:

    [
        { "id":"1", "type": "goal", "team": "host", "score": "1-0" },
        { "id":"2", "type": "yellowcard", "team": "guest" },
        { "id":"3", "type": "goal", "team": "guest", "score": "1-1" },
        { "id":"4", "type": "redcard", "team": "host" },
        { "id":"5", "type": "goal", "team": "host", "score": "2-1" }
    ]
   prev_event( list($list), 2, { "type": "goal" } )
     - Searches the next element with type = "goal" starting at index 2. Result would be the element with id = 1 (index 0).

Parameters

The method prev_event searches in the other direction. Is no event found, an empty object is returned.

nr5()

With this instruction a data set of the world knowledge (Project: Nummer5) can be accessed. Definition: nr5(aggregator, search_criteria) * aggregator - a string containing the name of the data aggregator in Nummer5 * search_criteria - an object that contains the search criteria in key/value form

    nr5("test_aggregator", { "key1": "bob", "key2": "alice" })
      - accesses the object, that is stored in the Nummer5 type "test_aggregator" and carries the value "bob" as key1 and "alice" as key2

    nr5("test_aggregator", { "key2": "python" })
      - accesses the object, that is stored in the Nummer5 type "test_aggregator" and carries the value "python" under key2

Return value is always a complete object from which properties can be selected by the property notation.

 properties: {
     "nummer5_test_1": {
            "mappingExpression": "nr5(\"test_aggregator\", {\"key1\": \"monty\" })",
            "truthExpression": "true",
            "voc": []
        },
        "nummer5_test_1_key_2": {
            "mappingExpression": "$nummer5_test_1.key2",
            "truthExpression" : "true",
            "voc": [ {noun: "[nummer5_test_1_key1.value()]" ]
        }
    }

In this example the property nummer5_test_1_key_2 would take the value “python” and the property nummer5_test_1 the value { key1: “monty”, key2: “python”, … } because that is defined in the test_aggregator.

With the following aggregator notation, the actual data aggregator name will be automatically extracted from the requests: nummer5_doc_type

    nr5("nummer5_doc_type", {"id":#uuid})

You can look up any path inside nr5 objects if you use the proper tricks. Look at the mapping expression in the example below. Here, we try to navigate into our number5 object, go into a child named “branch” and there go into a child named “subbranch”, which holds our key.

Note that ATML assumes that children of nr5 objects come as lists. You will have to add a dummy iterator “[0]” to every tier you want to walk through.

    "nummer5_test_2_key_2": {
            "mappingExpression": "$nummer5_test_2.branch[0].subbranch[0].key2",
            "truthExpression" : "true",
            "voc": [ {noun: "[nummer5_test_2_key2.value()]" ]
        }

pick_object()

This method picks an object at the end of a key path out of a data set.

pick_object(#object.list, "fieldName", "value 2")
     In a data structure like this:
         {
             "object:" {
                 "list": [
                     { "fieldName": "value 1", ... },
                     { "fieldName": "value 2", ... },
                     ...
                 ]
             }
         }
         the object with the fieldName "value 2" will be picked.

This is useful to pick elements out of deeply nested data structures.

Sentences

In the ATML3.0 training, sentences are defined. In the JSON tree, the structure is inside the sentences aray.

 sentences: [
    {
        name: "satz_001",
        trigger: [ "Auto" ],
        obligatory: true,
        variants: [ "Property is true and shows value|[true_property.value()]|2NEWLINE", ]
    },
    ...]

The sentence has the following fields:

For every chosen sentence a variant should be chosen and made to a RenderedSentence in the engine. The ATML3 containers in the variant are parsed. A sentence mostly consists of ATML3 containers and free text. The free text implicitly is converted to Text containers. Assume a training that is rendered with the following data set

 { "tiername": "hund", "tierfarbe": "braun", "anzahl_beine": "4" }

and fills propertys with the same names as the dataset keys. The following sentences result:

   Der [tiername] hat [anzahl_beine.value()] Beine.
   - Der Hund hat 4 Beine.

   [text:Der ][tiername][text: hat ][anzahl_beine.value()][text: Beine.]
   - Der Hund hat 4 Beine.

   [tiername,det=definite] hat [anzahl_beine.value()] Beine.
   - Der Hund hat 4 Beine.

Die Container die derzeit in der ATML3.0 Sprache existieren sind (anlehnung bei Namen an ATML2.5)

The containers are described in ther respective chapters. The general format is as follows:

Kinds of tags

ATML3 tags can be classified into the following:

Named Tags

   [text:The text that is to be rendered]
   [fail:The error message that is to be displayed]

Normal Tags

   [propertyName]
   [propertyName.value()]
   [propertyName,case=dat,adj=yes,det=definite]

All ATML-Tags can have parameters. To learn more about those options, go to the section containers.

Sentence Groups

Sentence groups can be used to apply selective operations on defined groups of sentences. A sentence group contains up to five different entries:

"sentenceGroups": [
  {
    "name": "sg1",
    "mode": "random",
    "number": 2,
    "sentenceNames": [
      "H1",
      "H1_2",
      "H1_3"
    ]
  },
  {
    "name": "sg2",
    "mode": "same",
    "reference": sg1",
    "sentenceNames": [
      "passende_Produkte",
      "passende_Produkte_2"
      "passende_Produkte_3"
    ]
  }
]

Story Mode

ATML3 is capable of rendering a sequence of events in a so called “story mode”. This mode behaves somewhat like a for loop does in programming. You will need this if you are looking to render a stream of events (goals in a soccer match or any other sorted event list).

prerequisites

a list of objects in your data json goal: [ { "player": "Harnik", "minute": 5, "type": "own_goal" }, { "player": "Werner", "minute": 66, "type": "goal" } ]

a meta sentence that is included in your “default” sentence group

{
 "name": "goals",
 "triggers": [ "Auto" ],
 "obligatory": true,
 "command": "[Meta:execute=Tor,items=event_list,iterator=CURRENT_EVENT,counter=CURRENT_INDEX]"
}

the meta command contains 4 different parameters (see below) * execute - used to point to a sentence group * items - ATML3 list property which contains the data * iterator - object to access the inner data from the itemlist * counter - internal counter for the story mode * an event story type

{
 "name": "Tor",
 "triggers": ["CURRENT_INDEX"],
 "sentenceOrder": [
 "goal_reg",
 "goal_own" ]
}

actual sentences that are rendered in this sentence group (goal_reg, goal_own)

{
 "name": "goal_reg",
 "triggers": [ "LOG_Tor_not_1_0" ],
 "obligatory": true,
 "variants": { "de-DE" : [
 { "text": "NEWLINE★ [VOC_MinuteTor;trailing:.] Minute: [VOC_Score_Tor] durch [VOC_SpielerTor]!" } ]
}

ATML3 properties (these are a bit different since we are iterating over objects)

a list property that contains the list of objects from above

"goal": {
 "mappingExpression": "list($spieldaten.goal)",
 "truthExpression": "int(count(list($spieldaten.goal))) >= 0",
 "voc": { "*" : [ { "noun": "[goal.value()]" } ] }
 }
2 meta properties for the story loop
"CURRENT_INDEX": {
 "mappingExpression" : "-1",
 "truthExpression" : "false"
 },
"CURRENT_EVENT" : {
 "mappingExpression" : "{}",
 "truthExpression" : "false"
 }

properties that point to the object in order to extract information from it

"TRIGGER_current_event_is_goal" : {
 "mappingExpression" : "",
 "truthExpression" : "$CURRENT_EVENT.event_type == \"goal\""
 },
"VOC_SpielerTor": {
 "mappingExpression": "$CURRENT_EVENT.player",
 "truthExpression": "true",
 "voc": { "de-DE" : [ { "noun": "[VOC_SpielerTor.value()]" } ] }
 },
"VOC_MinuteTor": {
 "mappingExpression": "$CURRENT_EVENT.minute",
 "truthExpression": "true",
 "voc": { "de-DE" : [ { "noun": "[VOC_MinuteTor.value()]" } ] }
 },
"VOC_TeamTor": {
 "mappingExpression": "$CURRENT_EVENT.team",
 "truthExpression": "true",
 "voc": { "de-DE" : [ { "noun": "[VOC_TeamTor.value()]" } ] }
 },
"VOC_ScoreTor": {
 "mappingExpression": "$CURRENT_EVENT.score",
 "truthExpression": "true",
 "voc": { "de-DE" : [ { "noun": "[VOC_ScoreTor.value()]" } ] }
 }

Containers

In this section the different containers and their parameters are described.

Some of the containers, for example PhraseContainer and ValueContainer are supposed to render vocabulary (or value, respectively). Containers can react to the truth value of properties.

Container basics

        [main_expression;trailing:);preceding:(]
        [main_expression,case=dat,prep=mit,det=definite;on,true=other_expression]

        [LIST_of_expressions.all()]
        [LIST_of_expressions.random(2)]

Containers go into sentences and their purpose is to “summon” atml rules, values and vocabulary into the sentences. They point at a property to be summoned into the text, but also define how the grammar module will inflect and construct the output of the property, so it will fit into the syntax of the sentence.

Containers are separated from the rest of the sentence by brackets [ and ]. They consist of a main expression and parameters. Parameter. The main expression can either be a property, a grouped property, a grammar container or text. All types except text come with a set of grammar subparameters.

Remember:

Fail Container

    [Fail:Der Wert load_index ist nicht im gültigen Wertebereich;On:fehlerbedingung=true]
    The error message appears in the myAX if the container is rendered. The rendering can be controlled by On and Off container parameters.

If this container is rendered in a sentence, the rendering of the text itself is aborted with an error message to the myAX. The error message is then displayed to the user.

The container does not lead to output in the text itself.

Grammar Container

This container can be used to render words with their grammatical function and preset grammatical information.

    [g:verb=gehen,num=s,person=1st;preceding:ich ]
        - renders "ich gehe"

    [g:noun=Charakter,num=p]
        - renders "Charaktere" because nominative is the default case and plural was set as numerus.

    [g:adjective=niedlich,case=gen,num=s,gender=f,det=def]
        - renders "niedlichen", as in "der niedlichen Katze"

    [g:determiner=def,num=s,gender=f]
        - renders "die"

The grammar container is intended to be used to render words, from which other words can inherit grammatical information. This can be useful if the case of something changes when a word giving grammatical information is replaced by a synonym or adjective groups which change the numerus of their noun shall be rendered.

Some defaults are set, all other fields must be filled:

The first two are for adjectives in the default position (here “und” and “sowie”). The default position is controlled by the language of the text. For german, the default position is in front of the noun, in spanish it is behind.

The other two conjunctions are for the non default position (here “KOMMA” and “oder”). They are necessary for spanish and french, for example.

The grammar container can be used to render verbs, if a “Du/Sie” switch was to be implemented.

    Den Duft [g:verb=riechen,grammar-from=reader] [appeal:reader,id=reader] direkt nach der Anwendung.
      - This sentence renders to "Den Duft riechen Sie direkt nach der Anwendung"  if the engine renders in SIE mode
      - This sentence renders to "Den Duft riechst du direkt nach der Anwendung"  if the engine renders in DU mode
      - This sentence renders to "Den Duft riecht Ihr direkt nach der Anwendung"  if the engine renders in IHR mode

    Robben [g:verb=treffen,person=3rd,tense=past] mit dem Ball.
      - Robben traf mit dem Ball

    Robben [g:verb=treffen,person=3rd] mit dem Ball.
    Robben [g:verb=treffen,person=3rd,tense=present] mit dem Ball.
      - Robben trifft mit dem Ball

With grammar-from you can inherit stuff from other containers. Directly defining a parameter overrides the inheritance (for example person=3rd will override the inherited person).

If you want to explicitly inherit single properties you can use the following parameters:

Group Container

Assume the property “group” has the mappingValue [“rot”, “gelb”, “grün”, “blau”]. The container looks as follows:

  [group.all()]
    - renders all members of the group, namely "rot, gelb, grün, blau"

  [group.best(3)]
    - renders the first 3 elements of the group, namely "rot, gelb, grün"

  [group.last(3)]
    - renders the last 3 elements of the group, namely "gelb, grün, blau"

  [group.all(),conj=oder]
    - renders all elements of the list but inserts a conjunction before the last element: "rot, gelb, grün oder blau" . The conjunction is free text.

  [group.range(1, 2)]
    - renders the second and third element of the group (index is 0-based): "gelb, grün"

  [group.all_random(),conj=oder]
    - like .All() but randomizes the order of the elements.

A group container outputs a part of a list. There are several selectors available, namely:

The group container also knows grammatical properties:

Phrase Container

  [wort]
    - renders "Hund"

  [wort,case=gen]
    - renders "Hundes"

  [wort,case=gen,det=indefinite]
    - renders "eines Hundes"

  [wort,case=gen,det=definite,prep=mit]
    - renders "mit des Hundes"

  [wort,case=dat,adj=yes,det=definite,prep=mit]
    - renders "mit dem braunen Hund"

  [wort,pronoun=demonstrative,case=Dat,prep=mit]
    - renders "mit diesem"

A phrase container renders the vocabulary of a property. The property can itself contain containers. The vocabulary is rendered with grammatic properties.

Defaults:

Permitted values for the parameters:

Text Container

  [text:hallo, welt!]
    - renders "hallo, welt!"

A text container simply renders a string.

  [text:dies ist ein test;capitalize;on,merkmal=true]
    - renders "Dies ist ein test" if the boolean value of the property "merkmal" is true.
    - renders nothing otherwise

Rendering of simple text by a container is useful if container parameters need to be applied to that text.

Value Container

Some examples:

              [merkmalsname.value()]
                - renders the value of a property, case=Nom and det=none

              [merkmalsname.value(),case=dat]
                - renders the value of a property, overrides case with Dativ and does not use a determiner

              [merkmalsname.value(),case=dat,det=definite]
                - renders the value of the property with a definitite determiner and in Dativ.

              [merkmalsname.value(),use_numerals=true]
                - renders the value and if it's a numerical value (eg 4) it will perform a lookup to find out if it's a number with a special word if
                  special words are used in the current language by convention (eg in German: 0 = null, 1 = ein, 2 = zwei, ... till 12 = zwölf, theese may
                  differ in other languages).

              [merkmalsname.value(),use_numerals=true,numeral_type=cardinal]
                - use cardinal or ordinal to switch what kind of number to render.

Value Containers just render the value (defined by the mappingExpression) for a property. They ignore the vocabulary. They can add grammatical informations and render with a case and determiner. Default values are case = nom and determiner = def.

The cases that exist are language dependent, eg nom, gen, dat, acc in German. Determiners might be

If a numeric property is rendered, use_numerals=true can be used to render number words in the current language. This is not implemented for all supported languages. If a numeric property is rendered, singular and plural can be inherited from the container using grammar-from or grammar-from-num.

Container parameters

Container parameters can be attached to a container to add instructions or information to the container.

Alternative

    [text:;alt:Nix gerendert]
     - renders "Nix gerendert"

   [no_vocabulary_property;alt,text=Nix gerendert]
     - renders "Nix gerendert" if no_vocabulary_property has no vocabulary or is false. (Use syntax of example 1)

The container parameter alt (for alternative) is used to render an alternative text, if the container would not render anything otherwise.

List

    [Gruppe.all();list]
         - Generates a markdown list like this:
             * Element_1
             * Element_2
             * Element_3

    [Gruppe.all();list,type=ordered]
         - Generates a markdown list like this:
             1. Element_1
             2. Element_2
             3. Element_3

    [Gruppe.all();list,format=HTML]
         - Generates a HTML list like this:
             <ul>
                 <li>Element_1</li>
                 <li>Element_2</li>
                 <li>Element_3</li>
             </ul>

    [Gruppe.all();list,format=HTML,type=ordered]
         - Generates a HTML list like this:
             <ol>
                 <li>Element_1</li>
                 <li>Element_2</li>
                 <li>Element_3</li>
             </ol>

    [Gruppe.all();list,format=HTML,id=Test]
         - Generates a HTML list with an id:
             <ul id="Test">
                 <li>Element_1</li>
                 <li>Element_2</li>
                 <li>Element_3</li>
             </ul>

    [Gruppe.all();list,format=HTML,id=Test,type=ordered]
         - Generates a HTML list with an id:
             <ol id="Test">
                 <li>Element_1</li>
                 <li>Element_2</li>
                 <li>Element_3</li>
             </ol>

    [Gruppe.all();list,format=BB]
         - Generates an BBCode list like this:
             [list]
                 [*]Element_1
                 [*]Element_2
                 [*]Element_3
             [/list]

    [Gruppe.all();list,format=BB,type=ordered]
         - Generates an BBCode list like this:
             [list=1]
                 [*]Element_1
                 [*]Element_2
                 [*]Element_3
             [/list]

The list parameter makes a group into a list of elements. By default, a markdown list will be generated, with the optional style-parameter the format can be switched to HTML or BBCode. This is however discouraged because we try to render everything through markdown and process it into other output types later.

Additionally an ID can be set to the element.

Capitalize

   [text:ich bin kleingeschrieben;capitalize]
     - renders "Ich bin kleingeschrieben"

   [hund_wort,prep=mit,case=dat;capitalize]
     - renders "Mit dem Hund", if the property hund_wort renders the vocabulary "Hund"

capitalize is a container parameter that forces the first letter of the rendered string to be upper case.

IMG

    [text:https://www.google.de/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png;img]
      - Generates a markdown image like this:
          ![](https://www.google.de/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png)

    [text:https://www.google.de/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png;img,text=alt text]
      - Generates a markdown image like this:
          ![alt text](https://www.google.de/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png)

    [text:https://www.google.de/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png;img,title=This is the google logo]
      - Generates a markdown image like this:
          ![](https://www.google.de/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png "This is the google logo")

    [text:https://www.google.de/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png;img,text=alt text,title=This is the google logo]
      - Generates a markdown image like this:
          [alt text](https://www.google.de/images/branding/googlelogo/1x/googlelogo_color_272x92dp.png "This is the google logo")

The img parameter generates an image.

Possible sub-parameters are:

Keyword

   [text:der goodyear 500;keyword,id=1,alt=der Reifen]
         - renders [Key,1,der goodyear 500,der Reifen]
         Depending on the defined keyword density the string `der goodyear 500` will be replaced with `der Reifen`.

With the keyword parameter you can define multiple keywords within your generated texts. Every defined id is depending on the given keyword density.

Kill

   [text:hallo] [text:;kill] [text:welt]
     - prevents rendering, because the second container does not render anything and carries the Kill parameter

kill is a parameter that prevents a sentence from being rendered if the container does not render to a text.

Lower

    [text:ICH BIN GROSSGESCHRIEBEN;lower]
     - renders "ich bin grossgeschrieben"

   [hund_wort,prep=mit,case=dat;lower]
     - renders "mit dem hund", if the property hund_wort renders "Hund"

lower is a parameter that forces the rendered string of a container to be all lower case.

On

   [text:test;on,true=bool_property]
     - only renders "test", if the property bool_property is true.

   [text:test;on,false=bool_property]
     - only renders "test", if the property bool_property is false.

on is a container parameter that activates or deactivates according to a condition.

On_random

   [text:i'm here;on_random,percentage=25]
         - will output "i'm here" with a probability of 25 percent

       [text:i'm here;on_random,percentage=LOGIC_percentage]
         - will output "i'm here" with a probability of $LOGIC_percentage percent and interpretes LOGIC_percentage as a numeric

on_random is a container param that will throw away a container param randomly.

Preceding

   [text:welt;preceding:hallo ]
     - renders "hallo welt"

   [drei.value();preceding:,text=StückzahlDOPPELPUNKT ]
     - renders "Stückzahl: 3", if the property drei renders to 3.

preceding is a container parameter that is used to insert text in front of a rendered string in a container.

Raw

  [text:https://www.google.de;raw]
    - renders "https://www.google.de" instead of "https://www.Google.De"

raw is a container parameter that forces ignoring the text modulation part.

Trailing

   [text:hallo;trailing: welt]
     - renders "hallo welt"

   [drei.value();trailing,text= Stück]
     - renders "3 Stück", if the property drei renders to 3

trailing is a container parameter that is used to insert text behind a rendered string in a container.

Upper

    [text:render me as upper case;upper]
     - renders "RENDER ME AS UPPER CASE"

upper is a parameter that forces the rendered string of a container to be all upper case.

URL

The url parameter generates an hyperlink.

Possible sub-parameters are:

    [text:https://www.google.de;url]
        - Generates a markdown link like this:
            [https://www.google.de](https://www.google.de)

    [text:https://www.google.de;url,text=click here]
        - Generates a markdown link like this:
        [click here](https://www.google.de)

    [text:https://www.google.de;url,title=This is a link to google]
        - Generates a markdown link like this:
            [https://www.google.de](https://www.google.de "This is a link to google")

    [text:https://www.google.de;url,target=_blank,rel=nofollow]
        - Generates a markdown link like this:
            [https://www.google.de](https://www.google.de){:target="_blank" rel="nofollow"}

    [text:https://www.google.de;url,text=click here,title=This is a link to google]
        - Generates a markdown link like this:
            [click here](https://www.google.de "This is a link to google")

Void

   [dog_phrase,id=test123;void]
     - renders nothin but can be referenced by grammar-from=test123 and will deliver it's grammatical properties

void is a container parameter that prevents a container from rendering an actual string but preserves its grammatical properties. It is mostly used as a reference for grammar containers.

Source

[hund_wort,prep=mit,case=dat;source:mit dem Hund]

source is a container parameter that can be filled with an intended output.

Keyword

   [text:der goodyear 500;keyword,id=1,alt=der Reifen]
     - here the engine will either display "der goodyear 500" or the alternative text "der Reifen"
       depending on the random selection.

To create a keyword, you need to set the keyword parameter with an ID and an alternative text within a container. The ID is needed for defining multiple keywords. The engine will choose randomly a selection of defined keywords in consideration of the density and deviation. Both can be adjusted in the advanced content project configuration.

Story types

Story types determine the order of the sentences you want to set.

ATML3 first tries to select a story type that is not named “default” and whose triggers are true (BEWARE: sentences need only one true trigger, for story types all triggers must be true). If none fits, the story type named “default” will be chosen.

name: "default",
"triggers": ["my_property_01"],
"sentenceOrder": [ "sentence_01", "sentence_02", "sentence_03" ]

name: "story_type_01",
"triggers": ["my_property_02"],
"sentenceOrder": [ "sentence_03", "sentence_02", "sentence_01" ]

In this example, story type "story_type_01" would be chosen if and only if the truth value of the property "my_property_02" is true. Otherwise, the "default" story type would be chosen.