Wiki source code of Template Mechanism

Last modified by Vincent Massol on 2026/08/30 19:36

Show last authors
1 The renderer carries no LaTeX of its own in Java. Exporting a page walks its XDOM, the tree of Blocks the wiki syntax was parsed into, and renders each Block with a Velocity template holding the LaTeX commands to produce. Which template that is is decided by name, and the name comes from the Block.
2
3 {{plantuml}}
4 @startuml
5 !theme bluegray
6 skinparam componentStyle rectangle
7
8 component "**XDOM**\n//the parsed page, one Block per piece of content//" as XDOM
9 component "**Template name**\n//the Block's class name,//\n//or its latex-template parameter//" as NAME
10 component "**Your template**\n//searched first//" as MINE
11 component "**The shipped default**\n//searched next//" as DEF
12 component "**The Block's children**\n//processed in its place//" as KIDS
13 component "**LaTeX**" as TEX
14
15 XDOM --> NAME : for each Block
16 NAME --> MINE
17 MINE --> DEF : not found
18 DEF --> KIDS : not found
19 MINE --> TEX : rendered
20 DEF --> TEX : rendered
21 @enduml
22 {{/plantuml}}
23
24 == One Template per Block ==
25
26 A Block asks for the template bearing its own simple class name: a ##WordBlock## is rendered by ##WordBlock##, a ##ParagraphBlock## by ##ParagraphBlock##. The XDOM sitting at the root of the tree is a Block like the others, so it has a template too, ##XDOM##, and that one stands for the whole document.
27
28 The templates the extension ships live inside its jar, as classloader resources under ##templates/latex/default/##. Reading the one named after a Block is the shortest way to find out what that Block currently produces.
29
30 A Block whose template is found nowhere is not dropped: its children are processed in its place, and only the container's own LaTeX is lost.
31
32 == Where a Template Is Looked Up ==
33
34 Every Block resolves to **two** paths, tried in that order: ##latex/<name>##, which is yours, then ##latex/default/<name>##, which is the extension's. The first that exists wins, so a ##latex/ParagraphBlock## you supply replaces the shipped ##latex/default/ParagraphBlock## for every paragraph of every export.
35
36 Each of the two paths is then resolved by XWiki's own template lookup, which searches three places in order:
37
38 * **The current skin.** When the skin is a wiki page, an ##XWiki.XWikiSkinFileOverrideClass## xobject whose ##path## is that path, which is how you [[override a template>>doc:documentation.extensions.dev.latex.override-template.WebHome]], or an xproperty of its ##XWiki.XWikiSkins## xobject named after the path — see the [[Skin Application>>doc:extensions:Extension.Skin Application]]. When the skin is on the filesystem, a file at that path under ##skins/<skin name>/##.
39 * **The ##templates## directory of the webapp**, so ##templates/latex/<name>## for the first path.
40 * **The classloader**, again under ##templates/##. This is where the shipped templates are found inside the extension's jar, and it is what makes ##WEB-INF/classes/templates/latex/<name>## an override point that needs no skin at all.
41
42 == The Document Template ==
43
44 The ##XDOM## template is the frame everything else is rendered into:
45
46 {{code language="tex"}}
47 \documentclass{$latex.properties.documentClass}
48
49 $latex.processor.render('Preamble')
50
51 \begin{document}$latex.processor.process($latex.block.getChildren())
52
53 \end{document}
54 {{/code}}
55
56 Two things follow from it. ##Preamble## is a template belonging to no Block at all: it exists only because the ##XDOM## template renders it by name, which is what makes ##latex/Preamble## the place to change everything between the document class and ##\begin{document}##. And the class is not fixed — it comes from the export's [[##documentClass## option>>doc:documentation.extensions.user.latex.export-page.export-options.WebHome]], falling back to ##article## when that option is left empty.
57
58 The shipped template wraps these lines in the ##XDOM## [[extension points>>doc:documentation.extensions.dev.latex.extension-points.WebHome]], which is how an extension adds to the generated document without taking the template over.
59
60 == Naming a Template on a Block ==
61
62 A Block can also ask for a template by name rather than by class, through a ##latex-template## parameter. Here one table cell is rendered by the ##custom1## template:
63
64 {{code language="none"}}
65 |=Head1|=Head2
66 |cell1|(% latex-template="custom/custom1" %)cell2
67 {{/code}}
68
69 The value is the path **without** the ##latex/## prefix, and it goes through the same two-path lookup as a class-derived name: ##latex/custom/custom1## first, then ##latex/default/custom/custom1##.

Get Connected