Modulo:Wikidata

Da Wikiquote, aforismi e citazioni in libertà.
Jump to navigation Jump to search

Il modulo Lua Wikidata serve per leggere il valore delle proprietà di Wikidata relative alla pagina corrente, cioè la pagina in cui è utilizzato il modulo. Sarà in futuro possibile leggere le proprietà anche di pagine diverse da quella corrente. Il modulo fornisce un utilizzo più avanzato, a volte senza alternativa, rispetto a quello che si può ottenere con la magic word: {{#property:proprietà}}.

Utilizzo[modifica]

Il modulo ha quattro funzioni:

  • formatStatements: restituisce il valore di una proprietà di Wikidata. Nel caso una proprietà abbia più di una dichiarazione (statement) può restituire tutti i valori, separandoli con una virgola e inserendo la congiunzione "e" prima dell'ultimo valore, oppure filtrarli se si specifica un rank (classificazione), un qualifier (qualificatore) o un indice. Permette di formattare il risultato attraverso delle opzioni (da qui il nome formatStatements). Se la pagina non ha un elemento su Wikidata, oppure non ha la proprietà specificata, oppure il valore della proprietà è a sua volta un elemento che non ha un'etichetta in italiano, non restituisce nulla. Se possibile (e se non diversamente specificato), i valori delle proprietà sono restituiti con wikilink, compresa eventuale disambiguazione nascosta con la barra verticale (es. [[Savoia (dipartimento)|Savoia]]). Il collegamento viene ricavato dall'interlink in italiano del rispettivo elemento su Wikidata; se il soggetto non è presente su Wikidata, oppure non possiede un interlink in italiano, il valore viene restituito senza wikilink.
  • getQualifier: restituisce il valore di un qualifier (qualificatore) di una proprietà di Wikidata. Se la proprietà ha più statement (dichiarazioni) e il qualifier è presente in più statement, oppure se il qualifier ha più valori, li può restituire tutti, oppure si possono filtrare in base a rank (classificazione) e indice (dello statement) come per la funzione formatStatements.
  • N: ritorna il numero di statement (dichiarazioni) della proprietà richiesta.
  • checkStatements[1] verifica se una proprietà di Wikidata ha un determinato valore. Nel caso una proprietà abbia più di una dichiarazione (statement) ne verifica tutti i valori. Se la pagina non ha un elemento su Wikidata, oppure non ha la proprietà specificata, oppure il valore della proprietà non corrisponde a quello da verificare, non restituisce nulla; altrimenti restituisce un numero corrispondente all'indice dello statement verificato.

Parametri di formatStatements[modifica]

La funzione formatStatements ha i seguenti parametri, l'unico obbligatorio è property. Gli esempi utilizzati fanno riferimento alla voce Dante Alighieri (il cui elemento su Wikidata è: Q1067).

Parametri di selezione
  • property: l'identificatore della proprietà;
    • esempio: {{#invoke:Wikidata|formatStatements|property=p19}} ritornerà: Firenze (P19 è il luogo di nascita).
  • rank: se valorizzato, il modulo ritorna solo gli statement che hanno un certo rank (classificazione). I rank disponibili sono i tre definiti da Wikidata: deprecated (sconsigliato), normal (normale) e preferred (preferito), più il tipo best (migliore). Con quest'ultimo vengono ritornati gli statement a partire dal rank più alto: i preferred se presenti, altrimenti i normal, mai i deprecated.
  • qualifier: l'identificatore di un qualifier (qualificatore) di una proprietà. Verranno ritornati solo gli statement che posseggono quel qualifier.
  • qualifiervalue: l'identificatore del valore del qualifier (qualificatore) specificato con il parametro qualifier. Verranno ritornati solo gli statement che posseggono quel qualifier e con il valore specificato con qualifiervalue.
  • qualifiertype: ulteriore filtro sul qualifier (qualificatore) specificato. Ha attualmente un unico valore accettato, qualifiertype=latest: se il qualifier contiene un valore di tipo "time", verrà ritornato solo lo statement che possiede quel qualifier e con il valore più recente.
  • n: se la proprietà ha più statement (dichiarazioni) ritorna solo il valore dell'n-esimo;
    • esempio: {{#invoke:Wikidata|formatStatements|property=p106|n=1}} ritornerà: poeta (P106 è la professione, mentre con n=2 avrebbe ritornato scrittore, con n=3 politico, ecc.).
  • value: se valorizzato, il modulo ritorna il valore di questo parametro invece di quello su Wikidata, formattandolo eventualmente secondo il pattern se specificato. Serve quando si usa il modulo all'interno di un template, per dare la precedenza al valore passato al template rispetto a quello su Wikidata;
    • esempio: {{#invoke:Wikidata|formatStatements|property=p19|value={{{LuogoNascita|}}}}} ritornerà: il valore di LuogoNascita se valorizzato nel template, altrimenti quello della proprietà P19 su Wikidata.
  • entityId: l'identificatore dell'entità – per ora NON FUNZIONANTE – quando sarà attivato permetterà di specificare un'entità (entity) di Wikidata relativa a una pagina diversa da quella in cui ci si trova.
Parametri per la formattazione del risultato
  • separator: separatore tra valori multipli, se diverso da virgola_spazio;
  • conjunction: separatore tra gli ultimi due valori, se diverso da spazio_e_spazio;
    • esempio: {{#invoke:Wikidata|formatStatements|property=p106|separator=/|conjunction=/}} ritornerà: poeta/scrittore/politico.
  • pattern: pattern utilizzato per ogni statement, sia per le proprietà che per il parametro "value" quando presente. La stringa "$1" verrà rimpiazzata dal valore ritornato per ogni sua occorrenza;
    • esempio: {{#invoke:Wikidata|formatStatements|property=p18|pattern=[[File:$1|thumb|Il nome del file è $1]]}} ritornerà: [[File:Portrait de Dante.jpg|thumb|Il nome del file è Portrait de Dante.jpg]] (P18 è l'immagine).
    • esempio con "value": {{#invoke:Wikidata|formatStatements|property=p18|value={{{Immagine|}}}|pattern=[[File:$1|thumb|Il nome del file è $1]]}} In un template, se il parametro Immagine fosse valorizzato a "Test.png" allora ritornerebbe [[File:Test.png|thumb|Il nome del file è Test.png]], altrimenti se Immagine non fosse valorizzato, ritornerebbe lo stesso risultato dell'esempio precedente.
  • novaluepattern:[1] se valorizzato, applica il pattern precedentemente definito solo agli statement di Wikidata e non al parametro "value"; es: "novaluepattern=no".
  • list: formatta il risultato ritornato come lista non ordinata; si deve assegnargli un valore qualunque, es: "list=sì". Eventuali parametri separator e conjunction vengono ignorati;
    • esempio: {{#invoke:Wikidata|formatStatements|property=p106|list=sì}}.
  • orderedlist: formatta il risultato ritornato come lista ordinata; si deve assegnargli un valore qualunque, es: "orderedlist=sì". Eventuali parametri separator e conjunction vengono ignorati. Se sono presenti entrambi i parametri list e orderedlist viene creata una lista non ordinata;
    • esempio: {{#invoke:Wikidata|formatStatements|property=p106|orderedlist=sì}}.

  • formatting: esegue formattazioni speciali, attulmente i valori consentiti sono:
    • formatting=nolink[1] per ritornare il risultato senza wikilink (anche se disponibile);
    • formatting=latitude e formatting=longitude per ritornare solo latitudine o longitudine in caso di proprietà di tipo coordinata.
  • value-module: nome di un modulo che effettua una formattazione speciale.
  • value-function: funzione nel modulo value-module.

Parametri di getQualifier[modifica]

Parametri di selezione:

  • gli stessi di formatStatements, con in più la differenza che i parametri obbligatori sono, oltre "property", anche "qualifier".

Parametri per la formattazione del risultato:

  • gli stessi di formatStatements, ad eccezione di list e orderedlist (non disponibili).

Parametri di N[modifica]

La funzione N ha un unico parametro (ordinale) obbligatorio per specificare la proprietà.

  • esempio: {{#invoke:Wikidata|N|p40}} ritornerà: 2 (P40 è "figlio").

Parametri di checkStatements[modifica]

La funzione checkStatements ha due parametri, di cui property è obbligatorio.

  • property: l'identificatore della proprietà.
  • value: il valore da verificare; value può essere espresso sia come stringa di testo sia come identificatore dell'elemento corrispondente su Wikidata;
    • esempio: {{#invoke:Wikidata|checkStatements|property=p106|value=poeta}} ritornerà: 1 (P106 è la professione, e "poeta" è la prima professione),
    • esempio: {{#invoke:Wikidata|checkStatements|property=p106|value=q49757}} ritornerà: 1 (P106 è la professione e Q49757 è l'identificatore dell'elemento "poeta").

Note[modifica]

  1. a b c :Funzionalità nuova e aggiuntiva rispetto al corrispondente modulo su Wikipedia.

Pagine correlate[modifica]


--[[
* Modulo per implementare le funzionalità dei template {{Wikidata}} e {{Wikidata Check}}.
* 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
]]

-- Messaggi di errore
local i18n = {
	["errors"] = {
		["property-param-not-provided"] = "Parametro ''property'' non fornito.",
		["qualifier-param-not-provided"] = "Parametro ''qualifier'' non fornito.",
		["entity-not-found"] = "Entità non trovata.",
		["unknown-claim-type"] = "Tipo asserzione sconosciuta.",
		["unknown-snak-type"] = "Tipo di snak sconosciuto.",
		["unknown-datavalue-type"] = "Tipo di dato sconosciuto.",
		["unknown-entity-type"] = "Tipo di entità sconosciuta.",
		["unknown-value-module"] = "Devi impostare entrambi i parametri: ''value-module'' e ''value-function''.",
		["value-module-not-found"] = "Modulo indicato da ''value-module'' non trovato.",
		["value-function-not-found"] = "Funzione indicata da ''value-function'' non trovata."
	},
	["somevalue"] = "''valore sconosciuto''",
	["novalue"] = "''nessun valore''"
}

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

local function formatError(key)
	return '<span class="error">' .. i18n.errors[key] .. '</span>'
end

local function formatList(values, ordered)
	local fmt = ordered and '<ol><li>%s</li></ol>' or '<ul><li>%s</li></ul>'
	return #values > 0 and string.format(fmt, mw.text.listToText(values, '</li><li>', '</li><li>')) or ''
end

local function formatEntityId(entityId, options, formatting)
	if formatting == 'raw' then
		return entityId
	end

	local label = mw.wikibase.label(entityId)
	local link = mw.wikibase.sitelink(entityId)
	if link and options.formatting ~= 'nolink' 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 = ''
 
	if args.time == 'precision' then
		ret = value.precision
	elseif args.time == 'calendarmodel' then
		ret = value.calendarmodel
	elseif args.time == 'year' and value.precision >= 9 then
		year, month, day = value.time:match('(%d+)%-(%d%d)%-(%d%d).+')
		ret = tonumber(year)
	elseif args.time == 'month' and value.precision >= 10 then
		year, month, day = value.time:match('(%d+)%-(%d%d)%-(%d%d).+')
		ret = mw.getLanguage('it'):formatDate('F', tonumber(year) .. '-' .. month)
	elseif args.time == 'day' and value.precision >= 11 then
		year, month, day = value.time:match('(%d+)%-(%d%d)%-(%d%d).+')
		ret = tonumber(day)
	elseif not args.time then
		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
	end

	return ret
end

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

local function formatFromPattern(str, options)
	-- la parentesi () extra serve per non ritornare anche il gsub.count
	return (mw.ustring.gsub(options.pattern, '$1', str))
end

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

local function formatDatavalue(datavalue, options, formatting)
	local ret

	--Use the customize handler if provided
	if options['value-module'] or options['value-function'] then
		if not options['value-module'] or not options['value-function'] then
			return formatError('unknown-value-module')
		end
		local formatter = require ('Modulo:' .. options['value-module'])
		if formatter == nil then
			return formatError('value-module-not-found')
		end
		local funct = formatter[options['value-function']]
		if funct == nil then
			return formatError('value-function-not-found')
		end
		return funct(datavalue.value, options)
	end

	--Default formatters
	if datavalue.type == 'wikibase-entityid' then
		ret = formatEntityId(getEntityIdFromValue(datavalue.value), options, formatting)
	elseif datavalue.type == 'string' then
		ret = datavalue.value
	elseif datavalue.type == 'monolingualtext' then
		ret = datavalue.value.text
	elseif datavalue.type == 'time' then
		ret = formatTime(datavalue.value, options)
	elseif datavalue.type == 'globecoordinate' then
		ret = formatGlobecoordinate(datavalue.value, options)
	elseif datavalue.type == 'quantity' then
		ret = tonumber(datavalue.value.amount)
	else
		ret = formatError('unknown-datavalue-type')
	end

	return ret
end

local function formatSnak(snak, options, formatting)
	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, options, formatting)
	else
		return formatError('unknown-snak-type')
	end
end

local function formatStatement(statement, options)
	if not statement.type or statement.type ~= 'statement' then
		return formatError('unknown-claim-type')
	end

	return formatSnak(statement.mainsnak, options)
end

local function formatStatements(claims, options)
	local formattedStatements = {}

	for _, claim in pairs(claims) do
		local formattedStatement = formatStatement(claim, options)
		-- eventuale pattern
		if options.pattern then
			formattedStatement = formatFromPattern(formattedStatement, options)
		end
		table.insert(formattedStatements, formattedStatement)
	end

	return ((options.list or options.orderedlist) and #formattedStatements > 1) and
		   formatList(formattedStatements, options.orderedlist ~= nil) or 
		   mw.text.listToText(formattedStatements, options.separator, options.conjunction)
end

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

-- Ritorna true se lo statement contiene il qualifier richiesto con un dato valore
local function hasQualifierValue(statement, options)
	local ret = false
	for i, qualifier in pairs(statement.qualifiers[options.qualifier]) do
		if formatSnak(qualifier, options, 'raw') == options.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.
-- Gli statement ritornati sono eventualmente filtrati in base ai parametri:
-- "rank", "qualifier", "qualifiertype" e "n"
local function getClaims(options)
	local entityId, entity, claims, filteredClaims

	-- get entity
	entityId = options.entityId and string.upper(options.entityId)
	entity = mw.wikibase.getEntity(entityId)
	if not entity then
		error('') -- error(formatError('entity-not-found'))
	end

	-- get property
	if not options.property then
		error(formatError('property-param-not-provided'))
	end

	if entity.claims and entity.claims[options.property] and
		#entity.claims[options.property] > 0 then
		claims = entity.claims[options.property]
	else
		error('') --TODO error?
	end

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

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

	-- con options.qualifiertype=latest ritorna solo il più recente
	if options.qualifier and options.qualifiertype == 'latest' then
		local latest, latestTime
		for i, claim in pairs(claims) do
			if claim.qualifiers and claim.qualifiers[options.qualifier] then
				for j, qualifier in pairs(claim.qualifiers[options.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 options.n ritorna solo l'n-esimo elemento
	if options.n then
		local n = tonumber(options.n)
		claims = (n and n <= #claims) and {claims[n]} or {}
	end

	return claims
end

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

local p = {}

-- Funzione di utilità, ritorna gli argomenti passati al modulo
-- scartando quelli valorizzati a stringhe vuote
local function getArgs(frame)
	local args = {}

	if frame == mw.getCurrentFrame() then
		-- argomenti passati indirettamente come parametri del template invocante
		local parent = frame:getParent()
		local parentArgs = parent and parent.args or {}
		for k, v in pairs(parentArgs) do
			if v ~= '' then
				args[k] = v
			end
		end
		-- argomenti passati direttamente come parametri di #invoke
		for k, v in pairs(frame.args) do
			if v ~= '' then
				args[k] = v
			end
		end
	else
		args = frame
	end

	-- trasforma i valori di property, qualifier e qualifiervalue in maiuscolo
	local toUpper = {
		property = true,
		qualifier = true,
		qualifiervalue = true
	}
	for k, v in pairs(args) do
		if toUpper[k] then
			args[k] = string.upper(v)
		end
	end

	-- rank impostato a best per default
	args.rank = args.rank or 'best'

	return args
end

-- Entry-point per {{#invoke:Wikidata|formatStatements}}
function p.formatStatements(frame)
	local args, ret, claims

	args = getArgs(frame)

	-- if parameter value is already set, use it
	if args.value then
		return not(args.novaluepattern) -- if parameter novaluepattern is not set
			and args.pattern and formatFromPattern(args.value, args)
			or args.value
	end

	-- get claims
	ret, claims = pcall(getClaims, args)
	if not ret then
		return claims:match('.+%d:%s(.+)$')
	end

	return formatStatements(claims, args)
end

-- Entry-point per {{#invoke:Wikidata|getQualifier}}
function p.getQualifier(frame)
	local args, ret, claims, formattedQualifier, formattedQualifiers

	args = getArgs(frame)

	-- if parameter value is already set, use it
	if args.value then
		return not(args.novaluepattern) -- if parameter novaluepattern is not set
			and args.pattern and formatFromPattern(args.value, args)
			or args.value
	end

	-- get qualifier name
	if not args.qualifier then
		return formatError('qualifier-param-not-provided')
	end

	-- get claims
	ret, claims = pcall(getClaims, args)
	if not ret then
		return claims:match('.+%d:%s(.+)$')
	end

	-- get qualifiers and format them
	formattedQualifiers = {}
	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
				formattedQualifier = formatSnak(qualifier, args)
				if args.pattern then
					formattedQualifier = formatFromPattern(formattedQualifier, args)
				end
				table.insert(formattedQualifiers, formattedQualifier)
			end
		end
	end

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

-- Entry-point per {{#invoke:Wikidata|N}}
function p.N(frame)
	local property, count, entity, entityId

	property = frame.args[1] and string.upper(frame.args[1])

	if not property then
		return formatError('property-param-not-provided')
	end

	entityId = frame.args.entityId and string.upper(frame.args.entityId)
	entity = mw.wikibase.getEntity(entityId)
	if entity and entity.claims and entity.claims[property] then
		count = #entity.claims[property]
	end

	return count or 0
end

-- Entry-point per {{#invoke:Wikidata|checkStatements}}
function p.checkStatements(frame)
	local property, value, checkvalue, entity, entityId

	property = frame.args.property and string.upper(frame.args.property)

	if not property then
		return formatError('property-param-not-provided')
	end

	value = frame.args.value
	entityId = frame.args.entityId and string.upper(frame.args.entityId)
	entity = mw.wikibase.getEntity(entityId)
	if entity and entity.claims and entity.claims[property] then
		local claims = entity.claims[property]
		for n, claim in pairs(claims) do
			if claim and claim.mainsnak and claim.mainsnak.datavalue then
				local datavalue = claim.mainsnak.datavalue
				-- controllo tramite identificatore per tipo di dato "entità" (proprietà/elemento)
				if datavalue.type == 'wikibase-entityid' then
					checkvalue = getEntityIdFromValue(datavalue.value)
					if checkvalue == string.upper(value) then
						return n
					end
				end
				-- controllo testuale tra stringhe (testo semplice senza wikilink)
				local options = { formatting = 'nolink' }
				checkvalue = formatDatavalue(datavalue, options)
				if tostring(checkvalue) == value then
					return n
				end
			end
		end
	end

	return ''
end

return p