Modulo:Wikidata

Versione del 4 mar 2014 alle 21:32 di Rotpunkt (discussione | contributi) (aggiornato al nuovo comportamento della getEntityObject, non-legacy style, e modifica uppercase in getArgs)
Info Istruzioni per l'uso
Questo è un modulo scritto in Lua. Le istruzioni che seguono sono contenute nella sottopagina Modulo:Wikidata/man (modifica · cronologia)
Sandbox: Modulo:Wikidata/sandbox (modifica · cronologia) · Sottopagine: lista · Test: Modulo:Wikidata/test (modifica · cronologia · esegui)

Il modulo Wikidata implementa le funzionalità dei template {{Wikidata}}, {{WikidataQ}}, {{WikidataIdx}}, {{WikidataN}}, {{WikidataLabel}}, {{WikidataDescription}}, {{WikidataLink}}, {{WikidataId}}, {{WikidataTipo}} e {{WikidataIstanza}}.

Utilizzo da un altro modulo

Il modulo può essere usato anche da un altro modulo tramite "require". È sufficiente inserire all'inizio del modulo:

local mWikidata = require('Modulo:Wikidata')

Le funzioni hanno gli stessi nomi di quelle utilizzate dai template ma con un underscore iniziale e ricevono come argomento, invece del frame, una table con cui specificare gli argomenti.

  • _getProperty(args, rawTable): per l'utilizzo della tabella args vedere il manuale del template {{Wikidata}}. Il parametro aggiuntivo rawTable, se valorizzato a true, fa sì che le dichiarazioni non vengano unite in un'unica stringa come per il template (separate dalla virgola e con la "e" prima dell'ultima), ma venga invece restituita una sequence, contenente le stringhe separate per ciascuna dichiarazione.
  • _getQualifier(args): vedere {{WikidataQ}}
  • _indexOf(args): vedere {{WikidataIdx}}
  • _N(args): vedere {{WikidataN}}
  • _getLabel(args): vedere {{WikidataLabel}}
  • _getDescription(args): vedere {{WikidataDescription}}
  • _getLink(args): vedere {{WikidataLink}}
  • _getDatatype(args): vedere {{WikidataTipo}}
  • _getId(args): vedere {{WikidataId}}
  • _instanceOf(args): vedere {{WikidataIstanza}}
  • _subClassOf(args): analogamente, vedere {{WikidataIstanza}}

A queste si aggiungono tre funzioni specifiche del modulo, che permettono di iterare sulle dichiarazioni di una proprietà:

  • _getClaims(property, args): restituisce una sequence con le dichiarazioni di una proprietà, come _getProperty, ma senza formattarle. Per gli argomenti utilizzabili nella tabella args vedere i parametri di selezione nel manuale del template {{Wikidata}}. Può restituire nil nel caso in cui la pagina non sia collegata a Wikidata.
  • _formatStatement(statement, args): formatta una dichiarazione (parametro statement) ottenuta tramite getClaims. Per l'utilizzo della tabella args vedere i parametri di formattazione nel manuale del template {{Wikidata}}.
  • _formatQualifiers(claim, qualifier, args, rawTable, retTable): formatta un qualificatore (parametro qualifier) di una dichiarazione (parametro claim) ottenuta tramite getClaims. Per l'utilizzo della tabella args vedere i parametri di formattazione nel manuale del template {{Wikidata}}. Il parametro rawTable, se valorizzato a true, fa sì che eventuali valori multipli di un qualificatore vengano restituiti come sequence invece che come unica stringa (con retTable è possibile specificare una sequence già esistente).
Esempio
local mWikidata = require('Modulo:Wikidata')
local p = {}

function p.main(frame)
	local capitale, data, stati, italia, onu

	-- utilizzo della funzione getProperty
	capitale = mWikidata._getProperty( { 'P36', from = 'Q183' } )
	-- utilizzo della funzione getQualifier
	data = mWikidata._getQualifier( { 'P36', 'P580', from = 'Q183' } )
	-- utilizzo della funzione N
	stati = mWikidata._N( { 'P47', from = 'Q183' } )
	-- utilizzo della funzione indexOf
	italia = mWikidata._indexOf( { 'P47', 'Q38', from = 'Q183' } )
	-- utilizzo della funzione instanceOf
	onu = mWikidata._instanceOf( { 'Q160016', from = 'Q183' } )

	return string.format('La capitale della Germania è %s, dal %s. ' .. 
						 'Confina con %s Stati, con l\'Italia: %s. ' ..
						 'Membro delle Nazioni Unite: %s.',
						 capitale, data, stati, italia and 'si' or 'no', onu and 'sì' or 'no') 
end

return p
Esempio con getClaims, formatStatement e formatQualifiers
local mWikidata = require('Modulo:Wikidata')
local p = {}

function p.main(frame)
	local scuole = {}
	local claims

	claims = mWikidata._getClaims('P69', { from = 'Q42' })
	for _, claim in ipairs(claims) do
		local scuola = mWikidata._formatStatement(claim)
		local inizio = mWikidata._formatQualifiers(claim, 'P580')
		local fine = mWikidata._formatQualifiers(claim, 'P582')
		table.insert(scuole, string.format('%s dal %s al %s', scuola, inizio, fine))
	end

	return 'Douglas Adams ha frequentato: ' .. table.concat(scuole, ', ')
end

return p

--[[
* Modulo per accedere a Wikidata in modo più avanzato rispetto a {{#property}}.

* Il modulo è stato importato inizialmente da:
* http://test2.wikipedia.org/w/index.php?title=Module:Wikidata&oldid=52322
]]

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

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

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

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

    local label = mw.wikibase.label( entityId )
    local link = mw.wikibase.sitelink( entityId )
    if link then
        if label then
            return '[[' .. link .. '|' .. label .. ']]'
        else
            return '[[' .. link .. ']]'
        end
    else
        return label or ''
    end
end

local function formatTime( value, options )
    local year, month, day
    local ret = ''
 
    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

    return ret
end

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

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

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

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

    --Use the customize handler if provided
    if options['value-module'] or options['value-function'] then
        if not options['value-module'] or not options['value-function'] then
            return formatError( 'unknown-value-module' )
        end
        local formatter = require ('Module:' .. options['value-module'])
        if formatter == nil then
            return formatError( 'value-module-not-found' )
        end
        local fun = formatter[options['value-function']]
        if fun == nil then
            return formatError( 'value-function-not-found' )
        end
        return fun( datavalue.value, options )
    end
 
    --Default formatters
    if datavalue.type == 'wikibase-entityid' then
        ret = formatEntityId( getEntityIdFromValue( datavalue.value ), options, formatting )
    elseif datavalue.type == 'string' then
        ret = datavalue.value
    elseif datavalue.type == 'time' then
        ret = formatTime( datavalue.value, options )
    elseif datavalue.type == 'globecoordinate' then
        ret = formatGlobecoordinate( datavalue.value, options )
    elseif datavalue.type == 'quantity' then
    	ret = tonumber(datavalue.value.amount)
    else
        ret = formatError( 'unknown-datavalue-type' )
    end

    return ret
end

local function formatSnak( snak, options, formatting )
    if snak.snaktype == 'somevalue' then
        return i18n['somevalue']
    elseif snak.snaktype == 'novalue' then
        return i18n['novalue']
    elseif snak.snaktype == 'value' then
        return formatDatavalue( snak.datavalue, options, formatting )
    else
        return formatError( 'unknown-snak-type' )
    end
end

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

local function formatStatements( claims, options )
    --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

    if list_end then table.insert( formattedStatements, list_end ) end
    return mw.text.listToText( formattedStatements, options.separator, options.conjunction )
end

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

-- Ritorna true se lo statement contiene il qualifier richiesto con un dato valore
local function hasQualifierValue( statement, options )
    local ret = false
    for i, qualifier in pairs( statement.qualifiers[options.qualifier] ) do	
        if formatSnak( qualifier, options, 'raw' ) == options.qualifiervalue then
            ret = true
            break
        end
    end
    return ret
end

-- Ritorna una table contenente gli statement per la property richiesta.
-- Gli statement ritornati sono eventualmente filtrati in base ai parametri:
-- "rank", "qualifier", "qualifiertype" e "n"
local function getClaims( options )
	local entity, claims, filteredClaims
	
    -- get entity
    entity = mw.wikibase.getEntityObject()
    if not entity then
        error( '' ) -- error(formatError( 'entity-not-found' ))
    end

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

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

    -- statements filtrati per rank
    if options.rank then
        filteredClaims = {}
        for i, claim in pairs(claims) do
            if claim.rank == options.rank then
                table.insert( filteredClaims, claim )
            end
        end
        claims = filteredClaims
    end

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

    -- con options.qualifiertype=latest ritorna solo il più recente
    if options.qualifier and options.qualifiertype == 'latest' then
        local latest, latestTime
        for i, claim in pairs( claims ) do
            if claim.qualifiers and claim.qualifiers[options.qualifier] then
                for j, qualifier in pairs( claim.qualifiers[options.qualifier] ) do
                    if qualifier.datavalue.type == 'time' then
                        if not latestTime or qualifier.datavalue.value.time > latestTime then
                            latest = claim
                            latestTime = qualifier.datavalue.value.time
                        end
                    end
                end
            end
        end
        claims = latest and { latest } or {}
    end

    -- con options.n ritorna solo l'n-esimo elemento
    if options.n then
        local n = tonumber( options.n )
        claims = (n and n <= #claims) and { claims[n] } or {}
    end

    return claims
end

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

local p = {}

-- Funzione di utilità, ritorna gli argomenti passati al modulo
-- scartando quelli con nome valorizzati a stringhe vuote.
-- Trasforma inoltre i valori di property e qualifier in uppercase.
local function getArgs( frame )
    local args = {}
 
    for k, v in pairs( frame.args ) do
        if v ~= '' then
            if k == "property" or k == "qualifier" then
                v = string.upper( v )
            end
            args[k] = v
        end
    end
 
    return args
end

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

    args = getArgs( frame )

    -- if parameter value is already set, use it
    if args.value then
        return args.pattern and formatFromPattern( args.value, args ) or args.value 
    end
    
    -- get claims
    ret, claims = pcall( getClaims, args )
    if not ret then
        return claims:match( '.+%d:%s(.+)$' )
    end

    return formatStatements( claims, args )
end

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

    args = getArgs( frame )

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

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

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

    -- get qualifiers and format them
    formattedQualifiers = {}
    for i, claim in pairs( claims ) do
        if claim.qualifiers and claim.qualifiers[args.qualifier] then
            for j, qualifier in pairs( claim.qualifiers[args.qualifier] ) do
                formattedQualifier = formatSnak( qualifier, args )
                if args.pattern then
                    formattedQualifier = formatFromPattern( formattedQualifier, args )
                end 
                table.insert( formattedQualifiers, formattedQualifier )
            end
        end
    end

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

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

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

    return count or 0
end
 
return p