More on the realise function
This topic shows you how to use the realise function to generate sentences from different kinds of data.
Contents
Realise a JSON array
This example uses the following two JSON arrays:
{"people":[ { "name":"John", "location":"London"}, { "name":"Anna", "location":"New York" }, { "name":"Peter", "location":"New York"} ], "cars":{ "NYcars":{"make":"Ford", "number":4, "location":"New York" }, "Londoncars":{"make":"Volvo", "number":2, "location":"London" } }}
and the following lex rule with “Abode” as the value for classes
:
<S id="LexRule1" classes="Abode"> <Subj word="{{msg.name}}"/> <VP word="live"/> <Obj word="{{msg.location}}" preposition="in"/> </S>
The following ATL script generates sentences from the lex rule:
[[realise((WholeJSON.people,'Abode'))]]
The result is:
John lives in London, Anna lives in New York. Peter lives in New York.
Each element in the JSON array is input in turn to the lex rule with classes="Abode"
and a sentence is generated. Three sentences are generated because there are three objects in the JSON array.
Realise a filtered JSON array
This example uses the same data and lex rule used for Realise a JSON array above.
To generate from a subset of the JSON array, nest the filter function the ATL as follows:
[[realise((filter(WholeJSON.people, p -> p.location == 'London'),'Abode'))]]
This selects only those elements in WholeJSON.people
with value ‘London’ for the location
key.
The generated output is:
John lives in London.
This time only one sentence is generated because the filter blocks the data for the two objects with "location":"New York"
.
Realise a JSON object
This example uses the following JSON data:
{"people":[ { "name":"John", "location":"London"}, { "name":"Anna", "location":"New York" }, { "name":"Peter", "location":"New York"} ], "cars":{ "NYcars":{"make":"Ford", "number":4, "location":"New York" }, "Londoncars":{"make":"Volvo", "number":2, "location":"London" } }}
and the following lex rule:
<S id="LexRule2" classes="Car"> <Subj> <Spec word="the"/> <N word="{{msg.location}}"/> <N word="office"/> </Subj> <VP word="have"/> <Obj> <Number int="{{msg.number}}"/> <N word="{{msg.make}}"/> </Obj> </S>
To generate from a JSON object that is not an array, nest the values function in the ATL as follows:
[[realise((values(WholeJSON.cars),'Car'))]]
The above ATL uses the values
function in realise
to transform the JSON object WholeJSON.cars
into a list of two objects. It uses a lex rule with classes="Car"
to generate a sentence from each item in the list.
The generated output is:
The New York office has 4 Fords. The London office has 2 Volvos.
The JSON object is converted into a list and each item in the list is generated with the classes="Car"
lex rule.
Realise a JSON array with mapping
This example uses the following JSON data:
{"people":[ { "name":"John", "location":"London"}, { "name":"Anna", "location":"New York" }, { "name":"Peter", "location":"New York"} ], "cars":{ "NYcars":{"make":"Ford", "number":4, "location":"New York" }, "Londoncars":{"make":"Volvo", "number":2, "location":"London" } }}
and the following lex rule:
<S id="LexRule1" classes="Abode"> <Subj word="{{msg.name}}"/> <VP word="live"/> <Obj word="{{msg.location}}" preposition="in"/> </S>
To generate from a JSON array with mapping, nest the map function in the ATL as follows:
[[realise((map(WholeJSON.people, f -> lower(f)),'Abode'))]]
The above ATL uses the map
function to apply the lower function to each item in WholeJSON.people
to transform it into lowercase. Then realise
generates text from a lex rule with classes="Abode"
.
The generated output is:
John lives in london. Anna lives in new york. Peter lives in new york.
The city names in the output have been converted to lowercase. Notice that the sentences still begin with a capital because they are generated with a Sentence lex rule.
Realise a sorted JSON object
This example uses the following JSON data:
{"people":[ { "name":"John", "location":"London"}, { "name":"Anna", "location":"New York" }, { "name":"Peter", "location":"New York"} ], "cars":{ "NYcars":{"make":"Ford", "number":4, "location":"New York" }, "Londoncars":{"make":"Volvo", "number":2, "location":"London" } }}
and the following lex rule:
<S id="LexRule2" classes="Car"> <Subj> <Spec word="the"/> <N word="{{msg.location}}"/> <N word="office"/> </Subj> <VP word="have"/> <Obj> <Number int="{{msg.number}}"/> <N word="{{msg.make}}"/> </Obj> </S>
To generate from a JSON object that has been sorted, nest both the sort and values functions in the ATL as follows:
[[realise((sort(values(WholeJSON.cars), (p,q) -> (sign(p.number - q.number))),"Car"))]]
The above ATL uses the sort
function to sort the data (converted into a list by values
) by the number of cars using the lambda expression (p,q) -> (sign(p.number - q.number)))
. Then realise
generates text from a lex rule with classes="Car"
.
The generated output is:
The London office has 2 Volvos. The New York office has 4 Fords.
Notice that the output sentences are now sorted by increasing numbers of cars.
Realise non-JSON data
You can use lex rules to generate from other kinds of input data (i.e. not just JSON objects). This section shows you how to input strings, lists, integers, ATL objects (lists of key–value pairs), and ATL strings.
When your input data is not in JSON format, there are two ways to handle this in a lex rule:
Input a list of ATL objects instead of JSON data and refer to the keys in the same way as you would for JSON objects, i.e. use
msg.name
to refer to a key called 'name'. See ATL guide > ATL objects for more information.Use a special Message property called “data”, i.e.
{{msg.data}}
and input strings, lists, numbers, etc.
A list of key–value pairs
Let’s use one of the lex rules above that takes JSON input:
<S id="LexRule1" classes="Abode"> <Subj word="{{msg.name}}"/> <VP word="live"/> <Obj word="{{msg.location}}" preposition="in"/> </S>
You can input an ATL object (a list of key–value pairs) with the same keys as the JSON data and the lex rule will treat the list as though it is a JSON object.
The following expression realises the rule with inputs that are new values for the keys ‘name’ and ‘location’:
[[realise((((name='Bill',location='Washington'),(name='Claire',location='Tampa')),'Abode'))]]
This produces:
Bill lives in Washington. Claire lives in Tampa.
The remaining examples show you how to use the special Message property, {{msg.data}}
, with input strings, lists of strings, integers and ATL strings.
A single string
This example illustrates the use of {{msg.data}}
in the following lex rule:
<S id="LexRule3" classes="StringInput2"> <Subj word="{{msg.data}}"/> <VP word="be"/> <PP string="on the payroll"/> </S>
Input a single string to the above lex rule and realise the sentence with the following:
[[realise(('Bill','StringInput2'))]]
Here, the string ‘Bill’ is the input data to a rule with classes=”StringInput2″. The output text is:
Bill is on the payroll.
A list of strings
In this example, we input a list of strings to the same lex rule used for A single string.
[[realise((('Bill','Susan','Anne'),'StringInput2'))]]
The output text is:
Bill, Susan and Anne are on the payroll.
An integer
To input an integer, we need a lex rule that takes an integer input:
<S id="LexRule4" classes="InputNumber"> <Subj> <Number int="{{msg.data}}" isAlpha="true"/> <N word="person"> <Feature name="pluralform" value="people"/> </N> </Subj> <VP word="be"/> <PP string="on the payroll"/> </S>
This rule has a <Number></Number>
component that accepts integer input data, int="{{msg.data}}"
.
Let’s realise the rule with the integer 1 as input:
[[realise((1,'InputNumber'))]]
The result is:
One person is on the payroll.
Realising the rule with the integer 342 as input:
[[realise((342,'InputNumber'))]]
produces:
Three hundred forty-two people are on the payroll.
An ATL string
In this example, we will use the lex rule that takes a string as input data:
<S id="LexRule3" classes="StringInput2"> <Subj word="{{msg.data}}"/> <VP word="be"/> <PP string="on the payroll"/> </S>
We can input an ATL string as follows:
[[realise(("one [[gender('Bill')]]",'StringInput2'))]]
and the output is:
One male is on the payroll.
Notice that the ATL string is encased in double quotes so that the ATL function [[gender('Bill')]]
is evaluated. The result is “one male” which is the input to the lex rule.
Individual list elements
Finally, when you input a list of items, individual members of the list can be accessed with square bracket notation (array notation). So the first element in the list is accessed with msg.data[0]
, the second with msg.data[1]
and so on. Don’t forget that the first element is at position 0 and the entire list is msg.data
.
For this example, we'll use a new lex rule that accesses elements of an input list:
<S id="LexRule5" classes="AccessList"> <Subj word="{{msg.data[0]}}"/> <VP word="live"/> <Obj word="{{msg.data[1]}}" preposition="in"/> </S>
The following expression realises the rule with an input list:
[[realise((('Bill','Washington'),'AccessList'))]]
This produces:
Bill lives in Washington.