The input notation to jsRealB realizer was originally designed to be a valid JavaScript program that reflects the traditional constituent syntax formalism. An internal structure is built by Constructors that create JavaScript objects which can be modified with property functions. The fact that jsRealB expressions are JavaScript expressions allows the use of the many development tools available for JavaScript to create and debug the realizer. This also allows a seamless integration in the browser environment.
While being compact and linguist-friendly, this notation is not so convenient when it must be created by another system. Producing a syntactically legal JavaScript programmatically can be cumbersome and error-prone. This is why we have defined an alternative input format to jsRealB using JSON. Almost all programming languages provide convenient and efficient APIs for transforming their data structures in JSON. Using this format, the What to say part of a natural language generation system can be defined in any programming language, while being able to use the jsRealB realizer for producing a well-formed and well-formatted natural language utterance. This is similar in spirit to the XML input format for SimpleNLG.
This format of JSON input has been used as output from two different programming languages, for which auxiliary functions have been developed to ease the creation of the JSON structures.
This notation closely parallels the usual jsRealB function calls that create constituents as described in the documentation. The JSON input is an object with a key that indicates if it is a phrase
or a terminal
depending on its key.
phrase
whose value is a string giving its type, e.g. "S"
or "NP"
; the value associated with the elements
key is the list of its children which are themselves constituents. terminal
whose value is a string giving its type, e.g."N"
or "V"
; the value associated with the lemma
key is a string giving the base form of the word. props
whose value is a list of key-value pairs that modify the realization of the constituent; the keys within this list correspond to the jsRealB options. lang
whose value specifies the realization language for this constituent. When it is not specified, it is the same as the one of its parent. This search is applied recursively until the root, at which level it must be specified. This is similar to the process used for XML namespace determination.To create the internal representation of the realizer, the JSON data structure is given as parameter to the fromJSON(...)
function which traverses the object and calls the appropriate constructors and option functions.
The following table illustrates the parallel between both jsRealB specifications for the sentence: The cat will not eat grey mice.
|
|
The JSON specification (on the right) is admittedly much more verbose than the original one (on the left). But like any markup language, the JSON specification is designed to be created programmatically using the JSON API of a host system, not written by a human.
The following is the json-rnc schema used to validate the JSON input to jsRealB.
This schema describes a valid JSON input, but it does not implement all constraints, most of which will be checked when fromJSON(...)
interprets the key-value pairs within the props
fields. Download the file [here](jsRealB.jsonrnc).
start = Constituent
Constituent = Phrase | Terminal
Phrase = {
phrase : /S|NP|AP|VP|AdvP|PP|CP|SP/,
elements: [Constituent],
props? : propsContent,
lang? : /en|fr/
}
Terminal = {
terminal: /N|A|Pro|D|V|Adv|C|P|DT|NO|Q/
lemma : string,
props? : propsContent,
lang? : /en|fr/
}
propsContent = {
g? : /[mfx]/, # gender: masculine, feminine or neutral
n? : /[sp]/, # number: singular, plural
pe? : (/123/|1|2|3), # person either as a number or a string containing a number
t? : /p|i|f|ps|c|s|si|ip|pr|pp|b|pc|pq|cp|fa|spa|spq/, # tense
f? : /co|su/, # comparative or superlative form
aux? : /av|êt|aê/, # French auxiliary
tn? : /|refl/, # tonic for pronoun
c? : /nom|acc|dat|refl|gen/, # case for pronoun
ow? : /s|p/, # owner for English pronoun: singular, plural
pos? : /post|pre/, # (post or pre)position of a French adjective
pro? : //, # NP or PP should be pronominalized
nat? : boolean, # NO or DT should be in natural form
# formatting options
cap? : //, # first letter of constituent should be capitalized
lier?: //, # an hyphen should be added with the following word
# list options
b? : [string], # strings to be added before a constituent
a? : [string], # strings to be added after a constituent
en? : [string], # strings to be added before and after a constituent
# special cases
tag? : tagContent,
date?: dateContent,
no? : noContent,
typ? : typContent
}
tagContent = [[string|{*:string}] # list of [tagname,{attributes as key:value pairs}]
@(minItems=2,maxItems=2)]
dateContent = { # selection of fields when realizing a DT
year? : boolean,
month? : boolean,
date? : boolean,
day? : boolean,
hour? : boolean,
minute?: boolean,
second?: boolean,
nat? : boolean,
det? : boolean,
rtime? : boolean
}
noContent = { # format of number
mprecision?: integer, # max precision
raw? : boolean, # output as originally entered
nat? : boolean, # output as "number in letters"
ord? : boolean # output as an ordinal number
}
typContent = { # modification of the type of sentence
neg? : (boolean|string) # negation (in French, string is used instead of "pas")
pas? : boolean, # passive
prog? : boolean, # use progressive
exc? : boolean, # exclamative form
perf? : boolean, # use perfect (English only)
contr?: boolean, # use contracted form (English only)
mod? : (boolean | /poss|perm|nece|obli|will/), # modals
int? : (boolean | /yon|wos|wod|wad|woi|whe|why|whn|how|muc/) # questions
}
.add(...)
: has no equivalent in the JSON specification; this kind of dynamic constituent modification must be performed within the system creating the JSON;NO("..")
: the number must be specified as a string for the lemma;DT()
: the corresponding lemma should be an empty string (""
);.pro()
, .cap()
, .lier()
: the value in the props
field should also be an empty string;.nat()
:the value in the props
field should be boolean.ppJSON(...)
function can be used to return an indented string representation of a JSON object, similar to the one in the above example, although the above example has been slightly edited for compactness. Its output is much more compact and more readable than the one produced by the JavaScript JSON.stringify(json,null,level)
The JSON specification is useful as input to a Unix-like filter that takes the output of another system. The dist
directory shows jsRealB-filter.js, a node.js script that can be used for such purpose. After reading a line from the standard input, it checks if it starts with a left brace. If so it takes for granted that it is a JSON input, it parses the line as JSON and calls fromJSON
on the resulting parse and realizes the expression. Here is an example of a simplistic external process for creating a JSON expression:
echo '{"phrase":"NP","elements":[{"terminal":"D","lemma":"a"},'\ '{"terminal":"N","lemma":"woman","props":{"g":"f","n":"p"}}],"lang":"en"}'| node jsRealB-filter.js
returns women
as realization. The determiner "a"
is plural because it agrees with the number of the noun within the noun phrase.
If the line does not start with a left brace, then it evaluated as a jsRealB expression, so
women
is also realized with the following:
echo 'NP(D("a"),N("woman").n("p"))' | node jsRealB-filter.js
Although our original motivation was for allowing JSON input, it is also possible to get the JSON expression corresponding to a given jsRealB expression by calling .toJSON()
on any Constituent. This call (similar to .toSource()
) creates a string that corresponds to the jsRealB expression to which it is applied. In fact, fromJSOM(exp.toJSON())
creates a clone of the original exp
.
The expression created by .toJSON()
is a single line (jsonl
format) which can be hard to decipher. This line can be given to ppJSON(exp)
to create an indented string such as the one shown in the right part of the above table.
These functions are used for defining the .clone()
method of Constituent
as follows:
clone(){return fromJSON(this.toJSON(), this.lang);}