Modulo:Wikidata
La documentazione per questo modulo può essere creata in Modulo:Wikidata/man
Errore script: Errore Lua: errore interno - l'interprete è uscito con stato 1.
--[[ * 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:Lingue') -- 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 -- Funzione per il template {{WikidataClasse}} function p.propertyHasEntity(frame) local args = getArgs(frame, { parentOnly = true }) local propertyId = args[1] args.recursion = tonumber(args.prof) or 8 return select(2, xpcall(function() return p._propertyHasEntity(propertyId, args) and 1 or '' end, errhandler)) end return p