GenoPro Home
GenoPro Home  |  SDK Home  |  Report Generator  |  Support  |  Search  |  Help  |  Site Map

Skip Navigation Links.

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
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 Greatest Benefits of the Phrase Generator

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..

Ghost Argument {!0}

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.

Default Argument {0=}

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

Sub-Phrases

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.

Nested Sub-Phrases

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.

Conditional Sub-Phrase {?0}

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 &amp; 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 &amp; or replace each conditional & by the caret ^.  GenoPro interprets all carets (^)   as AND operators (&).

<PhBirthAndDeath>Archimedes [was born in {0}][{?0&amp;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")

First Non-Empty Argument {0|1}

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)

HTML Argument {0h}

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.

Special Functions

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.


Real-Life Example

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

 

Copyright © 1998-2024. All rights reserved. GenoPro® and the GenoPro logo are registered trademarks.