உள்ளடக்கத்துக்குச் செல்

Module:Wikidata

கட்டற்ற கலைக்களஞ்சியமான விக்கிப்பீடியாவில் இருந்து.
Mdmahir (பேச்சு | பங்களிப்புகள்) பயனரால் செய்யப்பட்ட 15:08, 16 ஆகத்து 2015 அன்றிருந்தவாரான திருத்தம் (AntanO (Talk) பயனரால் செய்யப்பட்ட திருத்தம் 1897878 இல்லாது செய்யப்பட்டது)

Documentation for this module may be created at Module:Wikidata/doc

--[[
* Modulo per implementare le funzionalità dei template:
* {{Wikidata}}, {{WikidataQ}}, {{WikidataIdx}}, {{WikidataN}} e {{WikidataLink}}.
* Permette di accedere a Wikidata in modo più avanzato rispetto a {{#property}}.

* Il modulo è stato importato inizialmente da:
* http://test2.wikipedia.org/w/index.php?title=Module:Wikidata&oldid=52322
]]

require('Module:No globals')

local getArgs = require('Module:Arguments').getArgs

-- Categoria per le pagine con errori
local errorCategory = '[[Categoria:Voci con errori del modulo Wikidata]]'

-- Messaggi di errore
local i18n = {
	["errors"] = {
		["entityid-param-not-provided"] = "Parametro ''entityid'' non fornito",
		["property-param-not-provided"] = "Parametro ''property'' non fornito",
		["qualifier-param-not-provided"] = "Parametro ''qualifier'' non fornito",
		["value-param-not-provided"] = "Parametro ''valore'' da ricercare non fornito",
		["unknown-snak-type"] = "Tipo di snak sconosciuto",
		["unknown-datavalue-type"] = "Tipo di dato sconosciuto",
	    ["property-not-found"] = "Property not found.",
        ["entity-not-found"] = "Wikidata entity not found.",
        ["unknown-claim-type"] = "Unknown claim type.",
        ["unknown-entity-type"] = "Unknown entity type.",
        ["qualifier-not-found"] = "Qualifier not found.",
        ["site-not-found"] = "Wikimedia project not found.",
    },
	["somevalue"] = "''valore sconosciuto''",
	["novalue"] = "''nessun valore''",
["datetime"] =
	{
		-- $1 is a placeholder for the actual number
		[0] = "$1 billion years",	-- precision: billion years
		[1] = "$100 million years",	-- precision: hundred million years
		[2] = "$10 million years",	-- precision: ten million years
		[3] = "$1 million years",	-- precision: million years
		[4] = "$100,000 years",		-- precision: hundred thousand years
		[5] = "$10,000 years",		-- precision: ten thousand years
		[6] = "$1  millenium",	 	-- precision: millennium
		[7] = "$1 century",			-- precision: century
		[8] = "$1s",				-- precision: decade
		-- the following use the format of #time parser function
		[9]  = "Y",					-- precision: year, 
		[10] = "F Y",				-- precision: month
		[11] = "F j, Y",			-- precision: day
		[12] = "F j, Y ga",			-- precision: hour
		[13] = "F j, Y g:ia",		-- precision: minute
		[14] = "F j, Y g:i:sa",		-- precision: second
		["beforenow"] = "$1 BCE",	-- how to format negative numbers for precisions 0 to 5
		["afternow"] = "$1 CE",		-- how to format positive numbers for precisions 0 to 5
		["bc"] = '$1 "BCE"',		-- how print negative years
		["ad"] = "$1"				-- how print positive years
	},
	["monolingualtext"] = '<span lang="%language">%text</span>',
	["warnDump"] = "[[Category:Called function 'Dump' from module Wikidata]]"
}

-------------------------------------------------------------------------------
--                             Formatters
-------------------------------------------------------------------------------

local function errhandler(msg)
	local cat = mw.title.getCurrentTitle().namespace == 0 and errorCategory or ''
	return string.format('<span class="error">%s</span>%s', msg, cat)
end

local function formatExtLink(url)
	local protocols = { ftp = true, http = true, https = true }

	local success, uri = pcall(function() return mw.uri.new(url) end)
	if success and uri.protocol and protocols[uri.protocol] then
		local dest = tostring(uri)
		return string.format('[%s %s]', dest, dest:gsub(uri.protocol .. '://', ''))	
	else
		return url
	end
end

local function formatEntityId(entityId)
	local label = mw.wikibase.label(entityId)
	local link = mw.wikibase.sitelink(entityId)
	if link then
		if label then
			return '[[' .. link .. '|' .. label .. ']]'
		else
			return '[[' .. link .. ']]'
		end
	else
		return label or ''
	end
end

local function formatTime(value, args)
	local year, month, day
	local ret = ''
 
	year, month, day = value.time:match('(%d+)%-(%d%d)%-(%d%d).+')
	if value.precision == 9 then
		ret = tonumber(year)
	elseif value.precision == 10 then
		ret = mw.getLanguage('it'):formatDate('F Y', tonumber(year) .. '-' .. month)
	elseif value.precision == 11 then
		ret = mw.getLanguage('it'):formatDate('j F Y', tonumber(year) .. '-' .. month .. '-' .. day)
		ret = ret:gsub('^1%s', '1º ')
	end
	if value.precision >= 9 and value.precision <= 11 then
		ret = ret .. (value.time:sub(1, 1) == '-' and ' a.C.' or '')
	end

	return ret
end

local function formatGlobecoordinate(value, args)
	local ret
	if args.formatting == 'latitude' then
		ret = value.latitude
	elseif args.formatting == 'longitude' then
		ret = value.longitude
	else
		ret = value.latitude .. ', ' .. value.longitude
	end
	return ret
end

local function formatFromPattern(str, args)
	local pattern = args.pattern
	pattern = mw.ustring.gsub(pattern, '\\{', '{')
	pattern = mw.ustring.gsub(pattern, '\\}', '}')
	return mw.getCurrentFrame():preprocess(mw.message.newRawMessage(pattern, str):plain())
end

local function getEntityIdFromValue(value)
	local prefix = ''
	if value['entity-type'] == 'item' then
		prefix = 'Q'
	elseif value['entity-type'] == 'property' then
		prefix = 'P'
	else
		error(i18n.errors['unknown-entity-type'])
	end
	return prefix .. value['numeric-id']
end

local function formatDatavalue(datavalue, args)
	local ret

	--Default formatters
	if datavalue.type == 'wikibase-entityid' then
		if args.formatting == 'raw' then
			ret = getEntityIdFromValue(datavalue.value)
		else
			ret = formatEntityId(getEntityIdFromValue(datavalue.value))
		end
	elseif datavalue.type == 'string' then
		ret = datavalue.value
		if args.formatting == 'extlink' then
			ret = formatExtLink(ret)
		end
	elseif datavalue.type == 'monolingualtext' then
		ret = datavalue.value.text
	elseif datavalue.type == 'time' then
		if args.formatting == 'raw' then
			ret = datavalue.value.time
		else
			ret = formatTime(datavalue.value, args)
		end
	elseif datavalue.type == 'globecoordinate' then
		ret = formatGlobecoordinate(datavalue.value, args)
	elseif datavalue.type == 'quantity' then
		ret = tonumber(datavalue.value.amount)
	else
		error(i18n.errors['unknown-datavalue-type'])
	end

	return ret
end

local function formatSnak(snak, args)
	if snak.snaktype == 'somevalue' then
		return i18n['somevalue']
	elseif snak.snaktype == 'novalue' then
		return i18n['novalue']
	elseif snak.snaktype == 'value' then
		return formatDatavalue(snak.datavalue, args)
	else
		error(i18n.errors['unknown-snak-type'])
	end
end

local function formatStatement(statement, args)
	if not statement.type or statement.type ~= 'statement' then
		error(i18n.errors['unknown-claim-type'])
	end
 
	return formatSnak(statement.mainsnak, args)
end

local function formatStatements(claims, args, rawTable)
	local formattedStatements = {}
	local formattedStatement

	for i, claim in pairs(claims) do
		formattedStatement = formatStatement(claim, args)
		-- eventuale pattern
		if args.pattern then
			formattedStatement = formatFromPattern(formattedStatement, args)
		end
		table.insert(formattedStatements, formattedStatement)
	end
	if rawTable then
		return formattedStatements
	end

	if args.list or args.orderedlist then
		table.insert(formattedStatements, 1, args.list and '<ul><li>' or '<ol><li>');
		table.insert(formattedStatements, args.list and '</li></ul>' or '</li></ol>'); 
		args.separator = '</li><li>'
		args.conjunction = args.separator
	end

	return mw.text.listToText(formattedStatements, args.separator, args.conjunction)
end

-------------------------------------------------------------------------------
--                      Lettura e selezione statement
-------------------------------------------------------------------------------

-- Ritorna true se lo statement contiene il qualifier richiesto con un dato valore
local function hasQualifierValue(statement, args)
	local ret = false
	for i, qualifier in pairs(statement.qualifiers[args.qualifier]) do
		local isItem = qualifier.datavalue.snaktype == 'value' and
					   qualifier.datavalue.type == 'wikibase-entityid'
		-- per le proprietà di tipo item il confronto è eseguito sull'id
		if formatSnak(qualifier, isItem and { formatting = 'raw' } or {} ) == args.qualifiervalue then
			ret = true
			break
		end
	end
	return ret
end

-- Ritorna i claim con il rank richiesto
local function filterRankValue(claims, rank)
	local ret = {}
	for i, claim in pairs(claims) do
		if claim.rank == rank then
			table.insert(ret, claim)
		end
	end
	return ret
end

-- Ritorna una table contenente gli statement per la property richiesta,
-- oppure nil se l'entity o la proprietà non esistono.
-- Gli statement ritornati sono eventualmente filtrati in base ai parametri:
-- "rank", "qualifier", "qualifiertype" e "n"
local function getClaims(property, args)
	local entity, claims, filteredClaims
	
	-- get entity
	entity = mw.wikibase.getEntityObject(args.from)
	if not entity then
		return nil
	end

	if property and entity.claims and entity.claims[property] and
	   #entity.claims[property] > 0 then
	   claims = entity.claims[property]
	else
		return nil
	end

	-- statements filtrati per rank
	if args.rank then
		if args.rank == 'best' then
			filteredClaims = filterRankValue(claims, 'preferred')
			if #filteredClaims == 0 then
				filteredClaims = filterRankValue(claims, 'normal')
			end
		else
			filteredClaims = filterRankValue(claims, args.rank)
		end
		claims = filteredClaims
	end

	-- statements filtrati per qualifier
	if args.qualifier then
		filteredClaims = {}
		for i, claim in pairs(claims) do
			if claim.qualifiers and claim.qualifiers[args.qualifier] then
				if args.qualifiervalue then
					if hasQualifierValue(claim, args) then
						table.insert(filteredClaims, claim)
					end
				else
					table.insert(filteredClaims, claim)
				end
			end
		end
		claims = filteredClaims
	end

	-- con args.qualifiertype=latest ritorna solo il più recente
	if args.qualifier and args.qualifiertype == 'latest' then
		local latest, latestTime
		for i, claim in pairs(claims) do
			if claim.qualifiers and claim.qualifiers[args.qualifier] then
				for j, qualifier in pairs(claim.qualifiers[args.qualifier]) do
					if qualifier.datavalue.type == 'time' then
						if not latestTime or qualifier.datavalue.value.time > latestTime then
							latest = claim
							latestTime = qualifier.datavalue.value.time
						end
					end
				end
			end
		end
		claims = latest and {latest} or {}
	end

	-- con args.n ritorna solo l'n-esimo elemento
	if args.n then
		local n = tonumber(args.n)
		claims = (n and n <= #claims) and {claims[n]} or {}
	end

	return claims
end

-------------------------------------------------------------------------------
--                               API
-------------------------------------------------------------------------------

local p = {}

-- Ritorna il valore di una proprietà di Wikidata oppure nil se l'entity o
-- la proprietà non esistono, o se per parametri di selezione gli statement sono zero.
function p._getProperty(args, rawTable)
	local property, value, claims

	-- parametri posizionali
	property = args[1] and string.upper(args[1]) or nil
	if not property then
		error(i18n.errors['property-param-not-provided'], 2)
	end
	value = args[2]
	-- fix uppercase
	args.qualifier = args.qualifier and string.upper(args.qualifier) or nil
	
	-- if parameter value is already set, use it
	if value then
		if args.formatting == 'extlink' then
			value = formatExtLink(value)
		end
		return args.pattern and formatFromPattern(value, args) or value 
	end
	
	-- default rank
	args.rank = args.rank or 'best'

	-- get claims
	claims = getClaims(property, args)

	return (claims and #claims > 0) and formatStatements(claims, args, rawTable) or nil
end

-- Ritorna il valore di un qualifier di una proprietà di Wikidata,
-- o nil se l'entity o la proprietà non esistono, o se per parametri di selezione non ci sono risultati.
function p._getQualifier(args)
	local property, qualifier, value, claims, formattedQualifier, formattedQualifiers
	
	-- parametri posizionali
	property = args[1] and string.upper(args[1]) or nil
	if not property then
		error(i18n.errors['property-param-not-provided'], 2)
	end
	qualifier = args[2] and string.upper(args[2]) or nil
	if not qualifier then
		error(i18n.errors['qualifier-param-not-provided'], 2)
	end
	value = args[3]
	
	-- if parameter value is already set, use it
	if value then
		return args.pattern and formatFromPattern(value, args) or value 
	end

	-- default rank
	args.rank = args.rank or 'best'

	-- get claims
	claims = getClaims(property, args)
	if not claims or #claims == 0 then
		return nil
	end

	-- get qualifiers and format them
	formattedQualifiers = {}
	for i, claim in pairs(claims) do
		if claim.qualifiers and claim.qualifiers[qualifier] then
			for j, q in pairs(claim.qualifiers[qualifier]) do
				formattedQualifier = formatSnak(q, args)
				if args.pattern then
					formattedQualifier = formatFromPattern(formattedQualifier, args)
				end 
				table.insert(formattedQualifiers, formattedQualifier)
			end
		end
	end

	return #formattedQualifiers > 0 and
		   mw.text.listToText(formattedQualifiers, args.separator, args.conjunction) or nil
end

-- Ritorna l'indice dello statement con il valore richiesto, o -1 se non trovato.
function p._indexOf(args)
	local ret, property, value, claims

	-- parametri posizionali
	property = args[1] and string.upper(args[1]) or nil
	if not property then
		error(i18n.errors['property-param-not-provided'], 2)
	end
	value = args[2]
	if not value then
		error(i18n.errors['value-param-not-provided'], 2)
	end

	-- default rank
	args.rank = args.rank or 'best'

	-- get claims
	claims = getClaims(property, args)
	if not claims or #claims == 0 then
		return -1
	end

	args.formatting = 'raw'
	for i, claim in pairs(claims) do
		if formatStatement(claim, args) == value then
			ret = i
			break
		end
	end

	return ret or -1
end

-- Ritorna il numero di statement di una proprietà di Wikidata.
function p._N(args) 
	local entity, property, count

	-- parametri posizionali
	property = args[1] and string.upper(args[1]) or nil
	if not property then
		error(i18n.errors['property-param-not-provided'], 2)
	end

	entity = mw.wikibase.getEntityObject(args.from)
	if entity and entity.claims and entity.claims[property] then
		count = #entity.claims[property]
	end

	return count or 0
end

-- Ritorna true se la proprietà P31 (instance of) ha come valore almeno uno tra gli entityId specificati
function p._instanceOf(args)
	local statements = p._getProperty( { 'P31', from = args.from, formatting = 'raw' }, true)
	if statements then
		for _, statement in ipairs(statements) do
			for _, entityId in ipairs(args) do
				if statement == entityId then
					return true
				end
			end
		end
	end

	return false
end

-- Ritorna il titolo della pagina collegata a un dato item Wikidata.
function p._getLink(args) 
	-- parametri posizionali
	local entityId = args[1] and string.upper(args[1]) or nil
	if not entityId then
		error(i18n.errors['entityid-param-not-provided'], 2)
	end
	
	return formatEntityId(entityId)
end

-- Entry-point per {{Wikidata}}
function p.getProperty(frame)
	return select(2, xpcall(function()
		return p._getProperty(getArgs(frame, {parentOnly = true}))
	end, errhandler))
end

-- Entry-point per {{WikidataQ}}
function p.getQualifier(frame)
	return select(2, xpcall(function()
		return p._getQualifier(getArgs(frame, {parentOnly = true}))
	end, errhandler))
end

-- Entry-point per {{WikidataIdx}}
function p.indexOf(frame)
	return select(2, xpcall(function()
		return p._indexOf(getArgs(frame, {parentOnly = true}))
	end, errhandler))
end

-- Entry-point per {{WikidataN}}
function p.N(frame)
	return select(2, xpcall(function()
		return p._N(getArgs(frame, {parentOnly = true}))
	end, errhandler))
end

-- Entry-point per {{WikidataLink}}
function p.getLink(frame)
	return select(2, xpcall(function()
		return p._getLink(getArgs(frame, {parentOnly = true}))
	end, errhandler))
end

-- Entry-point per {{WikidataIstanza}}
function p.instanceOf(frame)
	return select(2, xpcall(function()
		return p._instanceOf(getArgs(frame, {parentOnly = true})) and 1 or 0
	end, errhandler))
end

-- returns the page id (Q...) of the current page or nothing of the page is not connected to Wikidata
function p.pageId(frame)
	local entity = mw.wikibase.getEntityObject()
	if not entity then return nil else return entity.id end
end

function p.Dump(frame)
	local data = mw.wikibase.getEntityObject()
	if not data then
		return i18n.warnDump
	end

	local f = frame.args[1] and frame or frame:getParent()

	local i = 1
	while true do
		local index = f.args[i]
		if not index then
			return "<pre>"..mw.dumpObject(data).."</pre>".. i18n.warnDump
		end

		data = data[index] or data[tonumber(index)]
		if not data then
			return i18n.warnDump
		end

		i = i + 1
	end
end

-- This is used to get a value, or a comma separated list of them if multiple values exist
p.getValue = function(frame)
	local propertyID = mw.text.trim(frame.args[1] or "")
	local input_parm = mw.text.trim(frame.args[2] or "")
	if input_parm == "FETCH_WIKIDATA" then
		local entity = mw.wikibase.getEntityObject()
		local claims
		if entity and entity.claims then
			claims = entity.claims[propertyID]
		end
		if claims then
			-- if wiki-linked value output as link if possible
			if (claims[1] and claims[1].mainsnak.snaktype == "value" and claims[1].mainsnak.datavalue.type == "wikibase-entityid") then
				local out = {}
				for k, v in pairs(claims) do
					local sitelink = mw.wikibase.sitelink("Q" .. v.mainsnak.datavalue.value["numeric-id"])
					local label = mw.wikibase.label("Q" .. v.mainsnak.datavalue.value["numeric-id"])
					if label == nil then label = "Q" .. v.mainsnak.datavalue.value["numeric-id"] end
							
					if sitelink then
						out[#out + 1] = "[[" .. sitelink .. "|" .. label .. "]]"
					else
						out[#out + 1] = "[[:d:Q" .. v.mainsnak.datavalue.value["numeric-id"] .. "|" .. label .. "]]<abbr title='Article is not yet available in this wiki'>[*]</abbr>"
					end
				end
				return table.concat(out, ", ")
			else
				-- just return best vakues
				return entity:formatPropertyValues(propertyID).value
			end
		else
			return ""
		end
	else
		return input_parm
	end
end

return p
"https://ta.wikipedia.org/w/index.php?title=Module:Wikidata&oldid=1897888" இலிருந்து மீள்விக்கப்பட்டது