Modulo:Wikidata: differenze tra le versioni

Contenuto cancellato Contenuto aggiunto
nuova funzione getQualifier, possibilità di filtrare per qualifier, nuovi parametri qualifiervalue, qualifiertype e formatting, formato primo del mese
m inverto logica del parametro per retrocompatibilità
 
(121 versioni intermedie di 7 utenti non mostrate)
Riga 1:
--[[
* Modulo per implementare le funzionalità dei template:
* Modulo per accedere a Wikidata in modo più avanzato rispetto a {{#property}}.
* {{Wikidata}}, {{WikidataQ}}, {{WikidataIdx}}, {{WikidataN}}, {{WikidataLabel}}, {{WikidataDescription}}
* {{WikidataLink}}, {{WikidataId}}, {{WikidataTipo}} e {{WikidataIstanza}}.
* Permette di accedere a Wikidata in modo più avanzato rispetto a {{#property}}.
 
* Per la maggior parte riscritto e ampliato a partire dalla versione iniziale a:
* Il modulo è stato importato inizialmente da:
* http://test2.wikipedia.org/w/index.php?title=Module:Wikidata&oldid=52322
* Nota per chi sviluppa: entity.claims[property] è una sequence Lua ma inizia da 0 invece che da 1, quindi:
* la dimensione è #entity.claims[property] + 1 ed è vuota quando next(entity.claims[property]) == nil.
]]
 
-- =============================================================================
-- Non utilizzare mai mw.wikibase.getEntity, per esempio un solo utilizzo di
-- mw.wikibase.getEntity('Q183') fa aumentare di 7 MB l'utilizzo di memoria
-- per Lua ed è molto lenta se ripetuta (unico utilizzo in getDatatype,
-- solo per proprietà, non essendoci alternative).
-- =============================================================================
 
require('strict')
 
local getArgs = require('Module:Arguments').getArgs
local mConvert = require('Module:Conversione')
local mLanguages = require('Module:Lingue')
 
-- Categoria per le pagine con errori
local errorCategory = '[[Categoria:Voci con errori del modulo Wikidata]]'
 
-- Messaggi
local i18n = {
[" errors"] = {
["property'entityid-param-not-provided"'] = "Parametro ''propertyentityid'' non fornito.",
["qualifier'property-param-not-provided"'] = "Parametro ''qualifierproperty'' non fornito.",
["entity'qualifier-param-not-found"provided'] = "EntitàParametro ''qualifier'' non trovata.fornito",
['value-param-not-provided'] = "Parametro ''valore'' da ricercare non fornito",
["unknown-claim-type"] = "Tipo asserzione sconosciuta.",
['entity-not-found'] = 'Entità non trovata',
["unknown-snak-type"] = "Tipo di snak sconosciuto.",
["'unknown-datavalueclaim-type"'] = "'Tipo di datoasserzione sconosciuto."sconosciuta',
["'unknown-entitysnak-type"'] = "'Tipo di entitàsnak sconosciuta."sconosciuto',
['unknown-datavalue-type'] = 'Tipo di dato sconosciuto',
["unknown-value-module"] = "Devi impostare entrambi i parametri: ''value-module'' e ''value-function''.",
['unknown-entity-type'] = 'Tipo di entità sconosciuta',
["value-module-not-found"] = "Modulo indicato da ''value-module'' non trovato.",
['unknown-output-format'] = 'Formato di output sconosciuto'
["value-function-not-found"] = "Funzione indicata da ''value-function'' non trovata."
},
[" somevalue"] = "''valore sconosciuto''",
[" novalue"] = "''nessun valore''",
datatypes = {
['commonsMedia'] = 'file multimediale su Commons',
['external-id'] = 'identificativo esterno',
['geo-shape'] = 'forma geografica',
['globe-coordinate'] = 'coordinate geografiche',
['math'] = 'espressione matematica',
['monolingualtext'] = 'testo monolingua',
['quantity'] = 'quantità',
['string'] = 'stringa',
['tabular-data'] = 'tabular data',
['time'] = 'data e ora',
['url'] = 'URL',
['wikibase-item'] = 'elemento',
['wikibase-property'] = 'proprietà'
}
}
 
local p = {}
 
-------------------------------------------------------------------------------
-- 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 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 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('<span style="word-break: break-all;">[%s %s]</span>', dest, dest:gsub(uri.protocol .. '://', ''))
else
return url
end
end
 
local function formatEntityId(entityId)
local label = mw.wikibase.getLabel(entityId)
local siteLink = mw.wikibase.getSitelink(entityId)
local ret
if entityId == mw.wikibase.getEntityIdForCurrentPage() then
ret = siteLink
elseif siteLink and label then
ret = mw.getContentLanguage():ucfirst(label) == siteLink and
string.format('[[%s]]', label) or
string.format('[[%s|%s]]', siteLink, label)
elseif siteLink then
ret = string.format('[[%s]]', siteLink)
elseif label then
ret = label
else
ret = ''
end
return ret
end
 
local function formatMonolingualtext(value, args)
local ret = ''
if not args.includelang or args.includelang:match('%f[a-z]' .. value.language .. '%f[^a-z]') then
if not args.excludelang or not args.excludelang:match('%f[a-z]' .. value.language .. '%f[^a-z]') then
ret = value.text
if args.showlang then
ret = mLanguages.lingue({ value.language }) .. '&nbsp;' .. ret
end
end
end
return ret
end
 
local function formatTimeWithPrecision(time, precision)
local months = {
'gennaio', 'febbraio', 'marzo', 'aprile', 'maggio', 'giugno',
'luglio', 'agosto', 'settembre', 'ottobre', 'novembre', 'dicembre'
}
local ret, year, month, day
year, month, day = time:match('(%d+)%-(%d%d)%-(%d%d).+')
function getEntityFromId( id )
year, month, day = tonumber(year), tonumber(month), tonumber(day)
if id then
if precision == 9 then
return mw.wikibase.getEntity( id )
ret = year
end
elseif precision == 10 then
return mw.wikibase.getEntity()
ret = months[month] .. ' ' .. year
elseif precision == 11 then
ret = day .. ' ' .. months[month] .. ' ' .. year
ret = ret:gsub('^1%s', '1º ')
end
if precision >= 9 and precision <= 11 then
ret = ret .. (time:sub(1, 1) == '-' and ' a.C.' or '')
end
 
return ret
end
 
local function formatTime(value, args)
local ret
if args.time == 'precision' then
function getEntityIdFromValue( value )
ret = value.precision
local prefix = ''
elseif if value['entity-type']args.time == 'itemcalendarmodel' then
ret = value.calendarmodel
prefix = 'Q'
elseif args.time == 'year' elseifand value['entity-type'].precision =>= 'property'9 then
ret = formatTimeWithPrecision(value.time, 9)
prefix = 'P'
elseif args.time == 'month' and value.precision >= 10 then
else
ret = formatTimeWithPrecision(value.time, 10)
return formatError( 'unknown-entity-type' )
elseif args.time == 'day' and value.precision >= 11 then
end
ret = formatTimeWithPrecision(value.time, 11)
return prefix .. value['numeric-id']
elseif not args.time then
ret = formatTimeWithPrecision(value.time, value.precision)
end
 
return ret or ''
end
 
local function formatGlobecoordinate(value, args)
local ret
if args.coord == 'latitude' then
ret = value.latitude
elseif args.coord == 'longitude' then
ret = value.longitude
elseif args.coord == 'globe' then
ret = value.globe
else
ret = string.format('%s, %s', 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 formatUserValue(value, args)
if args.extlink then
value = formatExtLink(value)
end
return args.pattern and formatFromPattern(value, args) or value
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 formatUnitSymbol(entityId, args)
local ret
for _, lang in ipairs({ 'mul', 'it', 'en' }) do
ret = p._getProperty({ 'P5061', includelang = lang, from = entityId })
if ret and ret ~= '' then
break
else
ret = nil
end
end
local space = ret == '°' and '' or ' '
if ret and args.showunitlink then
local link = mw.wikibase.getSitelink(entityId)
if link then
ret = string.format('[[%s|%s]]', link, ret)
end
end
return ret and (space .. ret) or ''
end
 
-- http://lua-users.org/wiki/SimpleRound
local function round(num, idp)
local mult = 10 ^ (idp or 0)
return math.floor(num * mult + 0.5) / mult
end
 
 
local function formatQuantity(value, args)
local ret = tonumber(value.amount)
 
if (args.unit or args.showunit) and value.unit ~= '1' then
local unitId = mw.ustring.match(value.unit, 'Q%d+')
if args.unit then
local opts = {
showunit = args.showunit,
showunitlink = args.showunitlink,
formatnum = args.formatnum,
rounding = args.rounding
}
ret = mConvert._main(ret, unitId, args.unit, opts)
else
-- se è richiesto solo il simbolo dell'unità
-- senza la conversione lo ottiene da P5061
ret = args.rounding and round(ret, args.rounding) or ret
if args.formatnum then
ret = mw.language.getContentLanguage():formatNum(ret)
end
ret = ret .. formatUnitSymbol(unitId, args)
end
elseif args.formatnum then
ret = args.rounding and round(ret, args.rounding) or ret
ret = mw.language.getContentLanguage():formatNum(ret)
elseif args.formatduration and value.unit ~= '1' then
local unitId = mw.ustring.match(value.unit, 'Q%d+')
ret = mConvert._main(ret, unitId, 'second')
ret = ret and mw.language.getContentLanguage()
:formatDuration(tonumber(ret), { 'days', 'hours', 'minutes', 'seconds' })
end
 
return ret
end
 
local function formatDatavalue(datavalue, snakdatatype, args)
local ret
 
if datavalue.type == 'wikibase-entityid' then
local entityId = getEntityIdFromValue(datavalue.value)
if args.showprop then
ret = p._getProperty({ args.showprop, n = 1, from = entityId, formatting = args.formatting }) or ''
elseif args.formatting then
local formatting = args.formatting:lower()
ret = (formatting == 'raw' or formatting == 'id') and entityId or
formatting == 'label' and mw.wikibase.getLabel(entityId) or
formatting == 'title' and (mw.wikibase.getSitelink(entityId) or '') or
error(i18n.errors['unknown-output-format'])
else
ret = formatEntityId(entityId)
end
elseif datavalue.type == 'string' then
ret = datavalue.value
if args.extlink and snakdatatype == 'url' then
ret = formatExtLink(ret)
elseif args.urlencode then
ret = mw.uri.encode(ret)
end
elseif datavalue.type == 'monolingualtext' then
ret = formatMonolingualtext(datavalue.value, args)
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 = formatQuantity(datavalue.value, args)
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, snak.datatype, args)
else
error(i18n.errors['unknown-snak-type'])
end
end
 
-- È al plurale perché anche i qualifier possono avere più di un valore
-- (si ottiene inserendo due volte lo stesso qualifier)
local function formatQualifiers(claim, qualifierId, args, rawTable, retTable)
local formattedQualifiers = retTable or {}
 
if claim.qualifiers and claim.qualifiers[qualifierId] then
local qualifiers = claim.qualifiers[qualifierId]
-- con args.nq seleziona solo l'n-esimo qualifier
if args.nq then
local n = tonumber(args.nq)
qualifiers = (n and n <= #qualifiers) and { qualifiers[n] } or {}
end
-- qualifier filtrati per snaktype, default "value"
args.snaktype = args.snaktype or 'value'
for _, qualifier in ipairs(qualifiers) do
if qualifier.snaktype == args.snaktype or args.snaktype == 'all' then
local formattedQualifier = formatSnak(qualifier, args)
if formattedQualifier ~= '' then
if args.pattern then
formattedQualifier = formatFromPattern(formattedQualifier, args)
if formattedQualifier ~= '' then
table.insert(formattedQualifiers, formattedQualifier)
end
else
table.insert(formattedQualifiers, formattedQualifier)
end
end
end
end
end
 
if rawTable then
return formattedQualifiers
end
 
return #formattedQualifiers > 0 and
mw.text.listToText(formattedQualifiers, args.separator, args.conjunction) or nil
end
 
local function appendQualifiers(statement, text, args)
local formattedQualifiers = {}
local qualifierIds = mw.text.split(args.showqualifiers, ',')
for _, qualifierId in ipairs(qualifierIds) do
if statement.qualifiers[qualifierId] then
local formattedQualifier = formatQualifiers(statement, qualifierId, args)
table.insert(formattedQualifiers, formattedQualifier)
end
end
if #formattedQualifiers > 0 then
text = string.format('%s (%s)', text, mw.text.listToText(formattedQualifiers, ', ', ', '))
end
return text
end
 
local function formatStatement(statement, args)
if not statement.type or statement.type ~= 'statement' then
error(i18n.errors['unknown-claim-type'])
end
local ret = formatSnak(statement.mainsnak, args)
function formatError( key )
-- eventuale showqualifiers
return '<span class="error">' .. i18n.errors[key] .. '</span>'
if args.showqualifiers and statement.qualifiers then
ret = appendQualifiers(statement, ret, args)
end
 
return ret
end
 
local function hasQualifierValueformatStatements( statementclaims, optionsargs, rawTable)
local retformattedStatements = false{}
 
for i, qualifier in pairs( statement.qualifiers[options.qualifier] ) do
for _, claim in ipairs(claims) do
if formatSnak( qualifier, options, 'raw' ) == options.qualifiervalue then
local formattedStatement = formatStatement(claim, args)
ret = true
if formattedStatement ~= '' then
break
-- eventuale pattern
end
if args.pattern then
end
formattedStatement = formatFromPattern(formattedStatement, args)
return ret
if formattedStatement ~= '' then
table.insert(formattedStatements, formattedStatement)
end
else
table.insert(formattedStatements, formattedStatement)
end
end
end
if rawTable then
return formattedStatements
end
 
return ((args.list or args.orderedlist) and #formattedStatements > 1) and
formatList(formattedStatements, args.orderedlist ~= nil) or
mw.text.listToText(formattedStatements, args.separator, args.conjunction)
end
 
-------------------------------------------------------------------------------
-- Ritorna una table contenente gli statement per la property richiesta.
-- Lettura e selezione statement
-- Gli statement ritornati sono eventualmente filtrati in base ai parametri:
-------------------------------------------------------------------------------
-- "rank", "qualifier", "qualifiertype" e "n"
 
local function getClaims( options )
-- Restituisce true se lo statement contiene il qualifier richiesto con un dato valore (o uno tra più valori separati da virgola)
local entity, property, claims, filteredClaims
local function hasQualifierValue(statement, qualifierId, qualifierValue)
local ret = false
for _, qualifier in ipairs(statement.qualifiers[qualifierId]) do
local isItem = qualifier.snaktype == 'value' and
qualifier.datavalue.type == 'wikibase-entityid'
local qualifierValues = mw.text.split(qualifierValue, ',')
for _, qualifierHas in ipairs(qualifierValues) do
-- per le proprietà di tipo item il confronto è eseguito sull'id
if formatSnak(qualifier, isItem and { formatting = 'raw' } or {}) == qualifierHas then
ret = true
break
end
end
end
return ret
end
 
-- Restituisce i claim con il rank richiesto
local function filterRankValue(claims, rank)
local ret = {}
for _, claim in ipairs(claims) do
if claim.rank == rank then
table.insert(ret, claim)
end
end
return ret
end
 
-- Restituisce una sequence Lua contenente gli statement per la property richiesta,
-- anche vuota se la proprietà non esiste, o non ci sono valori che soddisfano i criteri
-- ("rank", "qualifier", "qualifiertype", "noqualifier", ...).
-- Restituisce nil solo se la pagina non è collegata a un elemento Wikidata e non è indicato il from.
local function getClaims(propertyId, args)
local entityId, claims, filteredClaims
entityId = args.from or mw.wikibase.getEntityIdForCurrentPage()
if not entityId then
return nil
end
-- il default rank è 'best'
-- get entity
args.rank = args.rank or 'best'
entity = getEntityFromId( options.entityId )
if args.rank == if not entity'best' then
claims = mw.wikibase.getBestStatements(entityId, propertyId)
error( '' ) -- error(formatError( 'entity-not-found' ))
else
end
-- statements filtrati per rank
claims = mw.wikibase.getAllStatements(entityId, propertyId)
claims = filterRankValue(claims, args.rank)
end
 
-- statements filtrati per snaktype, default "value"
-- get property
args.snaktype = args.snaktype or 'value'
if not options.property then
if args.snaktype and args.snaktype ~= 'all' then
return error( formatError( 'property-param-not-provided' ) )
filteredClaims = {}
end
for _, claim in ipairs(claims) do
property = string.lower( options.property )
if claim.mainsnak.snaktype == args.snaktype then
table.insert(filteredClaims, claim)
end
end
claims = filteredClaims
end
 
-- statements filtrati per qualifier
if entity.claims == nil or
if args.qualifier then
entity.claims[property] == nil or
filteredClaims = {}
type(entity.claims[property]) ~= 'table' or
for _, claim in nextipairs(entity.claims[property]) == nil thendo
if claim.qualifiers and claim.qualifiers[args.qualifier] then
error('') --TODO error?
if args.qualifiervalue then
end
if hasQualifierValue(claim, args.qualifier, args.qualifiervalue) then
table.insert(filteredClaims, claim)
end
else
table.insert(filteredClaims, claim)
end
end
end
claims = filteredClaims
end
 
-- statements filtrati per essere senza un qualifier
-- converte entity.claims in una vera sequence (inizia da 1)
if args.noqualifier then
claims = {}
filteredClaims = {}
for i = 0, #entity.claims[property] do
for _, claim in ipairs(claims) do
table.insert( claims, entity.claims[property][i] )
if not (claim.qualifiers and claim.qualifiers[args.noqualifier]) then
end
table.insert(filteredClaims, claim)
end
end
claims = filteredClaims
end
 
-- statements filtrati per ranknon avere un certo valore a un certo qualifier opzionale
if args.qualifieroptnovalue and args.qualifiervalue then
if options.rank then
filteredClaims = {}
for i_, claim in pairsipairs(claims) do
if claim.rankqualifiers ==and optionsclaim.qualifiers[args.rankqualifieroptnovalue] then
if not hasQualifierValue(claim, args.qualifieroptnovalue, args.qualifiervalue) then
table.insert( filteredClaims, claim )
table.insert(filteredClaims, claim)
end
end
else
claims = filteredClaims
table.insert(filteredClaims, claim)
end
end
end
claims = filteredClaims
end
 
-- con args.qualifiertype=latest restituisce solo il più recente
-- statements filtrati per qualifier
if args.qualifier and args.qualifiertype == 'latest' then
if options.qualifier then
local latest, latestTime
filteredClaims = {}
for i_, claim in pairsipairs(claims) do
if claim.qualifiers and claim.qualifiers[optionsargs.qualifier] then
for _, qualifier in ipairs(claim.qualifiers[args.qualifier]) do
if options.qualifiervalue then
if qualifier.datavalue.type == 'time' then
if hasQualifierValue( claim, options ) then
if not latestTime or qualifier.datavalue.value.time > latestTime then
table.insert( filteredClaims, claim )
latest = claim
end
latestTime = qualifier.datavalue.value.time
else
end
table.insert( filteredClaims, claim )
end
end
end
end
end
end
claims = filteredClaims
claims = latest and { latest } or {}
end
end
 
-- con optionsargs.qualifiertype=latestn ritornarestituisce solo il piùl'n-esimo recenteelemento
if args.n then
if options.qualifier and options.qualifiertype == 'latest' then
local n = tonumber(args.n)
local latest, latestTime
claims = (n and n <= #claims) and { claims[n] } or {}
for i, claim in pairs( claims ) do
end
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
claims = latest and { latest } or {}
end
 
return claims
-- con options.n ritorna solo l'n-esimo elemento
end
if options.n then
local n = tonumber( options.n )
claims = (n and n <= #claims) and { claims[n] } or {}
end
 
-------------------------------------------------------------------------------
return claims
-- Funzioni esportate per altri moduli
-------------------------------------------------------------------------------
 
function p._getClaims(propertyId, args)
return getClaims(propertyId, args or {})
end
function formatStatements( claims, options )
--Format statement and concat them cleanly
local formattedStatements = {}
local list_end, formattedStatement
if options.list or options.orderedlist then
if options.list then
formattedStatements[1] = '<ul><li>'
list_end = '</li></ul>'
else
formattedStatements[1] = '<ol><li>'
list_end = '</li></ol>'
end
options.separator = '</li><li>'
options.conjunction = options.separator
end
for i, claim in pairs( claims ) do
formattedStatement = formatStatement( claim, options )
-- eventuale pattern
if options.pattern then
formattedStatement = formatFromPattern( formattedStatement, options )
end
table.insert( formattedStatements, formattedStatement )
end
 
function p._formatStatement(statement, args)
if list_end then table.insert( formattedStatements, list_end ) end
return formatStatement(statement, args or {})
return mw.text.listToText( formattedStatements, options.separator, options.conjunction )
end
 
function formatStatementp._formatQualifiers(claim, statementqualifierId, optionsargs, rawTable, retTable)
return formatQualifiers(claim, qualifierId, args or {}, rawTable, retTable)
if not statement.type or statement.type ~= 'statement' then
return formatError( 'unknown-claim-type' )
end
return formatSnak( statement.mainsnak, options )
end
 
-- Restituisce il valore di una proprietà di Wikidata oppure nil se l'entity o
function formatSnak( snak, options, formatting )
-- la proprietà non esistono, o se per parametri di selezione gli statement sono zero.
if snak.snaktype == 'somevalue' then
function p._getProperty(args, rawTable)
return i18n['somevalue']
local propertyId, value, claims, ret
elseif snak.snaktype == 'novalue' then
 
return i18n['novalue']
-- parametri posizionali
elseif snak.snaktype == 'value' then
propertyId = args[1] and string.upper(args[1])
return formatDatavalue( snak.datavalue, options, formatting )
if not propertyId then
else
error(i18n.errors['property-param-not-provided'], 2)
return formatError( 'unknown-snak-type' )
end
value = args[2]
-- fix uppercase
args.qualifier = args.qualifier and string.upper(args.qualifier)
 
if value then
ret = formatUserValue(value, args)
elseif args.wd ~= 'no' then
claims = getClaims(propertyId, args)
ret = (claims and #claims > 0) and formatStatements(claims, args, rawTable) or nil
end
 
return ret
end
 
-- Restituisce il valore di un qualifier di una proprietà di Wikidata,
function formatDatavalue( datavalue, options, formatting )
-- o nil se l'entity o la proprietà non esistono, o se per parametri di selezione non ci sono risultati.
local ret
function p._getQualifier(args)
local propertyId, qualifierId, value, claims, ret
 
-- parametri posizionali
--Use the customize handler if provided
propertyId = args[1] and string.upper(args[1])
if options['value-module'] or options['value-function'] then
if not propertyId then
if not options['value-module'] or not options['value-function'] then
error(i18n.errors['property-param-not-provided'], 2)
return formatError( 'unknown-value-module' )
end
qualifierId = args[2] and string.upper(args[2])
local formatter = require ('Module:' .. options['value-module'])
if formatter ==not nilqualifierId then
error(i18n.errors['qualifier-param-not-provided'], 2)
return formatError( 'value-module-not-found' )
end
value = args[3]
local fun = formatter[options['value-function']]
 
if fun == nil then
if value then
return formatError( 'value-function-not-found' )
ret = formatUserValue(value, args)
end
elseif args.wd ~= 'no' then
return fun( datavalue.value, options )
claims = getClaims(propertyId, args)
end
if claims and #claims > 0 then
local formattedQualifiers = {}
--Default formatters
for _, claim in ipairs(claims) do
if datavalue.type == 'wikibase-entityid' then
formattedQualifiers = formatQualifiers(claim, qualifierId, args, true, formattedQualifiers)
ret = formatEntityId( getEntityIdFromValue( datavalue.value ), options, formatting )
end
elseif datavalue.type == 'string' then
ret = #formattedQualifiers > 0 and
ret = datavalue.value
mw.text.listToText(formattedQualifiers, args.separator, args.conjunction) or nil
elseif datavalue.type == 'time' then
end
ret = formatTime( datavalue.value, options )
end
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
function formatEntityId( entityId, options, formatting )
if formatting == 'raw' then
return entityId
end
 
-- Restituisce l'indice dello statement con il valore richiesto, o nil se non trovato.
local label = mw.wikibase.label( entityId )
function p._indexOf(args)
local link = mw.wikibase.sitelink( entityId )
local ret, propertyId, value, claims
if link then
 
if label then
-- parametri posizionali
return '[[' .. link .. '|' .. label .. ']]'
propertyId = args[1] and string.upper(args[1])
else
if not propertyId then
return '[[' .. link .. ']]'
error(i18n.errors['property-param-not-provided'], 2)
end
end
else
value = args[2]
return label or ''
if not value then
end
error(i18n.errors['value-param-not-provided'], 2)
end
 
claims = getClaims(propertyId, args)
if claims and #claims > 0 then
args.formatting = 'raw'
for i, claim in ipairs(claims) do
if formatStatement(claim, args) == value then
ret = i
break
end
end
end
 
return ret
end
 
-- Restituisce il numero di statement di una proprietà di Wikidata.
function formatTime( value, options )
function p._N(args)
local year, month, day
local ret =propertyId, ''claims
year, month, day = value.time:match( '.+(%d%d%d%d%d)%-(%d%d)%-(%d%d).+' )
if value.precision == 9 then
ret = tonumber( year )
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 or value.precision == 11 then
ret = ret .. (value.time:sub(1, 1) == '-' and ' a.C.' or '')
end
 
-- parametri posizionali
return ret
propertyId = args[1] and string.upper(args[1])
if not propertyId then
error(i18n.errors['property-param-not-provided'], 2)
end
-- get claims
claims = getClaims(propertyId, args)
 
return claims and #claims or 0
end
 
-- Restituisce true se la propriertà specificata ha come valore
function formatGlobecoordinate( value, options )
-- almeno uno tra gli entityId passati come argomento.
local ret
function p._propertyHasEntity(propertyId, args)
if options.formatting == 'latitude' then
local statements = p._getProperty({ propertyId, from = args.from, formatting = 'raw' }, true)
ret = value.latitude
if statements then
elseif options.formatting == 'longitude' then
for _, statement in ipairs(statements) do
ret = value.longitude
for _, entityId in ipairs(args) do
else
if statement == entityId then
ret = value.latitude .. ', ' .. value.longitude
return true
end
end
return ret
end
end
 
-- Se non è stato trovato alcun valore, controlla se questo sia ereditato
-- tramite la proprietà "sottoclasse di" (P279) scavando in profondità
-- fino all'esaurirsi del numero specificato in args.recursion.
--[[ TODO: Valutare se sia opportuna una ricerca ricorsiva potenzialmente infinita.
Per farlo si può aggiungere un parametro (opzionale) maxDepth
che svolga l'attuale funzione di recursion e cambiare quest'ultimo
in un parametro booleano.
]]
args.recursion = tonumber(args.recursion) or 0
if args.recursion > 0 then
local recursion = args.recursion
if type(args.loadedEntities) ~= 'table' then
args.loadedEntities = setmetatable({}, {
__newindex = function(t, k, v)
rawset(t, k, v)
rawset(t, #t+1, k)
end })
args.loadedEntities[args.from or mw.wikibase.getEntityIdForCurrentPage()] = true
end
for _, statement in ipairs(statements) do
if not args.loadedEntities[statement] then
args.loadedEntities[statement] = true
args.recursion = args.recursion - 1
args.from = statement
if p._propertyHasEntity('P279', args) then
return true, args.loadedEntities
end
args.recursion = recursion
end
end
end
end
 
return false, args.loadedEntities
end
 
-- Restituisce true se la proprietà P31 (instance of) ha come valore almeno uno tra gli entityId specificati
function formatFromPattern( str, options )
function p._instanceOf(args)
-- la parentesi () extra serve per non ritornare anche il gsub.count
return ( mwp.ustring.gsub_propertyHasEntity( options.pattern, '$1P31', str ) args)
end
 
-- Restituisce true se la proprietà P279 (subclass of) ha come valore almeno uno tra gli entityId specificati
-- Ritorna gli argomenti passati al modulo, scartando quelli valorizzati a stringhe vuote
local function getArgsp._subclassOf( frame args)
return p._propertyHasEntity('P279', args)
local args = {}
for k, v in pairs( frame.args ) do
if v ~= '' then
args[k] = v
end
end
return args
end
 
-- Restituisce l'etichetta di un item o di una proprietà Wikidata.
local p = {}
function p._getLabel(args)
local entityId = args[1] and string.upper(args[1])
local ret
if args[2] then
ret = mw.wikibase.getLabelByLang(entityId, args[2])
else
ret = mw.wikibase.getLabel(entityId)
end
return ret
end
 
-- Restituisce la descrizione di un item o di una proprietà Wikidata.
function p.formatStatements( frame )
function p._getDescription(args)
local args, ret, claims
local entityId = args[1] and string.upper(args[1])
local ret = mw.wikibase.getDescription(entityId)
return ret
end
 
-- Restituisce il titolo della pagina collegata a un dato item Wikidata.
args = getArgs( frame )
function p._getLink(args)
-- parametri posizionali
local entityId = args[1] and string.upper(args[1])
if not entityId then
error(i18n.errors['entityid-param-not-provided'], 2)
end
return entityId:sub(1, 1) == 'Q' and formatEntityId(entityId) or nil
end
 
-- Restituisce il datatype di una proprietà Wikidata.
-- if parameter value is already set, use it
function p._getDatatype(args)
if args.value then
local propertyId, entity
return 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
 
-- parametri posizionali
return formatStatements( claims, args )
propertyId = args[1] and string.upper(args[1])
if not propertyId then
error(i18n.errors['property-param-not-provided'], 2)
end
 
entity = mw.wikibase.getEntity(propertyId)
if not entity then
error(i18n.errors['entity-not-found'], 2)
end
 
if not i18n.datatypes[entity.datatype] then
error(i18n.errors['unknown-datavalue-type'], 2)
end
 
return i18n.datatypes[entity.datatype]
end
 
-- Restituisce l'ID dell'item Wikidata collegato alla pagina corrente o a una pagina specificata
function p.getQualifier( frame )
-- (nota: se il parametro followRedirects è valorizzato con "no", segue i redirect fermandosi al primo redirect collegato a un elemento)
local args, ret, claims, qualifierName, formattedQualifier, formattedQualifiers
function p._getId(args)
local ret
local followRedirects = not args.followRedirects or args.followRedirects ~= "no"
if args[1] then
local title = mw.title.new(args[1])
while title do
local id = mw.wikibase.getEntityIdForTitle(title.prefixedText)
if id then
ret = id
break
else
title = followRedirects and title.redirectTarget or nil
end
end
else
ret = mw.wikibase.getEntityIdForCurrentPage()
end
return ret
end
 
-------------------------------------------------------------------------------
args = getArgs( frame )
-- Funzioni esportate per i template
-------------------------------------------------------------------------------
 
-- Funzione per il template {{Wikidata}}
-- if parameter value is already set, use it
function p.getProperty(frame)
if args.value then
return select(2, xpcall(function()
return args.pattern and formatFromPattern( args.value, args ) or args.value
return p._getProperty(getArgs(frame, { parentOnly = true }))
end
end, errhandler))
end
 
-- Funzione per il template {{WikidataQ}}
-- get qualifier name
function p.getQualifier(frame)
if not args.qualifier then
return select(2, xpcall(function()
return formatError( 'qualifier-param-not-provided' )
return p._getQualifier(getArgs(frame, { parentOnly = true }))
end
end, errhandler))
qualifierName = string.lower( args.qualifier )
end
-- get claims
ret, claims = pcall( getClaims, args )
if not ret then
return claims:match( '.+%d:%s(.+)$' )
end
 
-- Funzione per il template {{WikidataIdx}}
-- get qualifiers and format them
function p.indexOf(frame)
formattedQualifiers = {}
return select(2, xpcall(function()
for i, claim in pairs( claims ) do
return p._indexOf(getArgs(frame, { parentOnly = true }))
if claim.qualifiers and claim.qualifiers[qualifierName] then
end, errhandler))
for j, qualifier in pairs( claim.qualifiers[qualifierName] ) do
end
formattedQualifier = formatSnak( qualifier, args )
if args.pattern then
formattedQualifier = formatFromPattern( formattedQualifier, args )
end
table.insert( formattedQualifiers, formattedQualifier )
end
end
end
 
-- Funzione per il template {{WikidataN}}
return mw.text.listToText( formattedQualifiers, args.separator, args.conjunction )
function p.N(frame)
return select(2, xpcall(function()
return p._N(getArgs(frame, { parentOnly = true }))
end, errhandler))
end
function p.N( frame )
local entity, property, count
 
-- Funzione per il template {{WikidataLabel}}
property = string.lower( frame.args[1] )
function p.getLabel(frame)
entity = mw.wikibase.getEntity()
return select(2, xpcall(function()
if entity and entity.claims and entity.claims[property] and
return p._getLabel(getArgs(frame, { parentOnly = true }))
type( entity.claims[property] ) == 'table' and
end, errhandler))
next( entity.claims[property] ) then
end
-- "+ 1" perché entity.claims[property] è una sequence ma inizia da 0
count = #entity.claims[property] + 1
end
 
-- Funzione per il template {{WikidataDescription}}
return count or 0
function p.getDescription(frame)
return select(2, xpcall(function()
return p._getDescription(getArgs(frame, { parentOnly = true }))
end, errhandler))
end
 
-- Funzione per il template {{WikidataLink}}
function p.getLink(frame)
return select(2, xpcall(function()
return p._getLink(getArgs(frame, { parentOnly = true }))
end, errhandler))
end
 
-- Funzione per il template {{WikidataIstanza}}
function p.instanceOf(frame)
return select(2, xpcall(function()
return p._instanceOf(getArgs(frame, { parentOnly = true })) and 1 or ''
end, errhandler))
end
 
-- Funzione per il template {{WikidataTipo}}
function p.getDatatype(frame)
return select(2, xpcall(function()
return p._getDatatype(getArgs(frame, { parentOnly = true }))
end, errhandler))
end
 
-- Funzione per il template {{WikidataId}}
function p.getId(frame)
return select(2, xpcall(function()
return p._getId(getArgs(frame, { parentOnly = true }))
end, errhandler))
end
 
-- Funzione per il template {{WikidataValido}}
function p.checkProperty(frame)
return select(2, xpcall(function()
return p._N(getArgs(frame, { parentOnly = true })) > 0 and 1 or ''
end, errhandler))
end
 
-- Funzione per il template {{WikidataClasse}}
function p.propertyHasEntity(frame)
local args = getArgs(frame)
local propertyId = args[1]
return select(2, xpcall(function()
return p._propertyHasEntity(propertyId, args) and 1 or ''
end, errhandler))
end
 
return p