Template concepts

Download pxDoc Reference Guide in PDF and pxDoc Leaflet

Template concepts

Template concepts

Let's start with the few core concepts that organize your documentation generators:

  • pxDocGenerator and pxDocModules,
  • templates,
  • functions,
  • variables.

pxDocGenerators and pxDocModules

pxDocGenerator and pxDocModule share the same set of attributes.

				pxDocGenerator <name> <attributes> { ... }
				pxDocModule <name> <attributes> { ... }

Attributes

Description

Possible values (if any)

Optional

				 		  with: 
				 		    module1, module2, ...
				 		  

Comma-separated list of Modules that will be used by this generator

Any accessible pxDocModule name

Yes

				 		  stylesheet: 
				 		    MyStylesheet
				 		  

Name of a deployed Word stylesheet to use in the generator

Any valid deployed stylesheet ID

Yes

				 		  styles: 
				 		    MyStyle1, MyStyle2, ...
				 		  

Comma-separated list of variable style names

Only valid java identifiers (no spaces, no special characters...)

Yes

				 		  styleBindings: 
				 		    ParamStyle1->RealStyle1, 
				 		    ParamStyle2->RealStyle2, 
				 		    ...
				 		  

Comma-separated list of bindings of variable styles to concrete styles

Source styles are the Module(s) variable styles.
Target styles must exist in the chosen stylesheet.
All source styles must be bound.

Yes

 

Usage : Basic generator using a Stylesheet

Basic declaration of a generator which uses a stylesheet as a source for the Styles, header/footer, etc.

					pxDocGenerator HomePageExample stylesheet:MyStylesheet {
					
					  root template main(Object model) {
					    ...
					  }
					}

 

Usage : Basic generator using variable styles

Basic declaration of a generator which uses 3 variable styles: Title1, Title2 and bulletList. These styles will have to be bound with Styles from a Word stylesheet when generating the document.

					pxDocGenerator HomePageExample style: Title1, Titl2, BulletList {
					
					  root template main(Object model) {
					    ...
					  }
					}

 

Usage : Generator with imported modules

A generator with a Module imported. The styles of the Modules are bound with the styles of the Generator stylesheet

					pxDocGenerator HomePageExample 
					  with: TestModule 
					  stylesheet:MyStylesheet
					  styleBindings:moduleTitle1->Title1, moduleTitle2->Title2 {
					
					  /* content */
					}

See “Apply styles” section to learn more about style-binding.

 

Usage : Declaration of a Module with a stylesheet

					pxDocModule MyModule stylesheet:MyStylesheet {
					
					}

If you use a stylesheet in a Module, you will have to use the same stylesheet in all the Generators where this Module is imported.

 

Usage : Declaration of a Module with variable styles

					pxDocModule MyModule styles: Title1, Titl2, BulletList {
					
					}

 

Keyword 'template'

Templates is where the magic of pxDoc happens.

Templates can be considered as regular java methods since:

  • you can design your template signature (template parameters)
  • you can declare local variables
  • you can use almost all conditional (if-then-else), switch, or iteration instructions (for, while...).

... but with an extra set of built-in keywords dedicated to document generation:

  • about resources: document, subDocument, image
  • about styling: #, HeadingN, font, bold, italic, color, underline...
  • about navigation: bookmark, hyperlink
  • about tables: table, row, cell
  • about breaks: newPage, section, nextColumn...
  • and misc: table of content, field, language, samePage, ...
				<attributes> template templateName(args) { ... }

Attributes

Description

Possible values (if any)

Optional

				 		  root

Set the template to launch in a pxDocGenerator

One and only one template must be set as root in a pxDocGenerator

Yes

				 		  <public|private>

Template visibility.

public, private

Public by default.

Yes

				 		  override

Imported templates can be overridden by a local version of a template with the same java erasure.

 

Yes

				 		  templateName

A name for the template

Any valid java method name

No

(Type param1, ...)

Parameters for the template

Any valid java parameter declaration expression

Yes

 

Keyword 'apply'

Templates can be invoked using the special keyword apply.

				apply templateName(arguments) separator {...}

Attributes

Description

Possible values (if any)

Optional

templateName

The template to call

Any visible template.

No

(Type param1, ...)

Arguments given to the template

Given parameters must match the signature of a visible template

No

				 		  separator {...}

Inserts document elements (text, breaks, ...) between each template invocation

Can be used in case of template invocation with an Iterable as first parameter.

Content to be included between each template invocation is set inside '{' '}' and can contain any valid document elements.

No

 

Usages of template and apply keywords

Usage : Simplest template definition

			template myTemplate() {
			  // content
			}

 

Usage : Private template

			private template myTemplate(Person person) {
			  // content
			}

 

Usage : Root template

			root template main(Model model) {
			  // content
			}

 

Usage : Simple apply of a template

Templates can be invoked using the special keyword apply.

			template prettyAddress(Address address) {
			  address.number " " address.street ", " address.postalCode " " address.city
			}
			
			template myTemplate(Person person) {
			  var Address mainAddress = person.mainAddress
			  apply prettyAddress(mainAddress) // <- call to template 'prettyAddress(Address)'
			

When the first parameter given to the template being called is an Iterable, apply iterates the template invocation on each element.

			template firstTemplate(Person person) {
			  // this...
			  apply prettyAddress(person.addresses)
			
			  // is equivalent to
			  for (address : person.addresses) {
			    apply prettyAddress(address)
			  }
			}
			

 

Usage : Insert a separator when iterating on templates

When iterating on templates, it is sometimes useful to separate template invocations with a separator:

			template firstTemplate(Person person) {
			
			  // the separator instruction includes a paragraph break (§) between each address
			  apply prettyAddress(person.addresses) separator { § }
			
			  // same behaviour with too much code ;-/
			  for (var i=0; i<person.addresses.size; i++) {
			    apply prettyAddress(person.addresses.get(i))
			    if (i <person.addresses.size -1) {
			      §
			    }
			  }
			
			}
			

 

Usage : A real-life example of template (used to generate this documentation!)

All document keywords used in this example will be explained further. Don't panic!

			template toKeyword(Keyword keyword, int level) {
			
			  // Specify a title with the keyword name
			  HeadingN level:level {"Keyword '" keyword.keywordName "'" }
			
			  // Insert the keyword declaration description
			  apply toBasicExample(keyword.basicExamples) separator {§ }
			
			  // Insert the introduction text for the keyword
			  if (keyword.documentation !== null) {
			    apply toDoc(keyword.documentation, level)
			  }
			
			  // Build the table with the keyword attributes
			  if (!keyword.attributes.empty) {
			    table {
			      row header shadingColor:"0,0,0" {
			        cell {"Attributes" }
			        cell {"Description" }
			        cell {"Possible values (if any)" }
			        cell {"Optional" }
			      }
				  // Insert one row per attribute of the keyword
			      apply attributeRow(keyword.attributes)
			    }
			    §
			  }
			
			  // Insert the conclusion text of the keyword
			  if (keyword.conclusion !== null) {
			    apply toDoc(keyword.conclusion, level)
			  }
			
			  // Insert the usages (examples) for the keyword
			  apply toUsageExample(keyword.usageExamples)
			}

 

Keyword 'function'

All functions behaviors discussed in this section also apply to templates.

pxDoc functions are very similar to java methods:

				function Object myFunction(String param1, boolean param2) {
				  return param1 + param2;
				}

 

				<attributes> function ReturnType functionName(arguments) {...}

Attributes

Description

Possible values (if any)

Optional

				 		  <public|private>

Function visibility.

public, private

Public by default.

Yes

				 		  override

Imported functions can be overridden by a local version of a function with the same java erasure.

 

Yes

				 		  functionName

Function name

Any valid java method name

No

(Type param1, ...)

Parameters for the function

Any valid java parameter declaration expression

Yes

 

As pxDoc is based on Xbase, it shares with it many valuable improvements and possible code simplifications (in comparison with java).

Excerpt from the Xbase documentation:

Conceptually and syntactically, Xbase is very close to Java statements and expressions, with a few exceptions:

  • No checked exceptions
  • Everything is an expression, there are no statements
  • Lambda expressions
  • Type inference
  • Properties
  • Simple operator overloading
  • Powerful switch expressions

 

Implicit 'it' parameter

A function (or template) parameter named 'it' will allow you some extra simplifications in your code. Remember the template prettyAddress(Address address) we took as example ?

							template prettyAddress(Address address) {
							  address.number " " address.street ", " address.postalCode " " address.city
							}

With the it parameter, this template could have been written like this:

							template prettyAddress(Address it) {
							  number " " street ", " postalCode " " city
							}

Xbaselib extensions

The org.eclipse.xtext.xbase.lib provides a set of useful extensions that make complex things easy and short:

							function void testExtensions(List<Book> books) {
							  // Few IterableExtensions
							  // in our (dummy) example, Book has subclasses Novel, Fantaisy, ...
							
							  // filter(Class) filters elements instance of the specified class
							  var novels = books.filter(Novel)
							
							  // filter can take a lambda expression [] to carry out complex (or simple!) filter conditions:
							  // books published in year 1984
							  var byYearBooks = books.filter[book | book.publicationYear === 1984]
							  // IterableExtensions provides somes additional handy capabilities to express Integer ranges:
							  var twoThousandBooks = books.filter[book | (2000..2009).contains(book.publicationYear)]
							  
							  // you can sort your Lists with sortBy... Just give the name of the attribute to make the sort
							  var booksByYear = books.sortBy[publicationYear]
							  var booksByTitle = books.sortBy[title]
							  // you even sort using more powerful expressions
							  var booksByAuthorName = books.sortBy[author.name] 
							}
							
We recommend you to take time and learn more about extensions provided by org.eclipse.xtext.xbase.lib. They will allow you to make great things with your input data.

var / val

Variables can be declared with the var and val keywords.

  • var is used to declare non-final variables.
  • val is used to declare final variables. This is useful when you need to access a variable from a closure expression.
Variables have a public visibility by default. You can set them private using the private keyword.

Variables can be defined:

    • directly under pxDocGenerator or pxDocModule. In this case, they map to public fields under the underlying generator/module generated java classes.
    • inside a pxDoc template or function. In this case, they map to a local variable of the underlying generated java method.
				<var|val> <type>? name (= <initial>)?

Attributes

Description

Possible values (if any)

Optional

				 		  <var|val>

Declare a variable

var: non-final variables

val: final variables

No

<type>

The (java) type of the variable

Any valid java type.

Can be omitted since Xbase language support type inference

Yes

name

Name of the variable

Any valid java variable name.

No

= <initial>

An initial value for the variable

Any valid xbase/java expression.

Yes

 

Usage : In templates and functions:

					var Type name = ...
					val Type name = ...

 

Usage : In pxDocGenerators and pxDocModules, you can also set the variable visibility:

					private var String privateString = "Hello"
					public val String publicFinalString = "World"