Modulo:Wikidata
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.
La documentazione per questo modulo può essere creata in Modulo:Wikidata/man
--[[ * Modulo per implementare le funzionalità dei template: * {{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: * http://test2.wikipedia.org/w/index.php?title=Module:Wikidata&oldid=52322 ]] -- ============================================================================= -- 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('Module:No globals') local getArgs = require('Module:Arguments').getArgs local mConvert = require('Module:Conversione') local mLanguages = require('Module:Linguaggi') -- Categoria per le pagine con errori local errorCategory = '[[Categoria:Voci con errori del modulo Wikidata]]' -- Messaggi 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", ['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''", 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 }) .. ' ' .. 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).+') year, month, day = tonumber(year), tonumber(month), tonumber(day) if precision == 9 then ret = year elseif precision == 10 then 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 ret = value.precision elseif args.time == 'calendarmodel' then ret = value.calendarmodel elseif args.time == 'year' and value.precision >= 9 then ret = formatTimeWithPrecision(value.time, 9) elseif args.time == 'month' and value.precision >= 10 then ret = formatTimeWithPrecision(value.time, 10) elseif args.time == 'day' and value.precision >= 11 then ret = formatTimeWithPrecision(value.time, 11) 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 }) or '' else ret = args.formatting == 'raw' and entityId or 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) -- eventuale showqualifiers if args.showqualifiers and statement.qualifiers then ret = appendQualifiers(statement, ret, args) end return ret end local function formatStatements(claims, args, rawTable) local formattedStatements = {} for _, claim in ipairs(claims) do local formattedStatement = formatStatement(claim, args) if formattedStatement ~= '' then -- eventuale pattern if args.pattern then formattedStatement = formatFromPattern(formattedStatement, args) 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 ------------------------------------------------------------------------------- -- Lettura e selezione statement ------------------------------------------------------------------------------- -- Restituisce true se lo statement contiene il qualifier richiesto con un dato valore (o uno tra più valori separati da virgola) 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' args.rank = args.rank or 'best' if args.rank == 'best' then claims = mw.wikibase.getBestStatements(entityId, propertyId) else -- statements filtrati per rank claims = mw.wikibase.getAllStatements(entityId, propertyId) claims = filterRankValue(claims, args.rank) end -- statements filtrati per snaktype, default "value" args.snaktype = args.snaktype or 'value' if args.snaktype and args.snaktype ~= 'all' then filteredClaims = {} for _, claim in ipairs(claims) do if claim.mainsnak.snaktype == args.snaktype then table.insert(filteredClaims, claim) end end claims = filteredClaims end -- statements filtrati per qualifier if args.qualifier then filteredClaims = {} for _, claim in ipairs(claims) do if claim.qualifiers and claim.qualifiers[args.qualifier] then if args.qualifiervalue then 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 if args.noqualifier then filteredClaims = {} for _, claim in ipairs(claims) do if not (claim.qualifiers and claim.qualifiers[args.noqualifier]) then table.insert(filteredClaims, claim) end end claims = filteredClaims end -- statements filtrati per non avere un certo valore a un certo qualifier opzionale if args.qualifieroptnovalue and args.qualifiervalue then filteredClaims = {} for _, claim in ipairs(claims) do if claim.qualifiers and claim.qualifiers[args.qualifieroptnovalue] then if not hasQualifierValue(claim, args.qualifieroptnovalue, args.qualifiervalue) then table.insert(filteredClaims, claim) end else table.insert(filteredClaims, claim) end end claims = filteredClaims end -- con args.qualifiertype=latest restituisce solo il più recente if args.qualifier and args.qualifiertype == 'latest' then local latest, latestTime for _, claim in ipairs(claims) do if claim.qualifiers and claim.qualifiers[args.qualifier] then for _, qualifier in ipairs(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 restituisce 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 ------------------------------------------------------------------------------- -- Funzioni esportate per altri moduli ------------------------------------------------------------------------------- function p._getClaims(propertyId, args) return getClaims(propertyId, args or {}) end function p._formatStatement(statement, args) return formatStatement(statement, args or {}) end function p._formatQualifiers(claim, qualifierId, args, rawTable, retTable) return formatQualifiers(claim, qualifierId, args or {}, rawTable, retTable) end -- Restituisce 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 propertyId, value, claims, ret -- parametri posizionali propertyId = args[1] and string.upper(args[1]) if not propertyId then error(i18n.errors['property-param-not-provided'], 2) 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, -- 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 propertyId, qualifierId, value, claims, ret -- parametri posizionali propertyId = args[1] and string.upper(args[1]) if not propertyId then error(i18n.errors['property-param-not-provided'], 2) end qualifierId = args[2] and string.upper(args[2]) if not qualifierId then error(i18n.errors['qualifier-param-not-provided'], 2) end value = args[3] if value then ret = formatUserValue(value, args) elseif args.wd ~= 'no' then claims = getClaims(propertyId, args) if claims and #claims > 0 then local formattedQualifiers = {} for _, claim in ipairs(claims) do formattedQualifiers = formatQualifiers(claim, qualifierId, args, true, formattedQualifiers) end ret = #formattedQualifiers > 0 and mw.text.listToText(formattedQualifiers, args.separator, args.conjunction) or nil end end return ret end -- Restituisce l'indice dello statement con il valore richiesto, o nil se non trovato. function p._indexOf(args) local ret, propertyId, value, claims -- parametri posizionali propertyId = args[1] and string.upper(args[1]) if not propertyId 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 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 p._N(args) local propertyId, claims -- parametri posizionali 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 -- almeno uno tra gli entityId passati come argomento. function p._propertyHasEntity(propertyId, args) local statements = p._getProperty({ propertyId, 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 -- 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 p._instanceOf(args) return p._propertyHasEntity('P31', args) end -- Restituisce true se la proprietà P279 (subclass of) ha come valore almeno uno tra gli entityId specificati function p._subclassOf(args) return p._propertyHasEntity('P279', args) end -- Restituisce l'etichetta di un item o di una proprietà Wikidata. 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._getDescription(args) 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. 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. function p._getDatatype(args) local propertyId, entity -- parametri posizionali 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 -- (nota: segue i redirect fermandosi al primo redirect collegato a un elemento) function p._getId(args) local ret 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 = title.redirectTarget end end else ret = mw.wikibase.getEntityIdForCurrentPage() end return ret end ------------------------------------------------------------------------------- -- Funzioni esportate per i template ------------------------------------------------------------------------------- -- Funzione per il template {{Wikidata}} function p.getProperty(frame) return select(2, xpcall(function() return p._getProperty(getArgs(frame, { parentOnly = true })) end, errhandler)) end -- Funzione per il template {{WikidataQ}} function p.getQualifier(frame) return select(2, xpcall(function() return p._getQualifier(getArgs(frame, { parentOnly = true })) end, errhandler)) end -- Funzione per il template {{WikidataIdx}} function p.indexOf(frame) return select(2, xpcall(function() return p._indexOf(getArgs(frame, { parentOnly = true })) end, errhandler)) end -- Funzione per il template {{WikidataN}} function p.N(frame) return select(2, xpcall(function() return p._N(getArgs(frame, { parentOnly = true })) end, errhandler)) end -- Funzione per il template {{WikidataLabel}} function p.getLabel(frame) return select(2, xpcall(function() return p._getLabel(getArgs(frame, { parentOnly = true })) end, errhandler)) end -- Funzione per il template {{WikidataDescription}} 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 return p