Mòdul:Wikidata

La documentazione per questo modulo può essere creata in Mòdul:Wikidata/man

--[[* Modulo per implementare le funzionalità dei template:* {{Wikidata}}, {{WikidataQ}}, {{WikidataIdx}}, {{WikidataN}},* {{WikidataLabel}}, {{WikidataLink}}, {{WikidataTipo}} e {{WikidataId}}.* 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').getArgslocal mConvert = require('Module:Conversione')local mLanguages = require('Module:Linguaggi')-- Categoria per le pagine con errorilocal errorCategory = '[[Categoria:Voci con errori del modulo Wikidata]]'local p = {}-- Messaggi di errorelocal 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",["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"},["somevalue"] = "''valore sconosciuto''",["novalue"] = "''nessun valore''"}---------------------------------------------------------------------------------                             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)endlocal 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 ''endlocal 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] thenlocal dest = tostring(uri)return string.format('<div style="word-break: break-all;">[%s %s]</div>', dest, dest:gsub(uri.protocol .. '://', ''))elsereturn urlendendlocal function formatEntityId(entityId)local label = mw.wikibase.label(entityId)local link = mw.wikibase.sitelink(entityId)if link thenif label and label ~= link thenreturn '[[' .. link .. '|' .. label .. ']]'elsereturn '[[' .. link .. ']]'endelsereturn label or ''endendlocal function formatMonolingualtext(value, args)local ret = ''if not args.includelang or args.includelang:match('%f[a-z]' .. value.language .. '%f[^a-z]') thenif not args.excludelang or not args.excludelang:match('%f[a-z]' .. value.language .. '%f[^a-z]') thenret = value.textif args.showlang thenret = mLanguages.lingue( { value.language } ) .. '&nbsp;' .. retendendendreturn retendlocal function formatTimeWithPrecision(time, precision)local months = {'genar', 'febrar', 'marz', 'april', 'magg', 'giugn','luj', 'agost', 'settember', 'ottober', 'november', 'dicember'}local ret, year, month, day year, month, day = time:match('(%d+)%-(%d%d)%-(%d%d).+')year, month, day = tonumber(year), tonumber(month), tonumber(day)if precision == 9 thenret = yearelseif precision == 10 thenret = months[month] .. ' ' .. yearelseif precision == 11 thenret = day .. ' ' .. months[month] .. ' ' .. yearret = ret:gsub('^1%s', '1º ')endif precision >= 9 and precision <= 11 thenret = ret .. (time:sub(1, 1) == '-' and ' a.C.' or '')endreturn retendlocal function formatTime(value, args)local ret if args.time == 'precision' thenret = value.precisionelseif args.time == 'calendarmodel' thenret = value.calendarmodelelseif args.time == 'year' and value.precision >= 9 thenret = formatTimeWithPrecision(value.time, 9)elseif args.time == 'month' and value.precision >= 10 thenret = formatTimeWithPrecision(value.time, 10)elseif args.time == 'day' and value.precision >= 11 thenret = formatTimeWithPrecision(value.time, 11)elseif not args.time thenret = formatTimeWithPrecision(value.time, value.precision)endreturn ret or ''endlocal function formatGlobecoordinate(value, args)local retif args.coord == 'latitude' thenret = value.latitudeelseif args.coord == 'longitude' thenret = value.longitudeelseif args.coord == 'globe' thenret = value.globeelseret = value.latitude .. ', ' .. value.longitudeendreturn retendlocal function formatFromPattern(str, args)local pattern = args.patternpattern = mw.ustring.gsub(pattern, '\\{', '{')pattern = mw.ustring.gsub(pattern, '\\}', '}')return mw.getCurrentFrame():preprocess(mw.message.newRawMessage(pattern, str):plain())endlocal function formatUserValue(value, args)if args.extlink thenvalue = formatExtLink(value)endreturn args.pattern and formatFromPattern(value, args) or valueendlocal function getEntityIdFromValue(value)local prefix = ''if value['entity-type'] == 'item' thenprefix = 'Q'elseif value['entity-type'] == 'property' thenprefix = 'P'elseerror(i18n.errors['unknown-entity-type'])endreturn prefix .. value['numeric-id']endlocal function formatUnitSymbol(entityId, args)local ret = p._getProperty( { 'P558', n = 1, from = entityId } )local space = ret == '°' and '' or ' 'if ret and args.showunitlink thenlocal link = mw.wikibase.sitelink(entityId)if link thenret = string.format('[[%s|%s]]', link, ret)endendreturn ret and (space .. ret) or ''end-- http://lua-users.org/wiki/SimpleRoundlocal function round(num, idp)local mult = 10 ^ (idp or 0)return math.floor(num * mult + 0.5) / multendlocal function formatQuantity(value, args)local ret = tonumber(value.amount)if (args.unit or args.showunit) and value.unit ~= '1' thenlocal unitId = mw.ustring.match(value.unit, 'Q%d+')if args.unit thenlocal 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 P558ret = args.rounding and round(ret, args.rounding) or retif args.formatnum thenret = mw.language.getContentLanguage():formatNum(ret)endret = ret .. formatUnitSymbol(unitId, args)endelseif args.formatnum thenret = args.rounding and round(ret, args.rounding) or retret = mw.language.getContentLanguage():formatNum(ret)elseif args.formatduration and value.unit ~= '1' thenlocal 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' } )endreturn retendlocal function formatDatavalue(datavalue, snakdatatype, args)local retif datavalue.type == 'wikibase-entityid' thenlocal entityId = getEntityIdFromValue(datavalue.value)if args.showprop thenret = p._getProperty( { args.showprop, n = 1, from = entityId } ) or ''elseret = args.formatting == 'raw' and entityId or formatEntityId(entityId)endelseif datavalue.type == 'string' thenret = datavalue.valueif args.extlink and snakdatatype == 'url' thenret = formatExtLink(ret)elseif args.urlencode thenret = mw.uri.encode(ret)endelseif datavalue.type == 'monolingualtext' thenret = formatMonolingualtext(datavalue.value, args)elseif datavalue.type == 'time' thenif args.formatting == 'raw' thenret = datavalue.value.timeelseret = formatTime(datavalue.value, args)endelseif datavalue.type == 'globecoordinate' thenret = formatGlobecoordinate(datavalue.value, args)elseif datavalue.type == 'quantity' thenret = formatQuantity(datavalue.value, args)elseerror(i18n.errors['unknown-datavalue-type'])endreturn retendlocal function formatSnak(snak, args)if snak.snaktype == 'somevalue' thenreturn i18n['somevalue']elseif snak.snaktype == 'novalue' thenreturn i18n['novalue']elseif snak.snaktype == 'value' thenreturn formatDatavalue(snak.datavalue, snak.datatype, args)elseerror(i18n.errors['unknown-snak-type'])endend-- È al plurale perché anche i qualifier possono avere più di un valore-- (si ottiene inserendo due volte lo stesso qualifier)local function formatQualifiers(claim, qualifier, args, rawTable, retTable)local formattedQualifiers = retTable or {}if claim.qualifiers and claim.qualifiers[qualifier] thenlocal qualifiers = claim.qualifiers[qualifier]-- con args.nq seleziona solo l'n-esimo qualifierif args.nq thenlocal n = tonumber(args.nq)qualifiers = (n and n <= #qualifiers) and { qualifiers[n] } or {}endfor _, q in pairs(qualifiers) dolocal formattedQualifier = formatSnak(q, args)if formattedQualifier ~= '' thenif args.pattern thenformattedQualifier = formatFromPattern(formattedQualifier, args)endtable.insert(formattedQualifiers, formattedQualifier)endendendif rawTable thenreturn formattedQualifiersendreturn #formattedQualifiers > 0 and   mw.text.listToText(formattedQualifiers, args.separator, args.conjunction) or nilendlocal function appendQualifiers(statement, text, args)local formattedQualifiers = {}local qualifiers = mw.text.split(args.showqualifiers, ',')for _, qualifier in ipairs(qualifiers) doif statement.qualifiers[qualifier] thenlocal formattedQualifier = formatQualifiers(statement, qualifier, args)table.insert(formattedQualifiers, formattedQualifier)endendif #formattedQualifiers > 0 thentext = string.format('%s (%s)', text, mw.text.listToText(formattedQualifiers, ', ', ', '))endreturn textendlocal function formatStatement(statement, args)if not statement.type or statement.type ~= 'statement' thenerror(i18n.errors['unknown-claim-type'])end local ret = formatSnak(statement.mainsnak, args)-- eventuale showqualifiersif args.showqualifiers and statement.qualifiers thenret = appendQualifiers(statement, ret, args)endreturn retendlocal function formatStatements(claims, args, rawTable)local formattedStatements = {}for i, claim in pairs(claims) dolocal formattedStatement = formatStatement(claim, args)if formattedStatement ~= '' then-- eventuale patternif args.pattern thenformattedStatement = formatFromPattern(formattedStatement, args)endtable.insert(formattedStatements, formattedStatement)endendif rawTable thenreturn formattedStatementsendreturn ((args.list or args.orderedlist) and #formattedStatements > 1) and   formatList(formattedStatements, args.orderedlist ~= nil) or    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 valorelocal function hasQualifierValue(statement, qualifierId, qualifierValue)local ret = falsefor i, qualifier in pairs(statement.qualifiers[qualifierId]) dolocal isItem = qualifier.snaktype == 'value' and   qualifier.datavalue.type == 'wikibase-entityid'-- per le proprietà di tipo item il confronto è eseguito sull'idif formatSnak(qualifier, isItem and { formatting = 'raw' } or {} ) == qualifierValue thenret = truebreakendendreturn retend-- Ritorna i claim con il rank richiestolocal function filterRankValue(claims, rank)local ret = {}for i, claim in pairs(claims) doif claim.rank == rank thentable.insert(ret, claim)endendreturn retend-- 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 entityentity = mw.wikibase.getEntity(args.from)if not entity thenreturn nilendif property and entity.claims and entity.claims[property] and   #entity.claims[property] > 0 then   claims = entity.claims[property]elsereturn nilend-- statements filtrati per rank (default 'best')args.rank = args.rank or 'best'if args.rank == 'best' thenfilteredClaims = filterRankValue(claims, 'preferred')if #filteredClaims == 0 thenfilteredClaims = filterRankValue(claims, 'normal')endelsefilteredClaims = filterRankValue(claims, args.rank)endclaims = filteredClaims-- statements filtrati per qualifierif args.qualifier thenfilteredClaims = {}for i, claim in pairs(claims) doif claim.qualifiers and claim.qualifiers[args.qualifier] thenif args.qualifiervalue thenif hasQualifierValue(claim, args.qualifier, args.qualifiervalue) thentable.insert(filteredClaims, claim)endelsetable.insert(filteredClaims, claim)endendendclaims = filteredClaimsend-- statements filtrati per essere senza un qualifierif args.noqualifier thenfilteredClaims = {}for i, claim in pairs(claims) doif not (claim.qualifiers and claim.qualifiers[args.noqualifier]) thentable.insert(filteredClaims, claim)endendclaims = filteredClaimsend-- statements filtrati per non avere un certo valore a un certo qualifier opzionaleif args.qualifieroptnovalue and args.qualifiervalue thenfilteredClaims = {}for i, claim in pairs(claims) doif claim.qualifiers and claim.qualifiers[args.qualifieroptnovalue] thenif not hasQualifierValue(claim, args.qualifieroptnovalue, args.qualifiervalue) thentable.insert(filteredClaims, claim)endelsetable.insert(filteredClaims, claim)endendclaims = filteredClaimsend-- con args.qualifiertype=latest ritorna solo il più recenteif args.qualifier and args.qualifiertype == 'latest' thenlocal latest, latestTimefor i, claim in pairs(claims) doif claim.qualifiers and claim.qualifiers[args.qualifier] thenfor j, qualifier in pairs(claim.qualifiers[args.qualifier]) doif qualifier.datavalue.type == 'time' thenif not latestTime or qualifier.datavalue.value.time > latestTime thenlatest = claimlatestTime = qualifier.datavalue.value.timeendendendendendclaims = latest and {latest} or {}end-- con args.n ritorna solo l'n-esimo elementoif args.n thenlocal n = tonumber(args.n)claims = (n and n <= #claims) and { claims[n] } or {}endreturn claimsend---------------------------------------------------------------------------------                               API-------------------------------------------------------------------------------function p._getClaims(property, args)return getClaims(property, args or {})endfunction p._formatStatement(statement, args)return formatStatement(statement, args or {})endfunction p._formatQualifiers(claim, qualifier, args, rawTable, retTable)return formatQualifiers(claim, qualifier, args or {}, rawTable, retTable)end-- 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, ret-- parametri posizionaliproperty = args[1] and string.upper(args[1]) or nilif not property thenerror(i18n.errors['property-param-not-provided'], 2)endvalue = args[2]-- fix uppercaseargs.qualifier = args.qualifier and string.upper(args.qualifier) or nilif value thenret = formatUserValue(value, args)elseif args.wd ~= 'no' thenclaims = getClaims(property, args)ret = (claims and #claims > 0) and formatStatements(claims, args, rawTable) or nilendreturn retend-- 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, ret-- parametri posizionaliproperty = args[1] and string.upper(args[1]) or nilif not property thenerror(i18n.errors['property-param-not-provided'], 2)endqualifier = args[2] and string.upper(args[2]) or nilif not qualifier thenerror(i18n.errors['qualifier-param-not-provided'], 2)endvalue = args[3]if value thenret = formatUserValue(value, args)elseif args.wd ~= 'no' thenclaims = getClaims(property, args)if claims and #claims > 0 thenlocal formattedQualifiers = {}for _, claim in pairs(claims) doformattedQualifiers = formatQualifiers(claim, qualifier, args, true, formattedQualifiers)endret = #formattedQualifiers > 0 and  mw.text.listToText(formattedQualifiers, args.separator, args.conjunction) or nilendendreturn retend-- Ritorna l'indice dello statement con il valore richiesto, o nil se non trovato.function p._indexOf(args)local ret, property, value, claims-- parametri posizionaliproperty = args[1] and string.upper(args[1]) or nilif not property thenerror(i18n.errors['property-param-not-provided'], 2)endvalue = args[2]if not value thenerror(i18n.errors['value-param-not-provided'], 2)endclaims = getClaims(property, args)if claims and #claims > 0 thenargs.formatting = 'raw'for i, claim in pairs(claims) doif formatStatement(claim, args) == value thenret = ibreakendendendreturn retend-- Ritorna il numero di statement di una proprietà di Wikidata.function p._N(args) local property, claims-- parametri posizionaliproperty = args[1] and string.upper(args[1]) or nilif not property thenerror(i18n.errors['property-param-not-provided'], 2)end-- get claimsclaims = getClaims(property, args)return claims and #claims or 0end--[[* La proprietà specificata ha come valore almeno uno tra gli entityId specificati?** @param string property Wikidata Property ID* @param table args values (mixed with .from)* @return boolean]]function p._propertyHasEntity(property, args)local statements = p._getProperty( {property, from = args.from, formatting = 'raw' }, true)if statements thenfor _, statement in ipairs(statements) dofor _, entityId in ipairs(args) doif statement == entityId thenreturn trueendendendendreturn falseend-- Ritorna true se la proprietà P31 (instance of) ha come valore almeno uno tra gli entityId specificatifunction p._instanceOf(args)return p._propertyHasEntity('P31', args)end-- Ritorna true se la proprietà P279 (subclass of) ha come valore almeno uno tra gli entityId specificatifunction p._subclassOf(args)return p._propertyHasEntity('P279', args)end-- Ritorna l'etichetta di un item o di una proprietà Wikidata.function p._getLabel(args) -- parametri posizionalilocal entityId = args[1] and string.upper(args[1]) or nillocal langCode = args[2]local entity = mw.wikibase.getEntity(entityId)if not entity thenerror(i18n.errors['entity-not-found'], 2)endreturn entity:getLabel(langCode)end-- Ritorna il titolo della pagina collegata a un dato item Wikidata.function p._getLink(args) -- parametri posizionalilocal entityId = args[1] and string.upper(args[1]) or nilif not entityId thenerror(i18n.errors['entityid-param-not-provided'], 2)endreturn entityId:sub(1, 1) == 'Q' and formatEntityId(entityId) or nilend-- Ritorna il datatype di una proprietà Wikidata.function p._getDatatype(args) local ret, property, entity, datatype-- parametri posizionaliproperty = args[1] and string.upper(args[1]) or nilif not property thenerror(i18n.errors['property-param-not-provided'], 2)endentity = mw.wikibase.getEntity(property)if not entity thenerror(i18n.errors['entity-not-found'], 2)enddatatype = entity.datatypeif datatype == 'commonsMedia' thenret = 'file multimediale su Commons'elseif datatype == 'globe-coordinate' thenret = 'coordinate geografiche'elseif datatype == 'monolingualtext' thenret = 'testo monolingua'elseif datatype == 'quantity' thenret = 'quantità'elseif datatype == 'string' thenret = 'stringa'elseif datatype == 'time' thenret = 'data e ora'elseif datatype == 'url' thenret = 'URL'elseif datatype == 'external-id' thenret = 'identificatore esterno'elseif datatype == 'wikibase-item' thenret = 'elemento'elseif datatype == 'wikibase-property' thenret = 'proprietà'elseif datatype == 'math' thenret = 'espressione matematica'elseerror(i18n.errors['unknown-datavalue-type'], 2)endreturn retend-- Ritorna l'ID dell'item Wikidata collegato alla pagina corrente.function p._getId()return mw.wikibase.getEntityIdForCurrentPage()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 {{WikidataLabel}}function p.getLabel(frame)return select(2, xpcall(function()return p._getLabel(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 ''end, errhandler))end-- Entry-point per {{WikidataTipo}}function p.getDatatype(frame)return select(2, xpcall(function()return p._getDatatype(getArgs(frame, {parentOnly = true}))end, errhandler))end-- Entry-point per {{WikidataId}}function p.getId(frame)return select(2, xpcall(function()return p._getId()end, errhandler))endreturn p