Extension:External Data/Retrieving and displaying data
External Data offers four basic ways to retrieve outside data and display it on the page: #external_value, #for_external_table, #display_external_table and #format_external_table. Although they are considered deprecated, you can also use the legacy #get_*_data functions to do the initial retrieval step; examples of both methods are shown below.
If Scribunto is installed, a Lua module can access external data by calling mw.ext.externalData.getExternalData()
.
The examples on this page all involve querying web data (the most popular data source), but External Data also supports retrieving data from many other data sources, including databases, LDAP servers and local files. For more information on these, and on web data retrieval itself, see the "Data sources" section in the navigation bar above. As of version 3.0, these other data sources can be used directly within #for_external_table
and similar parser functions described here, specifying other necessary parameters such as |source=
at the end of the parameter list; see #"Legacy" versus "Standalone" mode for details.
"Legacy" versus "Standalone" mode
Glossary entries: Standalone mode • Legacy mode
As of version 3.2 of this extension, external data sources are both retrieved and displayed within a single call #for_external_table and #display_external_table and similar parser functions. Parameters necessary for the data source itself (such as |source=
, |db=
, or |url=
) are specified at the end of the parameter list. This obviates the need to use #get_external_data
, #get_db_data
or similar, and then call the display parser functions separately, which is how things were done in the 2.x series.
The new all-in-one method is called the standalone mode and the other method legacy mode. "Standalone" mode is preferred going forward, for best compatibility with Parsoid. New releases of External Data require an additional LocalSettings.php setting to enable the legacy mode.
Below is a comparison of the two methods, using the #external_value display function in a simple example. This one-line CSV file (with a header) is used as the external data source. The notable difference is that "legacy" mode requires a separate #get_web_data to actually fetch the data from the remote server. In this contrived example, "standalone" entails a bit more repetition (of the URL), but ends up being more concise in real-world usage with tabular data and display functions like #for_external_table
.
Standalone mode | Legacy mode | Expected result |
---|---|---|
* Germany has population {{#external_value:Population|source=https://discoursedb.org/GermanyCSV.txt}}. * Germany has area {{#external_value:Area|source=https://discoursedb.org/GermanyCSV.txt}}. * Its capital is {{#external_value:Capital|source=https://discoursedb.org/GermanyCSV.txt}}. |
{{#get_web_data:url=https://discoursedb.org/GermanyCSV.txt|data=population=Population,area=Area,capital=Capital}} * Germany has population {{#external_value:population}}. * Germany has area {{#external_value:area}}. * Its capital is {{#external_value:capital}}. |
|
Hint: The #arraymap
parser function from Extension:Page Forms may come in handy for further parsing of individual values.
"Limited" versus "Intuitive" parsing
Glossary entries: Limited parsing • Intuitive parsing
Most of External Data's display parser functions accept an "expression" parameter: wikitext which is combined values from with the external data source and rendered to the page. In reference to this expression parameter, you will see "limited parsing" or "the old way" and "intutive parsing" mentioned in examples below.
Here are the differences:
- The limited parsing or "old" method passes the wikitext expression as the first parameter.
- example:
{{#for_external_table:expression}}
(note the lack of a leading pipe here) - This method does not correctly expand templates and parser functions within
expression
. It is maintained for backward compatibility, but is not preferred if you're using External Data ≥ 3.0 where "intuitive" parsing is supported.
- example:
- The intuitive parsing or "new" method passes the wikitext expression as the second parameter, while the first is empty. This is the preferred method when using External Data ≥ 3.0.
- example:
{{{#for_external_table:|expression}}
- With this method, templates and parser functions in
expression
, even wrapping the{{{variable}}}
macros, will work just as they normally would in body text or within templates.
- example:
Displaying individual values
See also: Tag emulation mode
To display just a single value from an outside source, use the #external_value
parser function:
{{#external_value:local variable name|optional fallback value}}
The optional fallback value
can contain wiki markup, including additional {{#external_value:}}
calls.
By default, #external_value
displays an error message if it is called for a variable that has not been set, or if the specified data source is inaccessible, or the data source does not contain any data.
There is no provision for a fallback/default value if the request fails, but you can disable the error message by adding $wgExternalDataVerbose = false;
to LocalSettings.php:
#external_value example
Given this comma-delimited external data file[1]
Area,Borders,Capital,Population "357,050 km²","Austria,Belgium,Czech Republic,Denmark,France,Luxembourg,Netherlands,Poland,Switzerland",Berlin,"82,411,001"
…the table below demonstrates how to retrieve individual values with #external_value
.
Standalone mode | Legacy mode | Expected output |
---|---|---|
* Germany borders the following countries: {{#arraymap:{{#external_value:Borders|source=https://discoursedb.org/GermanyCSV.txt|format=csv with header}}|,|x|[[w:x|]]}}. * Germany has population {{#external_value:Population|source=https://discoursedb.org/GermanyCSV.txt}}. * Germany has area {{#external_value:Area|source=https://discoursedb.org/GermanyCSV.txt}}. * Its capital is [[w:{{#external_value:Capital|source=https://discoursedb.org/GermanyCSV.txt}}|]]. |
{{#get_web_data:url=https://discoursedb.org/GermanyCSV.txt|format=csv with header|data=bordered countries=Borders,population=Population,area=Area,capital=Capital}} * Germany borders the following countries: {{#arraymap:{{#external_value:bordered countries}}|,|x|[[w:x|]]}}. * Germany has population {{#external_value:population}}. * Germany has area {{#external_value:area}}. * Its capital is [[w:{{#external_value:capital}}|]]. |
|
The |format=
in the first #external_value
of the Standalone example is for demonstration purposes only. In actuality, this file format (CSV with headers) is properly auto-detected.
For the bordered countries
value, Page Forms' #arraymap
function as well as the pipe trick are employed to split the comma-delimited value apart and make each country's name into a wikilink.
Displaying a table of values
If you want to retrieve and display tabular data, you can use any of the display functions #for_external_table, #display_external_table, or #format_external_table.
#for_external_table
The #for_external_table
display function renders arbitrary wikitext for each row of tabular data source. As mentioned above, it can be called with the limited parsing format, but the recommended method supplies the expression
as the second parameter, while the first is empty. This way, templates and parser functions in expression
, even surrounding the {{{variable}}}
macros, will work as expected.
Call this display function like this in "legacy" mode, when preceded by a {{#get_*_data}}
function elsewhere on the page
{{#for_external_table:|expression}}
…or like this in "standalone" mode, where the parameters for the data source like |source=
or |url=
come at the end:
{{#for_external_table:|expression|optional data source parameters}}
The expression
parameter is a string that contains one or more macros. You can think of these like parameters in the context of MediaWiki templates.
As with template parameters, macros are denoted by a name surrounded in curly brackets, with an optional value specified after a pipe, e.g. {{{var}}}
and {{{var|default}}}
.
The default value used if the variable's value would be empty in the current loop.
The expression
string is then evaluated for each row of the external data source, macros are replaced by their corresponding values (or defaults), and the resulting wikitext is inserted into the page.
#for_external_table example
Let's try a similar example to #external_value above, but with multiple countries in a two-dimensional input file, rather than a single list of values. Given this external data file
Country,Area,Borders,Capital,Population Algeria,"2,381,743 km²","Libya,Mali,Mauritania,Niger,Tunisia",Algiers,"32,854,002" Angola,"1,246,700 km²","Democratic Republic of the Congo,Namibia,Zambia",Luanda,"24,383,301" Benin,"112,620 km²","Burkina Faso,Niger,Nigeria,Togo",Porto-Novo,"8,439,000"
the table below demonstrates how to retrieve rows of data from a delimited data file on a remote server using #for_external_data
.[2]
Standalone mode | Legacy mode |
---|---|
{| class="wikitable" ! Name ! Borders ! Population ! Area {{#for_external_table:| {{!}}- {{!}} {{{name}}} {{!}} {{{borders}}} {{!}} {{{population}}} {{!}} {{{area}}} | url = https://discoursedb.org/AfricaCSV.txt | format = csv with header | data = name=Country,borders=Borders,population=Population,area=Area }} |} |
{{#get_web_data:url = https://discoursedb.org/AfricaCSV.txt | format = csv with header | data = name=Country,borders=Borders,population=Population,area=Area}} {| class="wikitable" ! Name ! Borders ! Population ! Area {{#for_external_table:<nowiki/> {{!}}- {{!}} {{{name}}} {{!}} {{{borders}}} {{!}} {{{population}}} {{!}} {{{area}}}}} |} |
As mentioned in the previous section, the |format=csv with header
isn't strictly necessary here, as this particular data file's format would be auto-detected just fine. It's nonetheless shown for demonstration purposes.
The first or second argument to #for_external_table
holds the wikitext expression that will be used to form the rows of the table from each incoming data record; it's surrounded by ordinary wikitext to create the top and bottom of the table.
The {{!}} template is a standard MediaWiki trick to be able to use literal pipe characters in arguments to templates and parser functions.
Here's the expected output for either of the above methods:
Name | Borders | Population | Area |
---|---|---|---|
Algeria | Libya,Mali,Mauritania,Niger,Tunisia | 32,854,002 | 2,381,743 km² |
Angola | Democratic Republic of the Congo,Namibia,Zambia | 24,383,301 | 1,246,700 km² |
Benin | Burkina Faso,Niger,Nigeria,Togo | 8,439,000 | 112,620 km² |
Using #for_external_table for lists
Using #for_external_table
to build an HTML table is the standard approach, but it may also be used to create lists:
{{#for_external_table:| * {{{name}}} has the following borders: {{{borders}}}. }}
See #Caveat: whitespace trimming if you're using the "old" method of passing the expression as the first parameter to the parser function.
Modifying values in place
There are two extra helpers for building URLs and query strings: {{{fieldname.urlencode}}}
and {{{fieldname.htmlencode}}}
[3]. See the table below for examples.
These are especially useful when passing the expression the "old" way, as the first parameter to the parser function, because built-in parser functions like {{urlencode:…}}
are not recognized in that case.
As noted above, the "new" way of passing the expression as the second parameter is recommended; this is supported from version 3.0 onward.
When used in an expression passed as the… | Examples | Notes | ||
---|---|---|---|---|
1st parameter (old style) | 2nd parameter (recommended style) | |||
URL-encoding | {{{fieldname.urlencode}}}
| {{urlencode:{{{fieldname}}}}}
| <!-- "old" style --> {{#for_external_table: http://www.google.com/search?q={{{term.urlencode}}}}} <!-- recommended style --> {{#for_external_table:|http://www.google.com/search?q={{urlencode:{{{term}}}}}}} | As mentioned above, parser functions aren't understood in the first parameter (old style), so this wouldn't work: {{#for_external_table: http://www.google.com/search?q={{urlencode:{{{term}}}}}}}
|
HTML-encoding | {{{fieldname.htmlencode}}}
| same; MediaWiki has no built-in direct replacement | {{{field-name.htmlencode}}} | Analogous to PHP's htmlentities function
|
Caveat: whitespace trimming
If the wiki markup is passed as the first parameter to the display function ("limited" parsing), its leading whitespace is trimmed.
If a leading line break is required, e.g., to start a new table row or list item, prepend the parameter with <nowiki />
to preserve this line break like so:
{| class="wikitable" ! Name ! Borders ! Population ! Area {{#for_external_table:<nowiki /> {{!}}- {{!}} {{{name}}} {{!}} {{{borders}}} {{!}} {{{population}}} {{!}} {{{area}}} }} |}
#display_external_table
The #display_external_table
display function is similar in concept to #for_external_table, but it passes the each row of values to a template which handles the display.
This function is called as:
{{#display_external_table: template = template name | data = set of parameters, separated by commas | delimiter = delimiter | intro template = template name (optional) | outro template = template name (optional) }}
An explanation of the parameters:
|template=
- the name of the template into which each "row" of data will be passed|data=
- the data mappings between external variable and local template parameter; much like thedata
parameters for the other functions|delimiter=
- the separator used between one template call and the next; default is a newline. (To include newlines in the delimiter value, use "\n".)|intro template=
- a template displayed before the results set, only if there are any results|outro template=
- a template displayed after the results set, only if there are any results
For example, to display the data from the previous example in a table as before, you could create a template called "Country info row", that had the parameters "Country name", "Countries bordered", "Population" and "Area", and then call the #display_external_table
parser function as follows:
Standalone mode | Legacy mode |
---|---|
{| class="wikitable" ! Name ! Borders ! Population ! Area {{#display_external_table: source = https://discoursedb.org/AfricaCSV.txt | format = CSV with header | data = Country name=Country,Countries bordered=borders,Population=population,Area=area | template = Country info row}} |} |
{{#get_web_data:url = https://discoursedb.org/AfricaCSV.txt | format = CSV with header | data = Country name=Country,Countries bordered=borders,Population=population,Area=area }} {| class="wikitable" ! Name ! Borders ! Population ! Area {{#display_external_table:template = Country info row}} |} |
The template "Country info row" referenced by the |template=
parameter should contain wikitext similar to following:
|- | {{{Country name}}} | {{{Countries bordered}}} | {{{Population}}} | {{{Area}}}
#format_external_table
The #format_external_table
parser function is available if External Data ≥ 3.0 and Cargo ≥ 3.0 are installed. It passes the retrieved external data as a row-based two-dimensional array to the Cargo formatting engine, the same as used by the #cargo_query parser function. The function accepts the same parameters controlling the display as #cargo_query
, as well as an optional |data=
parameter which can be used to limit the number of displayed external variables, control their order and field aliases.
Example:
Standalone mode | Legacy mode |
---|---|
{{#format_external_table:source=https://expert.ru/avtory/konstantin_pakhunov/ | format = HTML | data = Title=article h2>a,URL=article h2>a.attr(href) | display format = table}} |
{{#get_external_data: url = https://expert.ru/avtory/konstantin_pakhunov/ | format = HTML | data = title=article h2>a,url=article h2>a.attr(href) }} {{#format_external_table:display format = table | data = Title=title,URL=url}} |
In Lua, the Cargo Lua function mw.ext.cargo.formatTable(table, parameters)
can be applied to the results returned by mw.ext.externalData.getExternalData()
function family to achieve similar results.
References
- ↑ Full example at https://discoursedb.org/wiki/Germany
- ↑ Full example at https://discoursedb.org/wiki/Countries_of_Africa
- ↑ See includes/EDParserFunctions.php around line 140