Module:Wikidata Boek
Deze module kan door een andere module worden gebruikt om wikidata over een werk te verkrijgen. Zie de comments bij de functie vraagWikidata
.
local p = {}
--[=[
intern gebruikt voor auteurs & vertalers & ~nu ook uitgevers & plaatsen~ het is eigenlijk gewoon voor wikidata-items ^^
functiesignatuur:
formatteerAuteur(auteur, -- het item zelf
genereerLink=true, -- Wel of niet links genereren.
gebruikOorspronkelijkeSchrijfwijze=true, --[[
Gebruik de tekst van de qualifier "Oorspronkelijke schrijfwijze",
als die bestaat. Heeft altijd de hoogste prioriteit als het aanstaat.
]]
gebruikPaginaTitel=<volgt standaard genereerLink>, --[[
Gebruik lokale paginatitel eerder dan een eigenschap of label van Wikidata.
Indien niet los gegeven, staat het aan als geneerLinks aanstaat en anders uit.
Prioriteit net onder oorspronkelijke schrijfwijze.
]]
prefereerEigenschap=nil --[[
Gebruik een bepaalde eigenschap van de Wikidatapagina van de auteur,
zoals "naam in moedertaal". De eigenschap moet een tekenreeks zijn,
niet een ander Wikidata-item.
Prioriteit hoger dan het label op Wikidata, maar lager dan
oorspronkelijke schrijfwijze en de lokale paginatitel.
]]
)
]=]
local function formatteerAuteur(t)
setmetatable(t, {__index = {
genereerLink = true,
gebruikOorspronkelijkeSchrijfwijze = true,
gebruikPaginaTitel = nil,
prefereerEigenschap = nil
}})
local auteur, genereerLink, gebruikOorspronkelijkeSchrijfwijze, gebruikPaginaTitel, prefereerEigenschap =
t[1] or t.auteur,
t[2] or t.genereerLink,
t[3] or t.gebruikOorspronkelijkeSchrijfwijze,
t[4] or t.gebruikPaginaTitel,
t[5] or t.prefereerEigenschap
local auteur_id -- wikidata ID
local auteurspagina -- pagina
local auteurstekst -- zichtbare tekst die teruggegeven wordt
if gebruikOorspronkelijkeSchrijfwijze and auteur.qualifiers and auteur.qualifiers['P1932'] then
-- er is een oorspronkelijke schrijfwijze en we willen hem gebruiken!
auteurstekst = mw.wikibase.formatValue(auteur.qualifiers['P1932'][1])
end
if auteurstekst and not genereerLink then
-- Als we de tekst al hebben en geen link hoeven, dan zijn we klaar.
return auteurstekst
end
if auteur.mainsnak.snaktype == 'value' then
-- Tijd om de wikidata van de auteur te vinden.
auteur_id = auteur.mainsnak.datavalue.value.id
-- Nu de paginalink, als we die nodig hebben:
if genereerLink or gebruikPaginaTitel then
auteurspagina = mw.wikibase.getSitelink(auteur_id)
if not auteurstekst
and (gebruikPaginaTitel
or (gebruikPaginaTitel ~= false and genereerLink)) then
if auteurspagina then
auteurstekst = mw.title.new(auteurspagina).text
end
end
end
-- als we de auteurstekst nog steeds niet gevonden hebben
if not auteurstekst then
if prefereerEigenschap then
local eigenschap = mw.wikibase.getBestStatements(auteur_id, prefereerEigenschap)[1]
if eigenschap and eigenschap.mainsnak.snaktype == 'value' then
assert(eigenschap.mainsnak.datavalue.type == 'string', "Geprefereerde eigenschap was geen string.")
auteurstekst = eigenschap.mainsnak.datavalue.value
end
end
-- nog steeds niet? dan gebruiken we het label
if not auteurstekst then
auteurstekst = mw.wikibase.getLabel(auteur_id)
end
end
end
if genereerLink and auteurspagina then
return '[[:' .. auteurspagina .. '|' .. auteurstekst .. ']]'
else
return auteurstekst
end
end
--[[
Gegeven een eerder opgehaalde wikidata-entiteit, geeft deze functie een
lijst met de namen van alle auteurs. Er wordt gekeken naar zowel eigenschap
P50 (auteur) als P2093 (auteur als tekenreeks – voor auteurs zonder
wikidata-pagina).
Auteurs die een Wikisource-pagina hebben worden een link naar die pagina.
Als de auteur in het werk de qualifier P1932 (oorspronkelijke schrijfwijze)
heeft, dan wordt dát de tekst die geretourneert wordt.
]]
local function getAuteurs(entiteit)
-- LET OP auteurs kunnen een volgnummer (P1545) hebben, om ze te sorteren; daar wordt nog niet naar geluisterd.
local geformatteerdeAuteurs = {}
-- eerst auteurs met een Wikidata-item
local auteurs = entiteit:getBestStatements('P50')
for i, auteur in ipairs(auteurs) do
table.insert(geformatteerdeAuteurs, formatteerAuteur{auteur})
end
-- dan is er nog een los attribuut voor auteurs zonder wikidata-item
local auteurs = entiteit:getBestStatements('P2093')
for i, auteur in ipairs(auteurs) do
table.insert(geformatteerdeAuteurs, mw.wikibase.formatValue(auteur.mainsnak))
end
return geformatteerdeAuteurs
end
--[[
Hetzelfde te gebruiken als getAuteurs. Verschil in de werking is dat er
op dit moment geen eigenschap “vertaler (als tekenreeks)” lijkt te bestaan,
dus hier wordt niet naar gezocht.
]]
local function getVertalers(entiteit)
local geformatteerdeVertalers = {}
local vertalers = entiteit:getBestStatements('P655')
for i, vertaler in ipairs(vertalers) do
table.insert(geformatteerdeVertalers, formatteerAuteur{vertaler})
end
return geformatteerdeVertalers
end
--[[
Gegeven een eerder opgehaalde wikidata-entiteit, geeft deze functie een
tabel met een "titel" en mogelijk een "ondertitel".
]]
local function getTitel(entiteit)
local titelObject = {}
local siteLink = entiteit:getSitelink()
local titel = entiteit:getBestStatements('P1476')
if titel[1] then
local titelSnak = titel[1].mainsnak -- we pakken de eerste, als er meerdere waardes zijn.
local titelTekst = mw.wikibase.formatValue(titelSnak)
if siteLink then
titelObject.titel = '[[:' .. siteLink .. '|' .. titelTekst .. ']]'
else
titelObject.titel = titelTekst
end
end
local ondertitel = entiteit:getBestStatements('P1680')
if ondertitel[1] then
local ondertitelSnak = ondertitel[1].mainsnak -- opnieuw de eerste
titelObject.ondertitel = mw.wikibase.formatValue(ondertitelSnak)
end
return titelObject
end
--[[
Deze functie geeft informatie over de druk, in het volgende formaat:
{
"jaar": "…", (als string omdat het ook iets als “19e eeuw” of “jaren 1920” kan zijn)
"uitgever": "…",
"plaats": "…",
"druk": {
"nummer": "…",
"schrijfwijze": "…"
}
}
De velden die niet beschikbaar zijn, worden weggelaten.
]]
local function getDruk(entiteit)
local drukInfo = {}
-- datum van uitgave
local datums = entiteit:getBestStatements('P577') -- ‘data’ is een mooier woord, maar ‘datums’ is duidelijker
if datums[1] then -- als er tenminste één datum is
-- kiezen de datum met de hoogste precisie:
local maxPrecisie = -1 -- 0 is de laagste precisie die het systeem ondersteunt
local datum
for k, v in ipairs(datums) do
if v.mainsnak.snaktype == 'value' then
local datum_element = v.mainsnak.datavalue.value
if datum_element.precision > maxPrecisie then
maxPrecisie = datum_element.precision
datum = datum_element['time']
end
end
end
if maxPrecisie >= 7 then -- minstens precisie ‘eeuw’
-- we geven (voor nu) alleen om het jaar.
string.gsub(datum, '^([+-])(%d+)', function(sign, jaar)
--[[
het jaar wordt altijd naar minstens 4 getallen gepad, maar in de
toekomst kan “de 19e eeuw” als “+18” worden weergegeven. Dus we
voegen nullen aan het _eind_ toe als het jaar minder dan vier
tekens lang is.
]]
jaar = string.gsub(jaar, '^(%d%d%d)$', '%10')
jaar = string.gsub(jaar, '^(%d%d)$', '%100')
jaar = string.gsub(jaar, '^(%d)$', '%1000') -- lelijke manier maar who cares, ik ken lua nog maar net
if maxPrecisie == 7 then -- eeuw
local eeuw = string.sub(jaar, 1, 2)
eeuw = tonumber(eeuw) + 1
eeuw = tostring(eeuw)
jaar = eeuw .. 'e eeuw' -- bijv. 18e eeuw
elseif maxPrecisie == 8 then -- decennium
local decennium = string.sub(jaar, 1, 3) .. '0'
jaar = 'jaren ' .. decennium
elseif maxPrecisie >= 9 then -- jaar of beter
-- niks, jaar is al goed
else
error('Daar gaat iets goed fout') -- hier kan je niet komen ^^
end
if sign == '-' then -- vóór christus
jaar = jaar .. ' v. Chr.'
end
drukInfo['jaar'] = jaar
end)
end
end
local uitgevers = entiteit:getBestStatements('P123')
if uitgevers[1] then
drukInfo['uitgever'] = formatteerAuteur{uitgevers[1], genereerLink=false}
end
local plaatsen = entiteit:getBestStatements('P291')
if plaatsen[1] then
drukInfo['plaats'] = formatteerAuteur{plaatsen[1], genereerLink=false}
end
local druk = entiteit:getBestStatements('P393')
if druk[1] and druk[1].mainsnak.snaktype == 'value' then
drukInfo.druk = {}
drukInfo.druk.nummer = druk[1].mainsnak.datavalue.value
if druk[1].qualifiers and druk[1].qualifiers['P1932'] then
local schrijfwijze = mw.wikibase.formatValue(druk[1].qualifiers['P1932'][1])
drukInfo.druk.schrijfwijze = schrijfwijze
end
end
local taal = entiteit:getBestStatements('P407')
if taal[1] and taal[1].mainsnak.snaktype == 'value' and taal[1].mainsnak.datavalue.value.id ~= 'Q7411' then -- deze druk is niet Nederlands!
local geformatteerdeTalen = {}
for k, v in ipairs(taal) do
table.insert(geformatteerdeTalen, formatteerAuteur{v, genereerLink=false})
end
drukInfo.taal = table.concat(geformatteerdeTalen, ', ')
end
return drukInfo
end
local function vindEersteDruk(entiteit, drukInfo)
--[[
als dit de eerste druk is, zijn we klaar. we doen twee checks:
- is het editienummer "1"?
- is dit werk een "eerste druk"/Q10898227?
]]
local dit_is_eerste_druk = false
local dit_is_vertaling = false
if drukInfo.druk and drukInfo.druk.nummer == "1" then
dit_is_eerste_druk = true
else
local entiteit_type = entiteit:getBestStatements('P31')
if entiteit_type[1] then
local entiteit_type = entiteit_type[1]
if entiteit_type.mainsnak.snaktype == 'value'
and entiteit_type.mainsnak.datavalue.value.id == 'Q10898227' -- eerste druk
then
dit_is_eerste_druk = true
end
end
end
-- om zeker te weten dat er geen eerste druk is waar we naar willen refereren,
-- moeten we ook vaststellen dat dit werk in de oorspronkelijke taal is.
local werk = entiteit:getBestStatements('P629')
if not werk[1] or werk[1].mainsnak.snaktype ~= 'value' then
-- geen werk gevonden waar dit aan verbonden is
return nil
end
werk = werk[1] -- het werk waar deze editie aan verbonden is
local werk_id = werk.mainsnak.datavalue.value.id -- het wikidata ID van het werk zelf
-- vind alle talen waar het oorspronkelijke werk in is geschreven
local werk_talen_statements = mw.wikibase.getBestStatements(werk_id, 'P407')
local werk_talen = {}
local taal_gevonden = false
for k, v in ipairs(werk_talen_statements) do
if v.mainsnak.snaktype == 'value' then
local taal_id = v.mainsnak.datavalue.value.id
werk_talen[taal_id] = true
taal_gevonden = true
end
end
if not taal_gevonden then
-- alle waardes voor werk_talen zijn dan true, aangezien we het niet weten
setmetatable(werk_talen, {__index = function() return true end})
end
-- voor de taaldetectie doen we: als de eerste taal van deze editie niet in
-- de lijst talen van het werk zit, is het een vertaling.
local editie_talen_statements = entiteit:getBestStatements('P407')
local editie_taal = editie_talen_statements[1] and editie_talen_statements[1].mainsnak.snaktype == 'value' and editie_talen_statements[1].mainsnak.datavalue.value.id
if not werk_talen[editie_taal] then
dit_is_vertaling = true
end
if dit_is_eerste_druk and not dit_is_vertaling then
-- klaar
return nil
end
-- hierna returnen we “werk_id” als we geen eerste druk vinden, in de hoop
-- in ieder geval het oorspronkelijke jaar van uitgave te achterhalen.
-- eerst het jaar vinden
local werk_jaar_statements = mw.wikibase.getBestStatements(werk_id, 'P577')
local werk_jaar = nil
for k, v in ipairs(werk_jaar_statements) do
if v.mainsnak.snaktype == 'value' then
local waarde = v.mainsnak.datavalue.value
if waarde.precision >= 9 then -- minstens op het jaar
werk_jaar = waarde['time']
werk_jaar = string.gsub(werk_jaar, '^([+-]%d+).*$', '%1')
break
end
end
end
-- nu de edities vinden:
local edities = mw.wikibase.getAllStatements(werk_id, 'P747')
local mogelijke_eerste_drukken = {}
for k, v in ipairs(edities) do
--[[
om te kwalificeren moeten ze (qua qualifiers) minstens
- een editienummer van 1 hebben; of
- van hetzelfde jaar zijn als het werk
en _niet_:
- in een andere taal zijn dan het werk
- een ander editienummer dan 1 hebben
- van een ander jaar zijn dan het werk
]]--
if not v.qualifiers or v.mainsnak.snaktype ~= 'value' then
-- als er niet genoeg informatie is (voor selectie danwel gebruik resp.) selecteren we het niet als eerste druk
else
-- positieve selectie onthouden voor als er meerdere kandidaten zijn
-- (negatieve selectie worden het sowieso niet, dus geen extra informatie nodig)
local positieve_selectie = { jaar_gelijk = false, editienummer_een = false }
local negatieve_selectie = false
-- Taal checken: (we doen 'als de eerste taal in de qualifiers buiten de groep talen van het werk valt, is het geen eerste druk')
if v.qualifiers['P407'] and v.qualifiers['P407'][1].snaktype == 'value' then
local taal = v.qualifiers['P407'][1].datavalue.value.id
if not werk_talen[taal] then
negatieve_selectie = true
end
end
if not negatieve_selectie then -- we zijn nog in de running
-- Jaar checken:
if v.qualifiers['P577'] and v.qualifiers['P577'][1].snaktype == 'value' then
local jaar = v.qualifiers['P577'][1].datavalue.value['time']
local jaar = string.gsub(jaar, '([+-]%d+).*$', '%1')
if jaar == werk_jaar then
positieve_selectie.jaar_gelijk = true
else
negatieve_selectie = true
end
end
if not negatieve_selectie then -- ik zou best een 'continue' statement willen
-- Editienummer checken
if v.qualifiers['P393'] and v.qualifiers['P393'][1].snaktype == 'value' then
local editienummer = v.qualifiers['P393'][1].datavalue.value
if editienummer == '1' then
positieve_selectie.editienummer_een = true
else
negatieve_selectie = true
end
end
end
end
if (positieve_selectie.jaar_gelijk or positieve_selectie.editienummer_een) and not negatieve_selectie then
-- deze wordt toegevoegd aan kandidaten
-- van positieve selectie maken we een string als key
local key = ''
if positieve_selectie.jaar_gelijk then
key = key .. 'jaar'
end
if positieve_selectie.editienummer_een then
key = key .. 'editie1'
end
mogelijke_eerste_drukken[key] = v.mainsnak.datavalue.value.id
end
end
end
-- jaar gelijk en editienummer goed verdient de voorkeur, daarna editienummer goed en geen jaar, en daarna geen editienummer maar jaar goed
if mogelijke_eerste_drukken['jaareditie1'] then
return mogelijke_eerste_drukken['jaareditie1']
elseif mogelijke_eerste_drukken['editie1'] then
return mogelijke_eerste_drukken['editie1']
elseif mogelijke_eerste_drukken['jaar'] then
return mogelijke_eerste_drukken['jaar']
else
return werk_id
end
end
--[=[
Volledige informatie, in de volgende vorm, maar van geen van de velden
mag worden aangenomen dat deze beschikbaar zal zijn:
{
"auteurs": {
1: "[[Auteur:Naam|Naam]]",
2: "Auteur Zonder Wikisourcepagina"
},
"vertalers": {
1: "[[Auteur:Naam|Naam]]"
}
"titel": {
"titel": "Hoofdtitel",
"ondertitel": "Ondertitel",
},
"drukInfo": {
"druk": {
"nummer": "3",
"schrijfwijze": "Derde druk"
},
"jaar": "1921",
"plaats": "Amsterdam",
"uitgever": "Uitgever"
},
"eersteDrukInfo": <zelfde opmaak als drukInfo>
}
]=]
function p.vraagWikidata(wikidata_id)
local return_data = {}
local entiteit = mw.wikibase.getEntity(wikidata_id)
return_data.auteurs = getAuteurs(entiteit)
return_data.vertalers = getVertalers(entiteit)
return_data.titel = getTitel(entiteit)
return_data.drukInfo = getDruk(entiteit)
-- info over eerste druk
local eerste_druk_id = vindEersteDruk(entiteit, return_data.drukInfo)
if eerste_druk_id then
local eerste_druk_entiteit = mw.wikibase.getEntity(eerste_druk_id)
return_data.eersteDrukInfo = getDruk(eerste_druk_entiteit)
else
return_data.eersteDrukInfo = {}
end
return return_data
end
return p