Module:Template parameter value
| This Lua module is used on approximately 11,700,000 pages, or roughly 18% of all pages. To avoid major disruption and server load, any changes should be tested in the module's /sandbox or /testcases subpages, or in your own module sandbox. The tested changes can be added to this page in a single edit. Consider discussing changes on the talk page before implementing them. |
| This module depends on the following other modules: |
Implements {{Template parameter value}} and {{HasTemplate}}, and can be used from other modules.
Module functions
getParameter
getParameter takes 4 arguments: The page name (string), the template/s (string or table of strings), the parameter (string), and an optional options table. It will return either true and the contents of the requested parameter or false and a reason for failure.
The following options are available:
- template_index: Which occurrence of the template to look for the parameter in. Set to -1 for last occurrence. (default: 1)
- parameter_index: Which occurrence of the parameter to look for (default: 1; only applies when
ignore_subtemplatesis false) - ignore_subtemplates: If parameters should only be searched for in the top-level template, ignoring the parameters in subtemplates (default: false)
- only_subtemplates: If parameters should only be searched for in subtemplates of the top-level template (default: false)
- ignore_blank: Whether or not blank values should count towards
parameter_index(default: false) - treat_as_regex: Whether or not the template string(s) should be treated as a lua regex (default: false)
getTemplate
getTemplate takes 3 arguments: The page name (string), the template/s (string or table of strings), and an optional options table. It will return either true and the text of the requested template or false and a reason for failure.
getTemplate supports the options template_index and treat_as_regex from getParameter.
Helper functions
The module exposes some of the helper functions used (matchAllTemplates, getParameters, and getAllParameters) for convenience. Each function has some comments above it in the code explaining its rough purpose.
Template functions
main implements {{Template parameter value}} and acts as a template wrapper for getParameter.
hasTemplate implements {{HasTemplate}} and somewhat acts as a wrapper for getTemplate (it only provides if the template was found, not the template text itself).
Testcases
Testcases are available at Module talk:Template parameter value/testcases
local p = {}
local PrepareText = require("Module:Wikitext Parsing").PrepareText
local function getTitle(title)
local success, titleObj = pcall(mw.title.new, title)
if success then return titleObj
else return nil end
end
--string.gmatch will check the largest block it can without re-scanning whats inside, but we need whats inside
local function matchAllTemplates(str)
local matches = {}
for template in string.gmatch(str, "{%b{}}") do
table.insert(matches, template)
local innerContent = string.sub(template, 3, -3)
for _,subtemplate in next,matchAllTemplates(innerContent) do
table.insert(matches, subtemplate)
end
end
return matches
end
--Forked version of getParameters from [[Module:Transcluder]] with extra features removed
local function escapeString(str)
return string.gsub(str, '[%^%$%(%)%.%[%]%*%+%-%?%%]', '%%%0')
end
local function getParameters(template)
local parameters, parameterOrder = {}, {}
local params = string.match(template, '{{[^|}]-|(.*)}}')
if params then
local count = 0
-- Temporarily replace pipes in subtemplates and wikilinks to avoid chaos
for subtemplate in string.gmatch(params, '{%b{}}') do
params = string.gsub(params, escapeString(subtemplate), string.gsub(subtemplate, ".", {["%"]="%%", ["|"]="@@:@@", ["="]="@@_@@"}) )
end
for wikilink in string.gmatch(params, '%[%b[]%]') do
params = string.gsub(params, escapeString(wikilink), string.gsub(wikilink, ".", {["%"]="%%", ["|"]="@@:@@", ["="]="@@_@@"}) )
end
for parameter in mw.text.gsplit(params, '|') do
local parts = mw.text.split(parameter, '=')
local key = mw.text.trim(parts[1])
local value
if #parts == 1 then
value = key
count = count + 1
key = tostring(count)
else
value = mw.text.trim(table.concat(parts, '=', 2))
end
value = string.gsub(string.gsub(value, '@@:@@', '|'), '@@_@@', '=')
key = string.gsub(string.gsub(key, '@@:@@', '|'), '@@_@@', '=')
table.insert(parameterOrder, key)
parameters[key] = value
end
end
return parameters, parameterOrder
end
-- Returns a table containing parameters and a table with the order in which each of their values were found.
-- Since this considers all subtemplates, a single parameter is expected to have multiple values.
-- E.g. {{ABC|X={{DEF|X=Value|Y=Other value}}{{ABC|X=Yes}}|Y=P}}
-- Would return {X={"{{DEF|X=Value|Y=Other value}}", "Value", "Yes"}, Y={"Other value", "P"}}
local function getAllParameters(template, ignore_blank, only_subtemplates)
local parameterTree = setmetatable({}, {
__index = function(self,key)
rawset(self,key,{})
return rawget(self,key)
end
})
local params, paramOrder = getParameters(template)
for _,key in ipairs(paramOrder) do
local value = params[key]
if not ignore_blank or value ~= "" then
if not only_subtemplates then
table.insert(parameterTree[key], value) --Insert the initial value into the tree
end
for subtemplate in string.gmatch(value, "{%b{}}") do --And now check for subvalues
local subparams = getAllParameters(subtemplate, ignore_blank)
for subkey,subset in next,subparams do
for _,subvalue in ipairs(subset) do
table.insert(parameterTree[subkey], subvalue) --And add any we find to our tree
end
end
end
end
end
return parameterTree
end
--Primary module entry point. Returns a success boolean and either the result or why it failed
function p.getValue(page, templates, parameter, options)
if not (templates and parameter) then --Required parameters
return false, "Missing required parameters 'templates' and 'parameter'"
end
parameter = tostring(parameter) --Force consistency
options = options or {}
local template_index = tonumber(options.template_index) or 1
local parameter_index = tonumber(options.parameter_index) or 1
local ignore_subtemplates = options.ignore_subtemplates or false
local only_subtemplates = options.only_subtemplates or false
local ignore_blank = options.ignore_blank or false
local treat_as_regex = options.treat_as_regex or false
if type(templates) == "string" then
templates = mw.text.split(templates, ", ?")
end
local title = getTitle(page)
if title == nil then
return false, "Requested title doesn't exist"
end
local content = PrepareText(title:getContent() or "")
local foundTemplates = 0
for _,template in next,matchAllTemplates(content) do
for _,wantedTemplate in pairs(templates) do
if not treat_as_regex then
wantedTemplate = escapeString(wantedTemplate)
end
local firstLetter = string.sub(wantedTemplate, 1, 1)
local firstUpper, firstLower = firstLetter:upper(), firstLetter:lower()
if firstUpper ~= firstLower then
wantedTemplate = "[" .. firstUpper .. firstLower .. "]" .. string.sub(wantedTemplate, 2)
end
if string.match(template, "^{{%s*"..wantedTemplate.."%s*[|}]") then
foundTemplates = foundTemplates + 1
if foundTemplates == template_index then --Found our wanted template
local value
if ignore_subtemplates then
value = getParameters(template)[parameter] or ""
else
local params = getAllParameters(template, ignore_blank, only_subtemplates)
value = params[parameter][parameter_index] or ""
end
value = string.gsub(value, "</?%a*include%a*>", "")
value = mw.text.trim(value)
return true, mw.text.decode(value) --due to PrepareText
end
end
end
end
return false, "No valid template found"
end
--Template entry point. Returns an empty string upon failure
function p.main(frame)
local args = require('Module:Arguments').getArgs(frame, {
wrappers = 'Template:Template parameter value'
})
local yesno = require("Module:Yesno")
local options = {
template_index = args[3],
parameter_index = args[5],
ignore_subtemplates = yesno(args.ignore_subtemplates or args.ist) or false,
only_subtemplates = yesno(args.only_subtemplates) or false,
ignore_blank = yesno(args.ignore_blank) or false,
treat_as_regex = yesno(args.treat_as_regex) or false,
}
local success, result = p.getValue(args[1], args[2], args[4], options)
if not success then
return ""
else
if args.dontprocess then
return result
else
return frame:preprocess(result)
end
end
end
--Potentially useful module entry points
p.matchAllTemplates = matchAllTemplates
p.getParameters = getParameters
p.getAllParameters = getAllParameters
return p