-- Version: 2021-01-03-- Module to implement getValue from Module:WikidataIB attempting to minimise resource use
local p =
local cdate -- initialise as nil and only load _complex_date function if needed-- is loaded lazily and has the following dependencies:-- Module:I18n/complex date, Module:ISOdate, Module:DateI18n (alternative for Module:Date),-- Module:Formatnum, Module:I18n/date, Module:Yesno, Module:Linguistic, Module:Calendar-- The following, taken from https://www.mediawiki.org/wiki/Wikibase/DataModel#Dates_and_times,-- is needed to use Module:Complex date which seemingly requires date precision as a string.-- It would work better if only the authors of the mediawiki page could spell 'millennium'.local dp =
local i18n =-- This allows an internationisation module to override the above tableif 'en' ~= mw.getContentLanguage:getCode then require("Module:i18n").loadI18n("Module:WikidataIB/i18n", i18n)end
-- This piece of html implements a collapsible container. Check the classes exist on your wiki.local collapsediv = '
'
-- Some items should not be linked.-- Each wiki can create a list of those in Module:WikidataIB/nolinks-- It should return a table called itemsindex, containing true for each item not to be linkedlocal donotlink = local nolinks_exists, nolinks = pcall(mw.loadData, "Module:WikidataIB/nolinks")if nolinks_exists then donotlink = nolinks.itemsindexend
--------------------------------------------------------------------------------- Private functions------------------------------------------------------------------------------------------------------------------------------------------------------------------ findLang takes a "langcode" parameter if supplied and valid-- otherwise it tries to create it from the user's set language -- failing that it uses the wiki's content language.-- It returns a language object--------------------------------------------------------------------------------- Dependencies: none-------------------------------------------------------------------------------local findLang = function(langcode) local langobj langcode = mw.text.trim(langcode or "") if mw.language.isKnownLanguageTag(langcode) then langobj = mw.language.new(langcode) else langcode = mw.getCurrentFrame:callParserFunction('int',) if mw.language.isKnownLanguageTag(langcode) then langobj = mw.language.new(langcode) else langobj = mw.language.getContentLanguage end end return langobjend
--------------------------------------------------------------------------------- roundto takes a number (x)-- and returns it rounded to (sf) significant figures--------------------------------------------------------------------------------- Dependencies: none-------------------------------------------------------------------------------local roundto = function(x, sf) if x
math.floor(x) then x = math.floor(x) end return xend
--------------------------------------------------------------------------------- decimalToDMS takes a decimal degrees (x) with precision (p)-- and returns degrees/minutes/seconds according to the precision--------------------------------------------------------------------------------- Dependencies: none-------------------------------------------------------------------------------local decimalToDMS = function(x, p) -- if p is not supplied, use a precision around 0.1 seconds if not tonumber(p) then p = 1e-4 end local d = math.floor(x) local ms = (x - d) * 60 if p > 0.5 then -- precision is > 1/2 a degree if ms > 30 then d = d + 1 end ms = 0 end local m = math.floor(ms) local s = (ms - m) * 60 if p > 0.008 then -- precision is > 1/2 a minute if s > 30 then m = m +1 end s = 0 elseif p > 0.00014 then -- precision is > 1/2 a second s = math.floor(s + 0.5) elseif p > 0.000014 then -- precision is > 1/20 second s = math.floor(10 * s + 0.5) / 10 elseif p > 0.0000014 then -- precision is > 1/200 second s = math.floor(100 * s + 0.5) / 100 else -- cap it at 3 dec places for now s = math.floor(1000 * s + 0.5) / 1000 end return d, m, send
--------------------------------------------------------------------------------- decimalPrecision takes a decimal (x) with precision (p)-- and returns x rounded approximately to the given precision-- precision should be between 1 and 1e-6, preferably a power of 10.--------------------------------------------------------------------------------- Dependencies: none-------------------------------------------------------------------------------local decimalPrecision = function(x, p) local s = 1 if x < 0 then x = -x s = -1 end -- if p is not supplied, pick an arbitrary precision if not tonumber(p) then p = 1e-4 elseif p > 1 then p = 1 elseif p < 1e-6 then p = 1e-6 else p = 10 ^ math.floor(math.log10(p)) end x = math.floor(x / p + 0.5) * p * s -- if it's integral, cast to an integer: if x
--------------------------------------------------------------------------------- dateFormat is the handler for properties that are of type "time"-- It takes timestamp, precision (6 to 11 per mediawiki), dateformat (y/dmy/mdy), BC format (BC/BCE),-- a plaindate switch (yes/no/adj) to en/disable "sourcing circumstances"/use adjectival form,-- any qualifiers for the property, the language, and any adjective to use like 'before'.-- It passes the date through the "complex date" function-- and returns a string with the internatonalised date formatted according to preferences.--------------------------------------------------------------------------------- Dependencies: findLang; cdate; dp[]-------------------------------------------------------------------------------local dateFormat = function(timestamp, dprec, df, bcf, pd, qualifiers, lang, adj, model) -- output formatting according to preferences (y/dmy/mdy/ymd) df = (df or ""):lower -- if ymd is required, return the part of the timestamp in YYYY-MM-DD form -- but apply Year zero#Astronomers fix: 1 BC = 0000; 2 BC = -0001; etc. if df
"+" then return timestamp:sub(2,11) else local yr = tonumber(timestamp:sub(2,5)) - 1 yr = ("000" .. yr):sub(-4) if yr ~= "0000" then yr = "-" .. yr end return yr .. timestamp:sub(6,11) end end -- A year can be stored like this: "+1872-00-00T00:00:00Z", -- which is processed here as if it were the day before "+1872-01-01T00:00:00Z", -- and that's the last day of 1871, so the year is wrong. -- So fix the month 0, day 0 timestamp to become 1 January instead: timestamp = timestamp:gsub("%-00%-00T", "-01-01T") -- just in case date precision is missing dprec = dprec or 11 -- override more precise dates if required dateformat is year alone: if df
"" or pd
"f" or pd
"-" and "BC" or "" local year, month, day = timestamp:match("[+-](%d*)-(%d*)-(%d*)T") local iso = tonumber(year) -- if year is missing, let it throw an error -- this will adjust the date format to be compatible with cdate -- possible formats are Y, YY, YYY0, YYYY, YYYY-MM, YYYY-MM-DD if dprec
7 then iso = math.floor((iso - 1) / 100) + 1 end if dprec
10 then iso = year .. "-" .. month end if dprec
"Q5727902" then adj = "circa" break end end end -- deal with Julian dates: -- no point in saying that dates before 1582 are Julian - they are by default -- doesn't make sense for dates less precise than year -- we can suppress it by setting |plaindate, e.g. for use in constructing categories. local calendarmodel = "" if tonumber(year) > 1582 and dprec > 8 and not pd and model
[^<]
', ) -- it may also be returned wrapped in a microformat, so remove that fdate = fdate:gsub("<[^>]*>", "") -- there may be leading zeros that we should remove fdate = fdate:gsub("^0*", "") -- if a plain date is required, then remove any links (like BC linked) if pd then fdate = fdate:gsub("%[%[.*|", ""):gsub("]]", "") end -- if 'circa', use the abbreviated form *** internationalise later *** fdate = fdate:gsub('circa ', 'c. ') -- deal with BC/BCE if bcf
"mdy" then fdate = fdate:gsub("(%d+) (%w+) (%d+)", "%2 %1, %3") end -- deal with adjectival form *** internationalise later *** if pd
--------------------------------------------------------------------------------- parseParam takes a (string) parameter, e.g. from the list of frame arguments,-- and makes "false", "no", and "0" into the (boolean) false-- it makes the empty string and nil into the (boolean) value passed as default-- allowing the parameter to be true or false by default.-- It returns a boolean.--------------------------------------------------------------------------------- Dependencies: none-------------------------------------------------------------------------------local parseParam = function(param, default) if type(param)
"false") or (param:sub(1,1)
"0") then return false else return true end else return default endend
--------------------------------------------------------------------------------- The label in a Wikidata item is subject to vulnerabilities-- that an attacker might try to exploit.-- It needs to be 'sanitised' by removing any wikitext before use.-- If it doesn't exist, return the id for the item-- a second (boolean) value is also returned, value is true when the label exists--------------------------------------------------------------------------------- Dependencies: none-------------------------------------------------------------------------------local labelOrId = function(id, lang) if lang
--------------------------------------------------------------------------------- linkedItem takes an entity-id and returns a string, linked if possible.-- This is the handler for "wikibase-item". Preferences:-- 1. Display linked disambiguated sitelink if it exists-- 2. Display linked label if it is a redirect-- 3. TBA: Display an inter-language link for the label if it exists other than in default language-- 4. Display unlinked label if it exists-- 5. Display entity-id for now to indicate a label could be provided-- dtxt is text to be used instead of label, or nil.-- lang is the current language code.-- uselbl is boolean switch to force display of the label instead of the sitelink (default: false)-- linkredir is boolean switch to allow linking to a redirect (default: false)-- formatvalue is boolean switch to allow formatting as italics or quoted (default: false)--------------------------------------------------------------------------------- Dependencies: labelOrId; donotlink[]-------------------------------------------------------------------------------local linkedItem = function(id, args) local lprefix = args.lprefix or "" -- toughen against nil values passed local lpostfix = args.lpostfix or "" local prefix = args.prefix or "" local postfix = args.postfix or "" local dtxt = args.dtxt local lang = args.lang or "en" -- fallback to default if missing local uselbl = args.uselabel or args.uselbl uselbl = parseParam(uselbl, false) local linkredir = args.linkredir linkredir = parseParam(linkredir, false) local disp local sitelink = mw.wikibase.getSitelink(id) local label, islabel if dtxt then label, islabel = dtxt, true else label, islabel = labelOrId(id) end if mw.site.siteName ~= "Wikimedia Commons" then if sitelink then if not dtxt then -- if sitelink and label are the same except for case, no need to process further if sitelink:lower ~= label:lower then -- strip any namespace or dab from the sitelink local pos = sitelink:find(":") or 0 local slink = sitelink if pos > 0 then local pfx = sitelink:sub(1,pos-1) if mw.site.namespaces[pfx] then -- that prefix is a valid namespace, so remove it slink = sitelink:sub(pos+1) end end -- remove stuff after commas or inside parentheses - ie. dabs slink = slink:gsub("%s%(.+%)$", ""):gsub(",.+$", "") -- if uselbl is false, use sitelink instead of label if not uselbl then -- use slink as display, preserving label case - find("^%u") is true for 1st char uppercase if label:find("^%u") then label = slink:gsub("^(%l)", string.upper) else label = slink:gsub("^(%u)", string.lower) end end end end if donotlink[label] then disp = prefix .. label .. postfix else disp = "" .. prefix .. label .. postfix .. "" end elseif islabel then -- no sitelink, label exists, so check if a redirect with that title exists, if linkredir is true -- display plain label by default disp = prefix .. label .. postfix if linkredir then local artitle = mw.title.new(label, 0) -- only nil if label has invalid chars if not donotlink[label] and artitle and artitle.redirectTarget then -- there's a redirect with the same title as the label, so let's link to that disp = "" .. prefix .. label .. postfix .. "" end end -- test if article title exists as redirect on current Wiki else -- no sitelink and no label, so return whatever was returned from labelOrId for now -- add tracking category -- for enwiki, just return the tracking category if mw.wikibase.getGlobalSiteId
--------------------------------------------------------------------------------- sourced takes a table representing a statement that may or may not have references-- it looks for a reference sourced to something not containing the word "wikipedia"-- it returns a boolean = true if it finds a sourced reference.--------------------------------------------------------------------------------- Dependencies: none-------------------------------------------------------------------------------local sourced = function(claim) if claim.references then for kr, vr in pairs(claim.references) do local ref = mw.wikibase.renderSnaks(vr.snaks) if not ref:find("Wiki") then return true end end endend
--------------------------------------------------------------------------------- setRanks takes a flag (parameter passed) that requests the values to return-- "b[est]" returns preferred if available, otherwise normal-- "p[referred]" returns preferred-- "n[ormal]" returns normal-- "d[eprecated]" returns deprecated-- multiple values are allowed, e.g. "preferred normal" (which is the default)-- "best" will override the other flags, and set p and n--------------------------------------------------------------------------------- Dependencies: none-------------------------------------------------------------------------------local setRanks = function(rank) rank = (rank or ""):lower -- if nothing passed, return preferred and normal -- if rank
"b" or w
"n" or w
--------------------------------------------------------------------------------- parseInput processes the Q-id, the blacklist and the whitelist-- if an input parameter is supplied, it returns that and ends the call.-- it returns (1) either the qid or nil indicating whether or not the call should continue-- and (2) a table containing all of the statements for the propertyID and relevant Qid-- if "best" ranks are requested, it returns those instead of all non-deprecated ranks--------------------------------------------------------------------------------- Dependencies: none-------------------------------------------------------------------------------local parseInput = function(frame, input_parm, property_id) -- There may be a local parameter supplied, if it's blank, set it to nil input_parm = mw.text.trim(input_parm or "") if input_parm
-- return nil if Wikidata is not available if not mw.wikibase then return false, input_parm end
local args = frame.args
-- can take a named parameter |qid which is the Wikidata ID for the article. -- if it's not supplied, use the id for the current page local qid = args.qid or "" if qid
-- The blacklist is passed in named parameter |suppressfields local blacklist = args.suppressfields or args.spf or ""
-- The whitelist is passed in named parameter |fetchwikidata local whitelist = args.fetchwikidata or args.fwd or "" if whitelist
-- The name of the field that this function is called from is passed in named parameter |name local fieldname = args.name or ""
if blacklist ~= "" then -- The name is compulsory when blacklist is used, so return nil if it is not supplied if fieldname
-- If we got this far then we're not on the blacklist -- The blacklist overrides any locally supplied parameter as well -- If a non-blank input parameter was supplied return it if input_parm then return false, input_parm end
-- We can filter out non-valid properties if property_id:sub(1,1):upper ~="P" or property_id
-- Otherwise see if this field is on the whitelist: -- needs a bit more logic because find will return its second value = 0 if fieldname is "" -- but nil if fieldname not found on whitelist local _, found = whitelist:find(fieldname) found = ((found or 0) > 0) if whitelist ~= 'ALL' and (whitelist:upper
-- See what's on Wikidata (the call always returns a table, but it may be empty): local props = if args.reqranks.b then props = mw.wikibase.getBestStatements(qid, property_id) else props = mw.wikibase.getAllStatements(qid, property_id) end if props[1] then return qid, props end -- no property on Wikidata return false, nilend
--------------------------------------------------------------------------------- createicon assembles the "Edit at Wikidata" pen icon.-- It returns a wikitext string inside a span class="penicon"-- if entityID is nil or empty, the ID associated with current page is used-- langcode and propertyID may be nil or empty--------------------------------------------------------------------------------- Dependencies: i18n[];-------------------------------------------------------------------------------local createicon = function(langcode, entityID, propertyID) langcode = langcode or "" if not entityID or entityID
--------------------------------------------------------------------------------- assembleoutput takes the sequence table containing the property values-- and formats it according to switches given. It returns a string or nil.-- It uses the entityID (and optionally propertyID) to create a link in the pen icon.--------------------------------------------------------------------------------- Dependencies: parseParam;-------------------------------------------------------------------------------local assembleoutput = function(out, args, entityID, propertyID)
-- sorted is a boolean passed to enable sorting of the values returned -- if nothing or an empty string is passed set it false -- if "false" or "no" or "0" is passed set it false local sorted = parseParam(args.sorted, false)
-- noicon is a boolean passed to suppress the trailing "edit at Wikidata" icon -- for use when the value is processed further by the infobox -- if nothing or an empty string is passed set it false -- if "false" or "no" or "0" is passed set it false local noic = parseParam(args.noicon, false)
-- list is the name of a template that a list of multiple values is passed through -- examples include "hlist" and "ubl" -- setting it to "prose" produces something like "1, 2, 3, and 4" local list = args.list or ""
-- sep is a string that is used to separate multiple returned values -- if nothing or an empty string is passed set it to the default -- any double-quotes " are stripped out, so that spaces may be passed -- e.g. |sep=" - " local sepdefault = i18n["list separator"] local separator = args.sep or "" separator = string.gsub(separator, '"', ) if separator
-- collapse is a number that determines the maximum number of returned values -- before the output is collapsed. -- Zero or not a number result in no collapsing (default becomes 0). local collapse = tonumber(args.collapse) or 0
-- replacetext (rt) is a string that is returned instead of any non-empty Wikidata value -- this is useful for tracking and debugging local replacetext = mw.text.trim(args.rt or args.replacetext or "")
-- if there's anything to return, then return a list -- comma-separated by default, but may be specified by the sep parameter -- optionally specify a hlist or ubl or a prose list, etc. local strout if #out > 0 then if sorted then table.sort(out) end -- if there's something to display and a pen icon is wanted, add it the end of the last value local hasdisplay = false for i, v in ipairs(out) do if v ~= i18n.missinginfocat then hasdisplay = true break end end if not noic and hasdisplay then out[#out] = out[#out] .. createicon(args.langobj.code, entityID, propertyID) end if list
"prose" then strout = mw.text.listToText(out) else strout = mw.getCurrentFrame:expandTemplate end if collapse >0 and #out > collapse then strout = collapsediv .. strout .. "
" end else strout = nil -- no items had valid reference end if replacetext ~= "" and strout then strout = replacetext end return stroutend
--------------------------------------------------------------------------------- rendersnak takes a table (propval) containing the information stored on one property value-- and returns the value as a string and its language if monolingual text.-- It handles data of type:-- wikibase-item-- time-- string, url, commonsMedia, external-id-- quantity-- globe-coordinate-- monolingualtext-- It also requires linked, the link/pre/postfixes, uabbr, and the arguments passed from frame.-- The optional filter parameter allows quantities to be be filtered by unit Qid.--------------------------------------------------------------------------------- Dependencies: parseParam; labelOrId; i18n[]; dateFormat;-- roundto; decimalPrecision; decimalToDMS; linkedItem;-------------------------------------------------------------------------------local rendersnak = function(propval, args, linked, lpre, lpost, pre, post, uabbr, filter) lpre = lpre or "" lpost = lpost or "" pre = pre or "" post = post or "" args.lang = args.lang or findLang.code -- allow values to display a fixed text instead of label local dtxt = args.displaytext or args.dt if dtxt
"somevalue" then -- value is unknown val = i18n["Unknown"] ------------------------------------ elseif snak.snaktype
"wikibase-item" then -- data type is a wikibase item: -- it's wiki-linked value, so output as link if enabled and possible local qnumber = dv.id if linked then val = linkedItem(qnumber, args) else -- no link wanted so check for display-text, otherwise test for lang code local label, islabel if dtxt then label = dtxt else label, islabel = labelOrId(qnumber) local langlabel = mw.wikibase.getLabelByLang(qnumber, args.lang) if langlabel then label = mw.text.nowiki(langlabel) end end val = pre .. label .. post end -- test for link required ------------------------------------ elseif dtype
"commonsMedia" or dtype
"string" or dtype
"" or lpre
"" then -- don't link if no linkpre/postfix or linkprefix is just ":" val = pre .. dv .. post elseif dtype
"quantity" then -- quantities have mainsnak.datavalue.value.amount and mainsnak.datavalue.value.unit -- the unit is of the form http://www.wikidata.org/entity/Q829073 -- -- implement a switch to turn on/off numerical formatting later local fnum = true -- -- a switch to turn on/off conversions - only for en-wiki local conv = parseParam(args.conv or args.convert, false) -- if we have conversions, we won't have formatted numbers or scales if conv then uabbr = true fnum = false args.scale = "0" end -- -- a switch to turn on/off showing units, default is true local showunits = parseParam(args.su or args.showunits, true) -- -- convert amount to a number local amount = tonumber(dv.amount) or i18n["NaN"] -- -- scale factor for millions, billions, etc. local sc = tostring(args.scale or ""):sub(1,1):lower local scale if sc
"a") then if amount < 1e4 then amount = roundto(amount, 4) else amount = math.floor(amount + 0.5) end end if fnum then amount = args.langobj:formatNum(amount) end if posdif ~= negdif then -- non-symmetrical range = " +" .. posdif .. " -" .. negdif elseif posdif ~= 0 then -- symmetrical and non-zero range = " ±" .. posdif else -- otherwise range is zero, so leave it as "" end else -- round scaled numbers to integers or 4 sig fig if (scale > 0 or sc
fblang then usym = us.mainsnak.datavalue.value.text found = true break end if found then break end end -- loop through fallback table end -- loop through values of P5061 if found then usep, unit = " ", usym end end end -- format display: if conv then if range
"$" or unit
"globe-coordinate" then -- 'display' parameter defaults to "inline, title" *** unused for now *** -- local disp = args.display or "" -- if disp
"lat" then val = decimalPrecision(lat, prec) elseif show
"longlat" then val = decimalPrecision(long, prec) .. ", " .. decimalPrecision(lat, prec) else local ns = "N" local ew = "E" if lat < 0 then ns = "S" lat = - lat end if long < 0 then ew = "W" long = - long end if form
if latsec
0 then if latmin
0 then val = latdeg .. "°" .. ns .. " " .. longdeg .. "°" .. ew else val = latdeg .. "°" .. latmin .. "′" .. ns .. " " val = val .. longdeg .. "°".. longmin .. "′" .. ew end else val = latdeg .. "°" .. latmin .. "′" .. latsec .. "″" .. ns .. " " val = val .. longdeg .. "°" .. longmin .. "′" .. longsec .. "″" .. ew end end end ------------------------------------ elseif dtype
--------------------------------------------------------------------------------- propertyvalueandquals takes a property object, the arguments passed from frame,-- and a qualifier propertyID.-- It returns a sequence (table) of values representing the values of that property-- and qualifiers that match the qualifierID if supplied.--------------------------------------------------------------------------------- Dependencies: parseParam; sourced; labelOrId; i18n.latestdatequalifier;-- roundto; decimalPrecision; decimalToDMS; assembleoutput;-------------------------------------------------------------------------------local function propertyvalueandquals(objproperty, args, qualID) -- needs this style of declaration because it's re-entrant
-- onlysourced is a boolean passed to return only values sourced to other than Wikipedia -- if nothing or an empty string is passed set it true local onlysrc = parseParam(args.onlysourced or args.osd, true)
-- linked is a a boolean that enables the link to a local page via sitelink -- if nothing or an empty string is passed set it true local linked = parseParam(args.linked, true)
-- prefix is a string that may be nil, empty (""), or a string of characters -- this is prefixed to each value -- useful when when multiple values are returned -- any double-quotes " are stripped out, so that spaces may be passed local prefix = (args.prefix or ""):gsub('"', )
-- postfix is a string that may be nil, empty (""), or a string of characters -- this is postfixed to each value -- useful when when multiple values are returned -- any double-quotes " are stripped out, so that spaces may be passed local postfix = (args.postfix or ""):gsub('"', )
-- linkprefix is a string that may be nil, empty (""), or a string of characters -- this creates a link and is then prefixed to each value -- useful when when multiple values are returned and indirect links are needed -- any double-quotes " are stripped out, so that spaces may be passed local lprefix = (args.linkprefix or args.lp or ""):gsub('"', )
-- linkpostfix is a string that may be nil, empty (""), or a string of characters -- this is postfixed to each value when linking is enabled with lprefix -- useful when when multiple values are returned -- any double-quotes " are stripped out, so that spaces may be passed local lpostfix = (args.linkpostfix or ""):gsub('"', )
-- wdlinks is a boolean passed to enable links to Wikidata when no article exists -- if nothing or an empty string is passed set it false local wdl = parseParam(args.wdlinks or args.wdl, false)
-- unitabbr is a boolean passed to enable unit abbreviations for common units -- if nothing or an empty string is passed set it false local uabbr = parseParam(args.unitabbr or args.uabbr, false)
-- qualsonly is a boolean passed to return just the qualifiers -- if nothing or an empty string is passed set it false local qualsonly = parseParam(args.qualsonly or args.qo, false)
-- maxvals is a string that may be nil, empty (""), or a number -- this determines how many items may be returned when multiple values are available -- setting it = 1 is useful where the returned string is used within another call, e.g. image local maxvals = tonumber(args.maxvals) or 0
-- pd (plain date) is a string: yes/true/1 | no/false/0 | adj -- to disable/enable "sourcing cirumstances" or use adjectival form for the plain date local pd = args.plaindate or args.pd or "no" args.pd = pd
-- allow qualifiers to have a different date format; default to year args.qdf = args.qdf or args.qualifierdateformat or args.df or "y"
local lang = args.lang or findlang.code
-- qualID is a string list of wanted qualifiers or "ALL" qualID = qualID or "" -- capitalise list of wanted qualifiers and substitute "DATES" qualID = qualID:upper:gsub("DATES", "P580, P582") local allflag = (qualID
-- all proper values of a Wikidata property will be the same type as the first -- qualifiers don't have a mainsnak, properties do local datatype = objproperty[1].datatype or objproperty[1].mainsnak.datatype
-- out[] holds the a list of returned values for this property -- mlt[] holds the language code if the datatype is monolingual text local out = local mlt =
for k, v in ipairs(objproperty) do local hasvalue = true if (onlysrc and not sourced(v)) then -- no value: it isn't sourced when onlysourced=true hasvalue = false else local val, lcode = rendersnak(v, args, linked, lprefix, lpostfix, prefix, postfix, uabbr) if not val then hasvalue = false -- rank doesn't match elseif qualsonly and qualID then -- suppress value returned: only qualifiers are requested else out[#out+1], mlt[#out+1] = val, lcode end end
-- See if qualifiers are to be returned: local snak = v.mainsnak or v if hasvalue and v.qualifiers and qualID ~= "" and snak.snaktype~="novalue" then -- collect all wanted qualifier values returned in qlist, indexed by propertyID local qlist = local timestart, timeend = "", "" -- loop through qualifiers for k1, v1 in pairs(v.qualifiers) do if allflag or qwanted[k1] then if k1
"P1319" then local ts = v1[1].datavalue.value.time local dp = v1[1].datavalue.value.precision qlist[k1] = dateFormat(ts, dp, args.qdf, args.bc, pd, "", lang, "after") elseif k1
"P582" then timeend = propertyvalueandquals(v1, qargs)[1] or "" -- treat only one end time as valid else local q = assembleoutput(propertyvalueandquals(v1, qargs), qargs) -- we already deal with circa via 'sourcing circumstances' if the datatype was time -- circa may be either linked or unlinked *** internationalise later *** if datatype ~= "time" or q ~= "circa" and not (type(q)
if maxvals > 0 and #out >= maxvals then break end end -- of for each value loop
-- we need to pick one value to return if the datatype was "monolingualtext" -- if there's only one value, use that -- otherwise look through the fallback languages for a match if datatype
lang2) and not found then bestval = out[idx2] found = true break end end -- loop through values of property end -- loop through fallback languages if found then -- replace output table with a table containing the best value out = else -- more than one value and none of them on the list of fallback languages -- sod it, just give them the first one out = end end return outend
---------------------------------------------------------------------------------------------------------------------------------------------------------------- Public functions---------------------------------------------------------------------------------------------------------------------------------------------------------------- _getValue makes the functionality of getValue available to other modules--------------------------------------------------------------------------------- Dependencies: setRanks; parseInput; propertyvalueandquals; assembleoutput; parseParam; sourced;-- labelOrId; i18n.latestdatequalifier; roundto; decimalPrecision; decimalToDMS;-------------------------------------------------------------------------------p._getValue = function(args) -- parameter sets for commonly used groups of parameters local paraset = tonumber(args.ps or args.parameterset or 0) if paraset
2 then -- equivalent to raw args.rank = "best" args.fetchwikidata = "ALL" args.onlysourced = "no" args.noicon = "true" args.linked = "no" args.pd = "true" elseif paraset
-- implement eid parameter local eid = args.eid if eid
local propertyID = mw.text.trim(args[1] or "")
args.reqranks = setRanks(args.rank)
-- replacetext (rt) is a string that is returned instead of any non-empty Wikidata value -- this is useful for tracking and debugging, so we set fetchwikidata=ALL to fill the whitelist local replacetext = mw.text.trim(args.rt or args.replacetext or "") if replacetext ~= "" then args.fetchwikidata = "ALL" end
local f = f.args = args local entityid, props = parseInput(f, f.args[2], propertyID)
if not entityid then return props -- either the input parameter or nothing end
-- qual is a string containing the property ID of the qualifier(s) to be returned -- if qual
"DATES" then qualifiers P580 (start time) and P582 (end time) returned -- if nothing or an empty string is passed set it nil -> no qualifiers returned local qualID = mw.text.trim(args.qual or ""):upper if qualID
-- set a language object and code in the args table args.langobj = findLang(args.lang) args.lang = args.langobj.code
-- table 'out' stores the return value(s): local out = propertyvalueandquals(props, args, qualID)
-- format the table of values and return it as a string: return assembleoutput(out, args, entityid, propertyID)end
--------------------------------------------------------------------------------- getValue is used to get the value(s) of a property-- The property ID is passed as the first unnamed parameter and is required.-- A locally supplied parameter may optionaly be supplied as the second unnamed parameter.-- The function will now also return qualifiers if parameter qual is supplied--------------------------------------------------------------------------------- Dependencies: _getValue; setRanks; parseInput; propertyvalueandquals; assembleoutput; parseParam; sourced;-- labelOrId; i18n.latestdatequalifier; roundto; decimalPrecision; decimalToDMS;-------------------------------------------------------------------------------p.getValue = function(frame) local args= frame.args if not args[1] then args = frame:getParent.args if not args[1] then return i18n.errors["No property supplied"] end end
return p._getValue(args)end
--------------------------------------------------------------------------------- getPropOfProp takes two propertyIDs: prop1 and prop2 (as well as the usual parameters)-- If the value(s) of prop1 are of type "wikibase-item" then it returns the value(s) of prop2-- of each of those wikibase-items.-- The usual whitelisting, blacklisting, onlysourced, etc. are implemented--------------------------------------------------------------------------------- Dependencies: parseParam; setRanks; parseInput; sourced; propertyvalueandquals assembleoutput;-------------------------------------------------------------------------------p._getPropOfProp = function(args) -- parameter sets for commonly used groups of parameters local paraset = tonumber(args.ps or args.parameterset or 0) if paraset
2 then -- equivalent to raw args.rank = "best" args.fetchwikidata = "ALL" args.onlysourced = "no" args.noicon = "true" args.linked = "no" args.pd = "true" elseif paraset
args.reqranks = setRanks(args.rank) args.langobj = findLang(args.lang) args.lang = args.langobj.code local pid1 = args.prop1 or args.pid1 or "" local pid2 = args.prop2 or args.pid2 or "" local localval = mw.text.trim(args[1] or "") if pid1
"" then return nil end
local f = f.args = args local qid1, statements1 = parseInput(f, localval, pid1) if not qid1 then return localval end
local onlysrc = parseParam(args.onlysourced or args.osd, true) local maxvals = tonumber(args.maxvals) or 0 local qualID = mw.text.trim(args.qual or ""):upper if qualID
"wikibase-item" and snak.snaktype
p.getPropOfProp = function(frame) local args= frame.args if not args.prop1 and not args.pid1 then args = frame:getParent.args if not args.prop1 and not args.pid1 then return i18n.errors["No property supplied"] end end
return p._getPropOfProp(args)end
return p
--------------------------------------------------------------------------------- List of exported functions---------------------------------------------------------------------------------_getValuegetValue_getPropOfPropgetPropOfProp---------------------------------------------------------------------------------