Report Phrase Generator
GenoPro's report generator is capable to create rich custom reports. The
Phrase Generator is an innovation to generate narrative phrases. With the phrase generator,
you can produce phrases in the language of your choice without having to concatenate strings. This page describes the
features of the phrase generator and how to use it in your reports.
GenoPro provides a dialog named the Phrase Editor to
compose and test your phrases.
The Phrase Editor Dialog
Differences between FormatPhrase,
WritePhrase and WritePhraseDic
GenoPro provides four methods to format phrases with Util.FormatPhrase
as the core method. The other
methods are simple wrappers to format phrases from the
language dictionary or output phrases with fewer lines of code. Since the method Util.FormatPhrase returns a
string containing the phrase, the
Write method is necessary to output this phrase to the report:
Report.Write(Util.FormatPhrase("{0} was a mathematician.", "Archimedes"))
To save yourself some typing, you may use the method WritePhrase
to produce the same result. The method Report.WritePhrase is also faster to execute
than its equivalent combination of Report.Write and
Util.FormatPhrase .
Report.WritePhrase("{0} was a mathematician.", "Archimedes")
Once you are satisfied with your phrase, you may store the phrase template
into the
language dictionary (Dictionary.xml). The language dictionary is a
repository of all the text specific to a
language. Translating a report is done by translating the
language dictionary, without the need to inspect each line from the source code. In this example, we may define the
phrase PhMathematician in Dictionary.xml. For clarity we use the prefix Ph to designate a
phrase.
<PhMathematician>{0} was a mathematician.</PhMathematician>
Next, we can use the method WritePhraseDic to format a phrase
from the dictionary.
Report.WritePhraseDic("PhMathematician", "Archimedes")
The method WritePhraseDic will perform a dictionary lookup for
the phrase PhMathematician . If the dictionary entry PhMathematician is not
found, GenoPro will log an error message, otherwise the text
from PhMathematician will be used as the
formatting template. Similarly, you may use the method
LanguageDictionary.FormatPhrase
to format a phrase from the language dictionary. In the
later case, the formatted phrase will be returned in a string rather than being written to the report. You may use this
method to combine multiple phrases before writing them to the report.
For clarity purpose, we will use the method WritePhrase in our
tutorials.
Phrase Generator Tutorial
Getting Started with the Phrase Generator
The first parameter of WritePhrase is a template representing
the phrase body. The remaining parameters are the values to be inserted in the phrase. For instance,
the following code
Report.WritePhrase("{0} was a mathematician.", "Archimedes")
will replace the argument {0} by the parameter value
"Archimedes" to produce the following output:
Archimedes was a mathematician.
Use the curly braces { } for inserting a corresponding
zero-based index parameter. The first parameter is designed by the argument {0} , and there are
no limit on the number of arguments/parameters.
Report.WritePhrase("{0} was {1}{2}.", "Archimedes", "a great ",
"mathematician")
Archimedes was a great
mathematician.
The arguments may be repeated as many times, and may be in any order. For
instance, the following code
Report.WritePhrase("{1} {0}{2} {1}.", "Archimedes", "a mathematician", ";")
a mathematician Archimedes; a mathematician.
The phrase generator is as easy to use as the method
FormatString and has the ability to automatically remove
dead phrases. If there are no meaningful values within a phrase, then the entire phrase is reduced to
an empty string.
Report.WritePhrase("{0} was a mathematician.",
"")
In the example above, an empty string was supplied for argument {0} .
Since the entire phrase had no pertinent
data, the method WritePhrase wrote nothing (an
empty string). This feature is quite distinct from the ubiquitous method
FormatString
which blindly replaces arguments with their corresponding
parameter values.
Util.FormatString("{0} was a mathematician.", "")
was a mathematician.
Why this feature a benefit? Well, in genealogy there is quite often a lot
of missing data, such as the date of birth, place of birth, date of death and so on. The phrase
generator will not output a phrase body without any meaningful
data. Here an example where i is an object
representing an individual:
Report.WritePhrase("{0} was born{1}{2}.", i.Name, i.Birth.Date,
i.Birth.Place)
No text will be written if all three parameters, individual's name, date of
birth and place of birth, are empty. This
is much better than writing the dummy phrase " was born."
because there is no name, date of birth and place of birth..
Sometimes a phrase may have parameters that are not pertinent to the phrase
content. For instance, if the individual has a name but no date of birth and no place of birth.
Assuming the individual name was Archimedes in our example
above, the output would be:
Archimedes was born.
This is not better than the dummy phrase " was born.". It would be much
better to produce an empty phrase if both the date of birth and place of birth are empty. The solution
is to specify a ghost argument using the exclamation
mark (! ).
Report.WritePhrase("{!0} was
born{1}{2}.", i.Name, i.Birth.Date, i.Birth.Place)
The exclamation mark ! will
treat the
argument as non-pertinent. In our example, insert the
individual's name but do not count it as part of the
phrase. A ghost argument is the same as hardcoding the
individuals' name into the phrase body:
Report.WritePhrase("Archimedes was
born{0}{1}.", i.Birth.Date, i.Birth.Place)
Using a ghost argument, we can insert a parameter such as the individual's
name, yet produce an empty phrase if the birth
date and place of birth are empty. Almost every phrase in
the language dictionary contains a ghost argument. An empty value to a ghost argument does not produce an
empty phrase. For instance, if the name is blank, then
the following phrase will be generated.
Report.WritePhrase("{!0} was
born{1}{2}.", "", " in 287 BC", " in Sicily")
was born in 287 BC in Sicily.
In our example above, we may want to insert something if the name is blank.
In this case you can specify a default
value for the argument.
Report.WritePhrase("{!0=Archimedes} was
born{1}{2}.", "", " in 287 BC", " in
Sicily")
Archimedes was born in 287 BC in Sicily.
The default argument can be combined with a normal argument or a ghost
argument.
Report.WritePhrase("{0=Default text} for normal argument.", "Text")
Report.WritePhrase("{0=Default text} for normal argument.", "")
Report.WritePhrase("{!0=Default text} for
ghosted argument.",
"Text")
Report.WritePhrase("{!0=Default text} for
ghosted argument.",
"")
Text for normal argument.
Default text for normal argument.
empty phrase because argument {!0} is ghosted
empty phrase because argument {!0} is ghosted
Ghosted Default Argument
{0!=}
Use the exclamation mark (! ) before the equal sign (= )
to specify a ghosted optional default text. This way, the default value will be considered non-pertinent.
Report.WritePhrase("{0!=Default text} for
normal argument.",
"Text")
Report.WritePhrase("{0!=Default text} for
normal argument.",
"")
Text for normal argument.
empty phrase because the default value is ghosted
A sub-phrase is a section within a phrase automatically removed if having no
meaningful data.
Report.WritePhrase("{!0} was born[ in year {1}][ in {2}].", "Archimedes", "287 BC", "Sicily")
Report.WritePhrase("{!0} was born[ in year {1}][ in {2}].", "Archimedes", "", "Sicily")
Report.WritePhrase("{!0} was born[ in year {1}][ in {2}].", "Archimedes", "287 BC", "")
Report.WritePhrase("{!0} was born[ in year {1}][ in {2}].", "Archimedes", "", "")
Archimedes was born in year 287 BC in Sicily.
Archimedes was born in Sicily.
Archimedes was born in year 287 BC.
empty phrase since both sub-phrases are empty and the argument {!0} is ghosted.
A sub-phrase may be within another sub-phrase.
Report.WritePhrase("{!0} [died[ in {1}][ at the age of {2}]].", "Archimedes", "212 BC", "75")
Report.WritePhrase("{!0} [died[ in {1}][at the age of {2}]].", "Archimedes", "","75")
Report.WritePhrase("{!0} [died[ in {1}][ at the age of {2}]].", "Archimedes", "212 BC",
"")
Report.WritePhrase("{!0} [died[ in {1}][ at the age of {2}]].",
"Archimedes", "", "")
Archimedes died in 212 BC at the age of 75.
Archimedes died at the age of 75.
Archimedes died in 212 BC.
empty phrase, since the two nested sub-phrases are empty
Using nested sub-phrases is not very useful without the possibility of
including conditions for those sub-phrases.
A conditional sub-phrase is a directive to include the sub-phrase if its
required conditions are met. The conditional
argument is somewhat the reverse of the
ghost argument because it includes a sub-phrase only
if having pertinent data. Utilize a conditional sub-phrase
when you want to include a section of a phrase under a
specific condition without including the value of the
condition.
Use the question mark (? ) in front of the argument index to
create a conditional argument.
Report.WritePhrase("Archimedes [was born in {0}][[{?0} and ]died in {1}].", "287 BC", "212 BC")
Report.WritePhrase("Archimedes [was born in {0}][[{?0} and ]died in {1}].",
"287 BC", "")
Report.WritePhrase("Archimedes [was born in {0}][[{?0} and ]died in {1}].", "", "212 BC")
Report.WritePhrase("Archimedes [was born in {0}][[{?0} and ]died in {1}].", "", "")
Archimedes was born in 287 BC and died in
212 BC.
Archimedes was born in 287 BC.
Archimedes died in 212 BC.
empty phrase, since the two nested sub-phrases are empty
In the second phrase, the condition {?0} is met, however since
argument {1} is missing, the sub-phrase [[{?0} and ]died in {1}] is therefore empty,
resulting in only a a valid sub-phrase "was born in 287 BC" to
produce the phrase "Archimedes was born in 287 BC."
Negative Conditional Argument
{?!0}
In some cases, you may want to include a sub-phrase if a parameter is empty
or false . Use the exclamation
mark (! ) to negate the condition.
Report.WritePhrase("Archimedes is [{?0}dead][{?!0}alive].", true)
Report.WritePhrase("Elvis is [{?0}dead][{?!0}alive].",
false)
Archimedes is dead.
Elvis is alive.
Multiple Conditions
The phrase generator supports the logical OR operator (| )
and the logical AND operator (& ).
If multiple conditions must be met, use the AND
operator & .
Report.WritePhrase("Archimedes [was born in {0}][{?0&1} and ][died in {1}].", "287 BC", "212 BC")
In this case, the sub-phrase [{?0&1}
and ]
will be written only if both parameter 0
and parameter 1 are non-empty. The AND operator is optional; you may use nested
conditions like the phrase below to produce the same result. It is up
to you to decide which you prefer best.
Report.WritePhrase("Archimedes [was born in {0}][[{?0} and ]died in {1}].",
"287 BC", "212 BC")
Similarly, you may use the OR operator | (vertical bar) to write a
phrase if parameter 0 or parameter 1 is non-empty. In the example below, we assume the individual i
is dead if explicitly marked as dead or if born prior year
1850. The second sub-phrase [{?!1|2}alive] is
the negation of the condition {?1|2} , meaning
the individual is alive.
Report.WritePhrase("{!0} is [{?1|2}dead][{?!1|2}alive].", i.Name, i.IsDead,
i.Birth.Date.NYear < 1850)
Both operators | and & are optional.
For instance, you can write the same
phrase as above like this:
Report.WritePhrase("{!0} is [{?1}{?2}dead][{?!1}[{?!2}alive]].",
i.Name, i.IsDead, i.Birth.Date.NYear < 1850)
You cannot mix the operators | and & together within the same condition.
The following is not allowed because
there are & and | within the same
expression.
Report.WritePhrase("{!0} is [{?1&2|3|4|5}not
allowed].",
...)
Negate Multiple Conditions
Like a regular conditional sub-phrase, you can use the exclamation mark (! )
to negate the whole expression,
which may include multiple conditions like the example
[{?!1|2}alive]
the negation of the OR operator. You may also negate an
expression using the AND operator & .
Negate Previous Condition
If you just want to negate the previous condition, you can simply use the
exclamation mark in braces {!}. The exclamation alone means "else"
from the previous condition "if". For instance, if the previous condition was true,
then the {!} will evaluate to false, and vice-versa. The next two
phrases produce the same result:
Report.WritePhrase("{!0} is [{?1|2}dead][{?!1|2}alive].", i.Name, i.IsDead,
i.Birth.Date.NYear < 1850)
Report.WritePhrase("{!0} is [{?1|2}dead][{!}alive].", i.Name, i.IsDead,
i.Birth.Date.NYear < 1850)
Comparison Operator
Sometimes the condition may be comparing an argument against a specific
value. In such case, use the ?= operator.
Report.WritePhrase("Adding a [{?0=M}son][{?0=F}daughter] to family",
i.Gender)
Encoding the operator AND
(& ) in XML
Once you are done writing your code, you may want to move all your phrases
into the language dictionary (Dictionary.xml). If your phrases contain the AND operator & ,
you will have to encode each & by
& or substitute each & by the caret ^ .
For instance, storing the following
entry in the language dictionary will cause an error because
the ampersand & is a reserved symbol for XML.
<PhBirthAndDeath>Archimedes [was born in {0}][{?0&1} and ][died in {1}].</PhBirthAndDeath>
To fix the error, you can either encode the ampersand
& by its XML-equivalent
&
or replace each conditional & by the caret
^ . GenoPro interprets all carets (^ )
as AND operators (& ).
<PhBirthAndDeath>Archimedes [was born in {0}][{?0&1} and ][died in {1}].</PhBirthAndDeath>
<PhBirthAndDeath>Archimedes [was born in {0}][{?0^1} and ][died in {1}].</PhBirthAndDeath>
Next, you can use the following code:
Report.WritePhraseDic("PhBirthAndDeath", "287 BC", "212 BC")
You may ruse the vertical bar (| ) let the phrase generator pick
the first non-empty argument. Let's say
you want to output the name of an individual, giving priority
to his nick name if present. You would write the following code:
Report.WritePhrase("{0|1) was a great
mathematician!",
i.Name.Nick, i.Name.First)
When the vertical bar is used outside a condition, it means to include data
from parameter 0 or from parameter 1 keeping
the first non-empty. If both are empty, then an empty name
will be written. You may ghost the argument and use a default value like sample below.
Report.WritePhrase("{!0|1=Archimedes) was a great mathematician!",
i.Name.Nick, i.Name.First)
You may want to insert an hyperlink or some special HTML element (such as
bold) in your phrase. By default each argument
is HTML-encoded, meaning it is impossible to insert HTML code
within a phrase. You can bypass this behavior by using
the HTML argument {h} .
strNameHtml = "<a
href='http://en.wikipedia.org/wiki/Archimedes'>Archimedes</a>"
Report.WritePhrase("{!0h) was a great
mathematician.",
strNameHtml)
Report.WritePhrase("{!0h) was a
great mathematician.",
"<b>Archimedes</b>")
Report.WritePhrase("{!0) was a great mathematician.", strNameHtml)
Report.WritePhrase("{!0) was a great mathematician.", "<b>Archimedes</b>")
Archimedes was a great
mathematician.
Archimedes was a great mathematician.
<a href='http://en.wikipedia.org/wiki/Archimedes'>Archimedes</a> was a great
mathematician.
<b>Archimedes</b> was a great mathematician.
GenoPro uses the HTML argument intensively create HTML reports having
hyperlinks connecting family members. See
http://familytrees.genopro.com/ for
sample genealogy reports.
The phrase generator offers additional functionalities to generate phrases.
Insert spaces between phrases
{ }
So far, we have seen how to generate separate phrases. In the English
language, phrases must be separated by one or
two spaces. The following code produces two phrases without
any space in between.
Report.WritePhrase("{0) was a great mathematician.",
"Archimedes")
Report.WritePhrase("{0) was also an engineer.", "He")
Archimedes was a great mathematician.He was also an engineer.
The solution is to use the function to insert optional spaces { } .
This function will insert spaces
to concatenate phrases together.
Report.WritePhrase("{0) was a great mathematician.",
"Archimedes")
Report.WritePhrase("{ }{0) was a also an engineer.", "He")
This way the result will be:
Archimedes was a great mathematician. He was also an engineer.
You may put as many spaces as you wish, such as { } , { }
or { } .
Uppercase Next Character
{\U}
In the English language, a phrase must begin with an uppercase letter. To
guarantee a phrase begins with an uppercase
letter, use the special function {\U} .
Report.WritePhrase("{\U}{0) was also an engineer.",
"he")
He was also an engineer.
Line Break / New Line
{\br} {\n}
If you want a phrase to begin on a new paragraph, or end a paragraph after
writing a specific phrase, use the function
{\br} or {\n} to insert a new line / line break. Both
{\br} and {\n}
are identical and will insert the HTML entity
<br /> in your HTML report. If your
report uses another format such as plain text (.txt) or rich-text
format (.rtf), then the function {\br} and
{\n} will insert the proper code to produce a new line
in that format. If you are generating an HTML report, it is
recommended you use the {\br} because it
is much easier to remember the correlation between
{\br} and <br /> , however if you are
a hardcore JavaScript or C++ developer, you may prefer to use
the {\n} .
Report.WritePhrase("{0) was a great mathematician.{\br}",
"Archimedes")
Report.WritePhrase("{ }{\U}{0) was also an engineer.", "he")
Archimedes was a great mathematician.
He was also an engineer.
In the example above, notice the optional spaces { } have not
been inserted. The function { } inserts spaces between phrases.
If a phrase begins on a new paragraph, then the two phrases are
no longer considered following each other and therefore no
spaces are inserted.
Having read all the documentation, it is time to put together a real-life
example. If you want to see the true power
of the phrase generator, visit
http://familytrees.genopro.com/ and take a
look at some of the reports. The phrase generator
successfully generated millions of phrases. To see how those
phrases were generated, open the file Dictionary.xml and take
a look at the section <ReportGenerator>
to locate the phrase templates.
name = "Archimedes"
nameHtml = "<a
href='http://en.wikipedia.org/wiki/Archimedes'>Archimedes</a>"
birthDate = " in 287 BC"
birthPlace = " in Sicily"
birthPlaceHtml = "in <a
href='http://en.wikipedia.org/wiki/Sicily'>Sicily</a>"
deathDate = " in 212 BC"
Report.WritePhrase("1- {!0h}[ was born{1}{2h}][[{?1|2} and] died{3}].",
nameHtml, birthDate, birthPlaceHtml, deathDate)
Report.WritePhrase("2- {!0h}[ was born{1}{2h}][[{?1|2} and] died{3}].",
nameHtml, birthDate, birthPlaceHtml, "")
Report.WritePhrase("3- {!0h}[ was born{1}{2h}][[{?1|2} and] died{3}].",
nameHtml, birthDate, "", "")
Report.WritePhrase("4- {!0h}[ was born{1}{2h}][[{?1|2} and] died{3}].",
nameHtml, "", "", "")
Report.WritePhrase("5- {!0}[ was born{1}{2h}][[{?1|2} and] died{3}].", name,
"", "", deathDate)
Report.WritePhrase("6- {!0}[ was born{1}{2}][[{?1|2} and] died{3}].", name,
birthDate, "", deathDate)
Report.WritePhrase("7- {!0}[ was born{1}{2}][[{?1|2} and] died{3}].", name,
"", birthPlace, deathDate)
1- Archimedes was born
in 287 BC in
Sicily and died in 212 BC.
2- Archimedes was born
in 287 BC in
Sicily.
3- Archimedes was born
in 287 BC.
empty phrase because all pertinent arguments are empty
5- Archimedes died in 212 BC.
6- Archimedes was born in 287 BC and died in 212 BC.
7- Archimedes was born in Sicily and died in 212 BC.
See Also:
Phrase Editor
Util.FormatString
|