Help:Expansion
MediaWiki Handbook: Contents, Readers, Editors, Moderators, System admins +/- |
Expansion of templates, parser functions, variables (on this page collectively called templates in italics), and template parameters (tplargs) is done in substitution, and also as the first steps in page rendering. It consists of two phases: the creation of an XML parse tree, and producing the expanded wikitext. After expansion, two more steps are producing the HTML, and (in the user's browser) rendering the page. Considering intermediate results can be helpful in understanding the process.
Contents
- 1 XML parse tree
- 2 Expanded wikitext
- 3 Expansion of names and values
- 4 Braces, pipes, and equals signs produced by expansion
- 5 Balancedness
- 6 Sensitivity to missing or excess braces
- 7 Efficiency
- 8 Intermediate results
- 9 Substitution
- 10 Expansion depth limit
- 11 Internal code for parts in XML-style tags
- 12 See also
- 13 Links to other help pages
XML parse tree
The wikitext is parsed in Preprocessor DOM.php
. The result is an XML parse tree, also called DOM tree. The tree code is shown with the option "Show XML parse tree" of Special:ExpandTemplates (see mw:Extension:ExpandTemplates#XML parse tree). The parse tree of a page always starts with <root>
and ends with </root>
. These tags are not shown in the examples.
Parsing is done with respect to pairs of double braces Template:Cnw delimiting a template, and pairs of triple braces Template:Cnw delimiting a tplarg. If double opening braces are followed by triple closing braces or conversely, this is taken as delimiting a template, with one left-over brace outside it taken as plain text. For any pattern of braces this defines a set of templates and tplargs such that any two are either separate or nested (not overlapping).
Unmatched double rectangular closing brackets can be in a template or tplarg, but unmatched double rectangular opening brackets cannot. Unmatched double or triple closing braces inside a pair of double rectangular brackets are treated as plain text. Other formulation: in ambiguity between template or tplarg on one hand, and a link on the other hand, the structure with the rightmost opening takes precedence, even if this is the opening of a link without any closing, so not producing an actual link.
Examples (title is in general a part of a template or tplarg, see below, but here the whole of it):
give the parse trees:
In the case of more than three opening braces the last three are assumed to belong to a tplarg, unless there is no matching triple of closing braces, in which case the last two opening braces are are assumed to belong to a template.
Examples:
give the parse trees:
Thus, when nesting two double-brace structures, of which the outer structure does not have any pipe, at least one blank space is needed to avoid the pair of inner three braces to be interpreted as a triple-brace structure, and the outer two braces as plain text. This space does not affect the expanded wikitext because in the next processing phase spaces are stripped from the start and end of title.
Pipes
Templates and tplargs are decomposed in the same way, with pipes as separator, even though eventually any parts in a tplarg after the first (the parameter default) are ignored, and an equals sign in the first part is treated as plain text. Pipes inside inner templates and tplargs, or inside double rectangular brackets within the template or tplargs are not taken into account in this decomposition. The first part is called title<ref>In the case of a parser function, title (function name, colon, and first parameter) should not be confused with just the function name.</ref>, the other parts are simply called parts. If a part has one or more equals signs in it, the first equals sign determines the division into name = value. Equals signs inside inner templates and tplargs, or inside double rectangular brackets within the part are not taken into account in this decomposition. Parts without equals sign are indexed 1, 2, .., given as attribute in the <name> tag.
Examples:
{{ | | [[ | | ]] }} {{{ | | [[ | | ]] }}}
give the parse trees:
<template><title> </title><part><name index="1"/><value> </value></part><part><name index="2"/><value> [[ | | ]] </value></part></template>
<tplarg><title> </title><part><name index="1"/><value> </value></part><part><name index="2"/><value> [[ | | ]] </value></part></tplarg>
and
{{a|b|c=d|e}}
{{{a|b|c=d|e}}}
give the parse trees:
<template><title>a</title><part><name index="1"/><value>b</value></part><part><name>c</name>=<value>d</value></part><part><name index="2"/><value>e</value></part></template>
<tplarg><title>a</title><part><name index="1"/><value>b</value></part><part><name>c</name>=<value>d</value></part><part><name index="2"/><value>e</value></part></tplarg>
This is applied recursively: the wikitexts a, b, c, d, and e can themselves contain similar structures, and are then represented in the tree by similar code.
The parse tree does not distinguish between variables, parser functions, and templates. The <template>
tag refers to any of them. The tree is independent of the existence of a variable, parser function, or template with the given name, so when trying out with Special:ExpandTemplates how the first parsing phase works we do not have to bother using names of actual variables, parser functions, and templates.
Brackets
Like already demonstrated,
{{a|b[[c|d|e=f]]g}}
gives <template><title>a</title><part><name index="1"/><value>b[[c|d|e=f]]g</value></part></template>
However,
{{a|b[c|d|e=f]g}}
gives <template><title>a</title><part><name index="1"/><value>b[c</value></part><part><name index="2"/><value>d</value></part><part><name>e</name>=<value>f]g</value></part></template></root>
and
{{a|b<c d=e>f</c>g}}
gives <template><title>a</title><part><name>b<c d</name>=<value>e>f</c>g</value></part></template>
This demonstrates that double rectangular braces shield pipes and equals signs inside from being considered part of an outer structure, but single rectangular braces and angle brackets do not. (Note also that angle brackets which are not part of the XML tags are written <
and >
to avoid confusion.)
Expanded wikitext
The second step is the conversion of the parse tree to expanded wikitext. The result of the first and second step combined is shown with Special:ExpandTemplates, and with the action=raw&templates=expand parameters in the URL (like this); also the wikitext {{#tag:nowiki|...}}
expands to the expansion of the wikitext at the place of the dots, with the whole inside nowiki tags; hence it is displayed as this expansion of the wikitext at the place of the dots.
The wikitext can be considered a string expression, consisting of string literals without delimiters, and string functions (the brace structures), without operators: the only operation is concatenation by juxtaposition. They have no side effects, except if template limits are exceeded. Exception handling of a function does not stop evaluation of the expression, the function just produces a special return value; e.g. #expr
may produce a message instead of a number; when the #ifexist
limit is exceeded the else-value is returned; when the expand limit has been reached a brace structure is not expanded but returned as text.
There is no feature for entering a parse tree, to see what expanded wikitext it produces. However, to study what expanded wikitext a subtree of the parse tree of a given wikitext produces, one can identify the corresponding part of the wikitext, and use that as input of Special:ExpandTemplates etc. The only context sensitivity is represented in a possible attribute lineStart="1"
in the <template>
tag.
The first expansion step is the expansion of title (the wikitext before the first pipe).<ref>Title is expanded as a single item, therefore the condition in a call of a branching function with not even a then-part is expanded, even though expansion of the function name would be sufficient to conclude that the result is the empty string, regardless of the condition.</ref> The title of a tplarg is always expanded, even in cases where the parameter cannot be defined: if the expansion is for rendering the template itself, and if the template is called without parameters.
Distinction between variables, parser functions, and templates
The distinction between variables, parser functions, and templates is made in function braceSubstitution in Parser.php.
- If there are no parts, and title is a variable name (or
safesubst:
followed by a variable name), then we have a variable.
- Otherwise, if title contains a colon and the part before it forms the name of a parser function (or
safesubst:
followed by the name of a parser function), then we have a parser function with as first parameter the expanded wikitext of the part of title after the colon, while the remaining parameter names (if any) and values are the expanded wikitexts of the names and values of the parts. Some parameters of some parser functions expect plain text as parameters instead of name/value combinations. In that case, if there was a "=" in the text, this text is reconstructed from the supposed name, the "=", and the supposed value. For example, <template><title>#tag:math</title><part><name>a</name>=<value>5</value></part></template>
gives the expanded wikitext <math>a=5</math>
. Parameter values are assigned to parameters in two passes. Therefore a parameter name in a template can depend on the value of another parameter of the same template, regardless of the order in which they are specified in the template call, for example, using Template:ppp containing "{{{{{{p}}}}}}<noinclude>{{doc}}</noinclude>
", {{ppp|p=q|q=r}}
and even {{ppp|q=r|p=q}}
gives r
, but using Template:tvvv containing "{{{{{{{{{p}}}}}}}}}
", {{tvvv|p=q|q=r|r=s}}
gives s
.
- Otherwise, if title is a valid template name (in particular this excludes a name starting with "#") or
safesubst:
followed by the name of an existing template), then we have a template. The representation of the parts corresponds to the distinction between implicitly numbered parameters (with index being the number) and named parameters.
- Otherwise we have plain text.
In the cases mentioned, safesubst:
is ignored.
There are no variable names with a colon in it.<ref>For some variables there is a strongly related parser function with the same name. Therefore some overviews of variables and/or parser functions do not strictly distinguish between them.</ref> However, some variable names, e.g. PAGENAME, are also the name of a parser function. Thus:
- If title is "PAGENAME" and there are no parts, and then we have a variable.
- If title is "PAGENAME" and there are parts then it is a reference to Template:PAGENAME.
- If title is "pAGENAME" then it is anyway a reference to Template:PAGENAME.
- If title starts with "PAGENAME:" then we have a parser function.
- If title starts with "pAGENAME:" then it is a reference to a template.
Examples:
"{{PAGENAME}}"
→ "Expansion" [1]
"{{PAGENAME|}}"
→ "Template:PAGENAME" [2]
"{{pAGENAME}}"
→ "Template:PAGENAME" [3]
"{{PAGENAME:}}"
→ "" [4]
"{{PAGENAME:|}}"
→ "" [5]
"{{PAGENAME:help:def}}"
→ "Def" [6]
"{{PAGENAME:help:def|}}"
→ "Def" [7]
"{{pAGENAME:help:def}}"
→ "Template:PAGENAME:help:def" [8]
Similarly for NUMBEROFPAGES, but a difference is that as parser function with anything else than R as parameter (after the colon), it is equivalent with the variable:
Based on the XML tree, expansion starts with evaluating title for the outermost structures, and in the case of a parser function, the separation between the name and the parameter after the colon.
Expansion of names and values
Which names and values are expanded can be demonstrated by putting a template call in each, and checking the list of templates used in the edit page, see Help:Expansion/1.
For most parser functions all names and values are expanded, regardless of what is relevant for the result. The branching functions (#if, #ifeq, #iferror, #ifexist, #ifexpr, #switch) are exceptions: for #if, #iferror, #ifexist, #ifexp, only the part that is applicable is expanded; for #ifeq the first and the applicable part are expanded; for #switch, expanded are the names up to and including the match (or all if there is no match), and the value in the case of a match or if there is no match, the default, if any.
All names in a template call are expanded, and the titles of the tplargs in the template body, after which it is determined which values must be expanded, and for which tplargs in the template body the first part (default).
In the case of a tplarg, any parts beyond the first are never expanded. The possible name and the value of the first part is expanded if the title does not match a name in the template call.
Braces, pipes, and equals signs produced by expansion
Braces, pipes, and equals signs which are produced by expansion are taken as just characters, not parts of structures, since evaluations happen after the production of the XML tree. A colon does not affect the XML tree anyway, the one after the name of a parser function is just part of title.
For example, using
- Template:1= containing "1={{{1}}}"
- Template:p1=x containing "{{{1=x}}}"
we have:
- {{t1demo|{{{|1=x}}}}} gives start-1=x-end
- {{t1demo|{{#if:x|1=x}}}} gives start-1=x-end
- {{t1demo|{{1=|x}}}} gives start-Template:1=-end
- {{t1demo|{{1=|x}}=y}} gives start-{{{1}}}-end
- {{p1=x|{{{|1=x}}}=y}} gives Template:P1=x
- {{p1=x|{{1=|x}}=y}} gives Template:P1=x
Compare:
"{{1=|x}}"
gives "Template:1=" [15]
- {{t1demo|1=x}} gives start-x-end
- {{t1demo|1=x=y}} gives start-x=y-end
The examples also show that a parameter name "1=x", although impractical, works.
An example of an equals sign in a parameter value not being interpreted in a parameter definition:
- {{t2a1|1=x=y}} (using Template:Tcw and Template:T2demo containing start-{{{1}}}-middle-{{{2}}}-end) gives Template:T2a1.
Balancedness
Any wikitext is of the form )(*( or )*)( where * represents the part from the start of the first structure to the end of the last, and each parenthese represents zero or more sets of double or triple braces. If there is no such set, neither something similar for double rectangular brackets, then the wikitext is balanced.
If a wikitext is unbalanced then inserting that wikitext by hand or with substitution into another wikitext, or concatenating the two, may change some of the structures or add new ones, perhaps unintendedly, instead of only nesting them. If one wikitext is transcluded in the other there is no such complication.
A page demonstrating the result of excess closing braces and excess opening braces should put the live examples in that order, as is done in the next section.
Sensitivity to missing or excess braces
A wikitext with various pairs of double braces, e.g. {{#switch:r|p=q|r={{tc}}|s=t}} (and what is worse, also a more complicated one) is, of course, very sensitive to missing or excess braces. In the case of missing opening braces of Template:Tc, i.e. "tc}}", its closing braces are taken as closing braces of #switch, so all remaining wikitext intended to be inside the switch is now outside, and therefore shown independent of a switch index match. The latter also happens in the case of excess closing braces of tc: "{{tc}}}}". The intended closing braces of the switch are taken as plain text.
In the case of missing closing braces in "{{tc}}", i.e. "{{tc", the intended closing braces of the switch are taken as closing braces of Template:Tc (or more generally, as closing braces of the highest level under switch), so the switch does not have closing braces and is therefore not expanded. The latter also happens in the case of excess opening braces of tc: "{{{{tc}}".
In the case of missing closing braces or excess opening braces somewhere on a page, and also missing opening braces or excess closing braces further on on the same page, all text in between is considered part of the template call or parser function call etc., so it may not be shown, shown multiple times, etc., e.g.:
- "{{#switch:p|p=q|r={{tc|s=t}} ... {{#switch:p|p=q|r=tc}}|s=t}}" gives "q" (seemingly unrelated text "..." disappears)
Special:ExpandTemplates essentially shows how braces are grouped into double and triple braces, but an end tag does not show to which start tag it belongs, and a simple braces error in a wikitext with many braces can be cumbersome to find. Therefore techniques to keep things manageable are useful.
To avoid that a possible braces error in a part of the wikitext of a page affects the expansion of a later part one can temporarily add excess closing braces after the part with the possible errors, at a point in the wikitext that is supposed to be on the top level (outside braces):
- "{{#switch:p|p=q|r={{tc|s=t}} }}}}}} ... {{#switch:p|p=q|r=tc}}|s=t}}" gives "q}}}} ... q|s=t}}" (text "..." is preserved)
This raises the point of insertion to the top level (if enough closing braces are used), so that it is not part of the call of a template etc., so not conditional, not used multiple times, etc.
Further examples:
- {{#switch:p|p=q|r={{tc}}|s=t}} gives q
- {{#switch:q|p=q|r={{tc}}|s=t}} gives
- {{#switch:r|p=q|r={{tc}}|s=t}} gives in
- {{#switch:p|p=q|r=tc}}|s=t}} gives q|s=t}}
- {{#switch:q|p=q|r=tc}}|s=t}} gives |s=t}}
- {{#switch:r|p=q|r=tc}}|s=t}} gives tc|s=t}}
- {{#switch:p|p=q|r={{tc|s=t}} gives {{#switch:p|p=q|r=in
- {{#switch:q|p=q|r={{tc|s=t}} gives {{#switch:q|p=q|r=in
- {{#switch:r|p=q|r={{tc|s=t}} gives {{#switch:r|p=q|r=in
Another method of containing the propagation of any braces error in some wikitext is putting it in a template. For example, if the wikitext with the braces error is "{{", which is the content of Template:Lb, then {{1x|{{#if:|{{lb}}}} ...}} gives " ...", while {{1x|{{#if:|{{}} ...}} gives "{{1x|" (the text "..." is preserved in the first case, but not in the second).
We can apply this method e.g. for a switch, i.e. make each case a template call. If the overall template only contains this switch, based on a parameter, we can dispense with the overall template alltogether and call the subtemplates directly, and they can have one parameter less, except possibly for the default case. If the name of the subtemplate is obtained by concatenation of the name of the overall template and the value of the parameter the template call gets even shorter: {{p|q=r|s=t}} or {{p|r|s=t}} becomes {{pr|s=t}} for supported values of r. In this case there is no mechanism to handle an unsupported r: while with the switch we get nothing or the default, here we would get a call of a non-existing template, giving a red link. Alternatively we could use something like {{p{{#switch:r|.|.|.=r|default}}|s=t}} or {{ {{#switch:r|.|.|.=pr|void}}|s=t}}.
Compare the choice between using switch for an array and using a template for each element.
Advantages of having only a single template:
- easier to copy (to another wiki, or to make a different version)
- easier to get an overview of everything; however, this can be obtained on a separate page showing the contents of the templates with msgnw, see e.g. Template:Xpd/msgnw
- easier to make overall find/replace changes, etc.
- a common part before or after the switch is possible without duplication
- in the case of a common part, although it can be made a template, with subtemplates we at least need a template call in each
Advantages of having a template for each case:
- no propagation of wikitext errors
- less server load
Efficiency
Suppose a string S is the result of some expansion, and needed multiple times. For example, S is the municipality a given town belongs to, which is looked up in a table, and it is used for display, and for looking up the province it belongs to. Then we want to avoid that the server needs to determine the municipality twice. In a computer program we could use a variable S, but in MediaWiki (without VariablesExtension) the way to do this is with a template that uses a parameter for S. This way S is expanded only once. While extra layers of templates can increase page counts, they can in a case like this reduce them. In particular, if the lookup is done in a data template containing many data items, the preprocessor node count is often large, unless the data template stores the data in the form of values of unnamed parameters (which would not be possible in the example because we start from a given town name, not an integer), so avoiding duplication is worthwhile.
Some other cases where a template is needed to avoid duplicate expansion:
- finding a number and determining its order of magnitude to determine the desired rounding
- finding a population figure for display and for computation of the population density
- if S represents a number, computing S + 1 / S
There are also cases where a formula can be rewritten, such that S occurs only once. For example, in an expression we can write (S+.5)^2-.25
instead of S*(1+S)
.
See also Help:Template#Page counts.
Intermediate results
In the process from wikitext to rendering, the XML tree and the expanded wikitext are intermediate results which help to understand the process. Another intermediate result that can similarly be helpful is the HTML sent to the browser.
Using XML-style tag nowiki, <nowiki>{{t1demo| ''p'' > 1 }}</nowiki> displays the wikitext, and with #tag, {{#tag:nowiki|{{t1demo| ''p'' > 1 }}}} displays the expanded wikitext.
Thus we have e.g.:
wikitext
{{t1demo| ''p'' > 1 }}
{{#tag:nowiki|{{t1demo| ''p'' > 1 }}}}
<nowiki>{{t1demo| ''p'' > 1 }}</nowiki>
expanded wikitext
start- ''p'' > 1 -end
<nowiki>start- ''p'' > 1 -end</nowiki>
<nowiki>{{t1demo| ''p'' > 1 }}</nowiki>
HTML
start- <i>p</i> > 1 -end
start- ''p'' > 1 -end
{{t1demo| ''p'' > 1 }}
rendering
start- p > 1 -end
start- ''p'' > 1 -end
{{t1demo| ''p'' > 1 }}
The step from HTML to rendering depends on CSS: common and personal CSS files referred to in the HTML code, as well as possibly a CSS file specified in the browser.
Substitution
If a save command is applied to a page containing one or more titles starting with subst:
or safesubst:
, the wikitext is modified before saving. This substitution process treats all templates without subst:
or safesubst:
on the page and in directly or indirectly substituted templates as plain text. It also treats all tplargs on the page as plain text. The new wikitext is equal to what the expanded wikitext resulting from the wikitext without these occurrences of subst:
or safesubst:
would be if the other structures were treated as plain texts. For any substitution to occur there has to be at least one explicit occurrence of subst:
or safesubst:
on the page itself. If the substituted title is inside another title it may construct a text subst:
or safesubst:
causing that other title to be substituted too, etc. A text subst:
or safesubst:
in a substituted template can also be constructed with a tplarg (parameter value or default value).
Examples:
{{subst:lc:{{TC}}}}
changes to {{tc}}
.
{{subst:urlencode:{{tc}}}}
changes to %7B%7Btc%7D%7D
.
{{subst:lc:{{{A|B}}}}}
changes to {{{a|b}}}
.
{{su{{su{{subst:1x|bs}}t:1x|bs}}t:tc}}
changes to in
.
Special:ExpandTemplates can be used as usual to find the parse tree of wikitext containing "subst:" or "safesubst:", but it cannot be used to find the new wikitext. For this, one should use "show changes", or save a test page and press edit to see the result. In Special:ExpandTemplates the title starting with "subst:" is treated as an invalid template name, so "{{subst:" and the corresponding "}}" are treated as plain text. Prefixes "safesubst:" are ignored, like when they are in a transcluded page.
If a template contains a template call with subst:
, then if the outer template is transcluded the inner template call is not expanded, while if the outer template is substituted the inner template call is expanded. This can be used for branching depending on whether the outer template is transcluded or substituted.
Example:
{{#if:{{{{{|subst:}}}ns:0}}|transcluded|substituted}}
Expansion depth limit
There is an "expansion depth limit" of 40, see Help:Expansion depth.
Internal code for parts in XML-style tags
XML-style tags, e.g. <nowiki>
tags and <math>
tags, together with their content, are temporarily replaced by a so-called strip marker, a unique code with a length of ca. 37 characters plus the length of the tag name (independent of the length of the content). If a string operation is applied to it, only fully intact codes in the result are converted back to the original text, the rest is exposed. For example:
{{formatnum:<nowiki></nowiki>}}
gives .
See also
<references group=""></references>
Links to other help pages
- Reading
- Go · Search · Stop words · Namespace · Page name · Section · Backlinks · Redirect · Category · Image page · Special pages · Printable version
- Logging in and preferences
- Logging in · Preferences · User style
- Referencing
- Links · URLs · Piped links · Interwiki linking · Footnotes
- Style and formatting
- Wikitext examples · CSS · Reference card · HTML in wikitext · Formula · List · Table · Sorting · Colors · Images and file uploads
- Fixing mistakes
- Show preview · Testing · Reverting edits
- Advanced functioning
- Expansion · Template · Advanced templates · Parser function · Parameter default · Variable · System message · Substitution · Array · Calculation · Embed page