Module:PropertyChain/sandbox
Lua
Documentation for this module may be created at Module:PropertyChain/sandbox/doc
Code
--[[
__ __ _ _ ____ _ ____ _ _
| \/ | ___ __| |_ _| | ___ _| _ \ _ __ ___ _ __ ___ _ __| |_ _ _ / ___| |__ __ _(_)_ __
| |\/| |/ _ \ / _` | | | | |/ _ (_) |_) | '__/ _ \| '_ \ / _ \ '__| __| | | | | | '_ \ / _` | | '_ \
| | | | (_) | (_| | |_| | | __/_| __/| | | (_) | |_) | __/ | | |_| |_| | |___| | | | (_| | | | | |
|_| |_|\___/ \__,_|\__,_|_|\___(_)_| |_| \___/| .__/ \___|_| \__|\__, |\____|_| |_|\__,_|_|_| |_|
|_| |___/
Maintainers:
* Jarekt
]]
local getLabel = require('Module:Wikidata label')._getLabel -- get localized translations of date formats
local core = require('Module:Core') -- get localized translations of date formats
-------------------------------------------------------------------------------
local function getProperty(entity, prop)
return (core.parseStatements(entity:getBestStatements( prop ), nil) or {nil})[1]
end
-------------------------------------------------------------------------------
local function getItemProperty(item, prop)
return (core.parseStatements(mw.wikibase.getBestStatements( item, prop ), nil) or {nil})[1]
end
-------------------------------------------------------------------------------
local function getItemAllPropertyValues(item, prop)
return (core.parseStatements(mw.wikibase.getBestStatements( item, prop ), nil) or nil)
end
-- ==================================================
-- === External functions ===========================
-- ==================================================
local p = {}
--[[ ========================================================================================
Follow and recored a chain of properties:
* item - starting item id
* prop - property to follow
* endItem - (optional) item id used as a stopping criteria when encountered
* link - (optional) link type: wikidata, wikipedia (default) , commons, commonscat etc. same as in "Module:Wikidata label"
* separator - (optional with '→' default) symbol or string used to separate items in the list
* lang - (optional defaulting to user's language) language of the labels
]]
function p._PropertyChain(item, prop, endItem, link, separator, lang)
if not (lang and mw.language.isSupportedLanguage(lang)) then
lang = mw.getCurrentFrame():callParserFunction( "int", "lang" ) -- get user's chosen language
end
local chain, items = {}, {}
for iter = 1,50 do -- at maximum only 50 iterations are allowed
local entity = mw.wikibase.getEntity(item)
table.insert(chain, getLabel(entity, lang, link) )
items[entity.id] = true -- early detection of loops
item = getProperty(entity, prop)
if not item or items[item] or item==endItem then
-- stopping criteria: item is missing property "prop", or a loop is detected or end-item ID was found
break
end
end
if item and item==endItem then
table.insert(chain, getLabel(item, lang, link) )
end
return table.concat(chain, separator or '→')
end
--[[ ========================================================================================
Follow a chain of properties until endProp1 or endProp2 encountered and return that value :
* item - starting item id
* prop - property to follow
* endProp1, endProp2 - properties whose presence is the stopping criteria
* endProp2 is optional
]]
function p._PropertyChain2(item, prop, endProp1, endProp2)
local items = {}
for iter = 1,50 do -- at maximum only 50 iterations are allowed
local pp = getItemProperty(item, prop)
local ep = getItemProperty(item, endProp1)
if ep then
return ep
else if endProp2 then
ep = getItemProperty(item, endProp2)
if ep then
return ep
end
end
end
if not pp or items[pp] then
return nil -- loop detected or prop missing
else
items[pp] = true -- early detection of loops
item = pp
end
end
end
--[[ ========================================================================================
Follow multiple chains of properties until either endProp1 or endProp2 is encountered and return a table of all values found :
* item - starting item id
* parentProp - property to follow up the tree
* endProp1, endProp2 - properties whose presence is the stopping criteria
* endProp2 is optional
* alreadyTraversed - a table of already visited items
* maxDepth - maximum depth to avoud infinite loop
]]
function p._recursiveItemProperties (item, parentProp, endProp1, endProp2, alreadyTraversed, maxDepth)
if maxDepth == 0 then
return {}
else
-- endProp found, return all values
local ep = getItemAllPropertyValues(item, endProp1)
if ep then
return ep
else if endProp2 then
ep = getItemAllPropertyValues(item, endProp2)
if ep then
return ep
end
end
end
if alreadyTraversed[item] then
-- loop detected
return {}
else
alreadyTraversed[item] = true -- early detection of loops, before recursive call
end
-- traverse parentProp(s) tree
local pp = getItemAllPropertyValues(item, parentProp)
local res = {}
for _,ppv in ipairs(pp) do
for _,v in ipairs(p._recursiveItemProperties(ppv, parentProp, endProp1, endProp2, alreadyTraversed, maxDepth-1)) do
table.insert(res, v)
end
end
-- make res unique
local hash = {}
local resUnique = {}
for _,v in ipairs(res) do
if (not hash[v]) then
resUnique[#resUnique+1] = v
hash[v] = true
end
end
return resUnique
end
end
--[[ ========================================================================================
get all ISO 3166-2 or ISO 3166 1 codes for an item :
* item - starting item id
* separator - separator for concat multiple values
]]
function p._AllISO3166Codes(item, separator)
local alreadyTraversed = {} -- loop detection
local maxDepth = 10 -- at maximum only maxDepth iterations are allowed
local items = p._recursiveItemProperties(item, 'P131', 'P300', 'P297', alreadyTraversed, maxDepth)
return table.concat(items, separator or ', ')
end
function p.PropertyChain(frame)
local args = core.getArgs(frame)
-- find stopping item ID
local endItem = args.endqid
if not endItem and args.endpid then
endItem = getProperty(mw.wikibase.getEntity(args.qid), args.endpid, 'one')
end
return p._PropertyChain( args.qid, args.pid, endItem, args.link, args.separator, args.lang )
end
function p.PropertyChain2(frame)
local args = core.getArgs(frame)
return p._PropertyChain2( args.qid, args.pid, args.endpid1, args.endpid2 )
end
function p.AllISO3166Codes(frame)
local args = core.getArgs(frame)
return p._AllISO3166Codes( args.qid, args.sep )
end
--[[ ========================================================================================
get a ISO 3166-2 or ISO 3166 1 code for an item :
* item - starting item id
wrapper for specific _PropertyChain2 call
]]
function p.AISO3166Code(frame)
local args = core.getArgs(frame)
return p._PropertyChain2( args.qid, 'P131', 'P300', 'P297' )
end
return p