Module:Wikidata: Difference between revisions

no edit summary
No edit summary
No edit summary
 
Line 1: Line 1:
-- vim: set noexpandtab ft=lua ts=4 sw=4:
-- vim: set noexpandtab ft=lua ts=4 sw=4:
require('Module:No globals')
require('strict')


local p = {}
local p = {}
Line 362: Line 362:


local function findClaims(entity, property)
local function findClaims(entity, property)
if not property or not entity or not mw.wikibase.getBestStatements(entity, property)[1] then return end
if not property or not entity or not entity.claims then return end


if mw.ustring.match(property, "^P%d+$") then
if mw.ustring.match(property, "^P%d+$") then
-- if the property is given by an id (P..) access the claim list by this id
-- if the property is given by an id (P..) access the claim list by this id
return mw.wikibase.getBestStatements(entity, property)
return entity.claims[property]
else
else
property = mw.wikibase.resolvePropertyId(property)
property = mw.wikibase.resolvePropertyId(property)
if not property then return end
if not property then return end


return mw.wikibase.getBestStatements(entity, property)
return entity.claims[property]
end
end
end
end
Line 402: Line 402:
else
else
-- otherwise return the main snak
-- otherwise return the main snak
return claim[1].mainsnak
return claim.mainsnak
end
end
end
end
Line 439: Line 439:


local function parseInput(frame)
local function parseInput(frame)
local qid = frame.args.qid or mw.wikibase.getEntityIdForCurrentPage() or nil
local qid = frame.args.qid
if qid and (#qid == 0) then qid = nil end
if qid and (#qid == 0) then qid = nil end
local propertyID = mw.text.trim(frame.args[1] or "")
local propertyID = mw.text.trim(frame.args[1] or "")
Line 446: Line 446:
return false, input_parm, nil, nil
return false, input_parm, nil, nil
end
end
local entity = mw.wikibase.getEntity(qid)
local claims
local claims
if qid and mw.wikibase.entityExists(qid) and mw.wikibase.getBestStatements(qid, propertyID)[1] then
if entity and entity.claims then
claims = mw.wikibase.getBestStatements(qid, propertyID)
claims = entity.claims[propertyID]
if not claims then
if not claims then
return false, "", nil, nil
return false, "", nil, nil
Line 455: Line 456:
return false, "", nil, nil
return false, "", nil, nil
end
end
return true, claims
return true, entity, claims, propertyID
end
end
local function isType(claims, type)
local function isType(claims, type)
return claims and claims.mainsnak.snaktype == "value" and claims.mainsnak.datavalue.type == type
return claims[1] and claims[1].mainsnak.snaktype == "value" and claims[1].mainsnak.datavalue.type == type
end
end
local function getValue(claims, delim, labelHook)  
local function getValue(entity, claims, propertyID, delim, labelHook)  
if labelHook == nil then
if labelHook == nil then
labelHook = function (qnumber)
labelHook = function (qnumber)
Line 466: Line 467:
end
end
end
end
local out = {}
if isType(claims, "wikibase-entityid") then
if claims[1] then
local out = {}
local i = 1
for k, v in pairs(claims) do
while claims[i] ~= nil do
local qnumber = "Q" .. v.mainsnak.datavalue.value["numeric-id"]
if isType(claims[i], "wikibase-entityid") then
local sitelink = mw.wikibase.getSitelink(qnumber)
local qnumber = "Q" .. claims[i].mainsnak.datavalue.value["numeric-id"]
local label = labelHook(qnumber) or mw.wikibase.getLabel(qnumber) or qnumber
local sitelink = mw.wikibase.getSitelink(qnumber)
if sitelink then
local label = labelHook(qnumber) or mw.wikibase.getLabel(qnumber) or qnumber
out[#out + 1] = "[[" .. sitelink .. "|" .. label .. "]]"
if sitelink then
out[#out + 1] = "[[" .. sitelink .. "|" .. label .. "]]"
else
out[#out + 1] = "[[:d:" .. qnumber .. "|" .. label .. "]]<abbr title='" .. i18n["errors"]["local-article-not-found"] .. "'>[*]</abbr>"
end
else
else
out[#out + 1] = mw.wikibase.renderSnak(claims[i].mainsnak)
out[#out + 1] = "[[:d:" .. qnumber .. "|" .. label .. "]]<abbr title='" .. i18n["errors"]["local-article-not-found"] .. "'>[*]</abbr>"
end
end
i = i + 1
end
end
return table.concat(out, delim)
else
-- just return best values
return entity:formatPropertyValues(propertyID).value
end
end
return table.concat(out, delim)
end
end


Line 524: Line 522:
delim = delimdefault
delim = delimdefault
end
end
local go, claims = parseInput(frame)
local go, errorOrentity, claims, propertyID = parseInput(frame)
if not go then
if not go then
return claims
return errorOrentity
end
end
return getValue(claims, delim)
return getValue(errorOrentity, claims, propertyID, delim)
end
end


-- Same as above, but uses the short name property for label if available.
-- Same as above, but uses the short name property for label if available.
p.getValueShortName = function(frame)
p.getValueShortName = function(frame)
local go, claims = parseInput(frame)
local go, errorOrentity, claims, propertyID = parseInput(frame)
if not go then
if not go then
return claims
return errorOrentity
end
end
local entity = errorOrentity
-- if wiki-linked value output as link if possible
-- if wiki-linked value output as link if possible
local function labelHook (qnumber)
local function labelHook (qnumber)
local label
local label
local i = 1
local claimEntity = mw.wikibase.getEntity(qnumber)
if mw.wikibase.entityExists(qnumber) then
if claimEntity ~= nil then
if mw.wikibase.getBestStatements(qnumber, "P1813")[1] then
if claimEntity.claims.P1813 then
while mw.wikibase.getBestStatements(qnumber, "P1813")[i] ~= nil do
for k2, v2 in pairs(claimEntity.claims.P1813) do
if mw.wikibase.getBestStatements(qnumber, "P1813")[i].mainsnak.datavalue.value.language == "en" then
if v2.mainsnak.datavalue.value.language == "en" then
label = mw.wikibase.getBestStatements(qnumber, "P1813")[i].mainsnak.datavalue.value.text
label = v2.mainsnak.datavalue.value.text
end
end
i = i + 1
end
end
end
end
Line 554: Line 552:
return label
return label
end
end
return getValue(claims, ", ", labelHook);
return getValue(errorOrentity, claims, propertyID, ", ", labelHook);
end
end


Line 567: Line 565:
local input_parm = mw.text.trim(frame.args[3] or "")
local input_parm = mw.text.trim(frame.args[3] or "")
if input_parm == "FETCH_WIKIDATA" then
if input_parm == "FETCH_WIKIDATA" then
local entity = mw.wikibase.getEntity(itemID)
local claims
local claims
if frame.args[1] and mw.wikibase.entityExists(itemID) and mw.wikibase.getBestStatements(itemID, propertyID)[1] then
if entity and entity.claims then
claims = mw.wikibase.getBestStatements(itemID, propertyID)
claims = entity.claims[propertyID]
end
end
if claims then
if claims then
return getValue(claims, ", ")
return getValue(entity, claims, propertyID, ", ")
else
else
return ""
return ""
Line 585: Line 584:
local input_parm = mw.text.trim(frame.args[3] or "")
local input_parm = mw.text.trim(frame.args[3] or "")
if input_parm == "FETCH_WIKIDATA" then
if input_parm == "FETCH_WIKIDATA" then
local entityid = mw.wikibase.getEntityIdForCurrentPage()
local entity = mw.wikibase.getEntity()
if mw.wikibase.entityExists(entityid) ~= nil and mw.wikibase.getBestStatements(entityid, propertyID)[1] ~= nil then
if entity.claims[propertyID] ~= nil then
local out = {}
local out = {}
local i = 1
for k, v in pairs(entity.claims[propertyID]) do
while mw.wikibase.getBestStatements(entityid, propertyID)[i] ~= nil do
for k2, v2 in pairs(v.qualifiers[qualifierID]) do
for k2, v2 in pairs(mw.wikibase.getBestStatements(entityid, propertyID)[i].qualifiers[qualifierID]) do
if v2.snaktype == 'value' then
if v2.snaktype == 'value' then
out[#out + 1] = outputHook(v2);
out[#out + 1] = outputHook(v2);
end
end
end
end
i = i + 1
end
end
return table.concat(out, ", "), true
return table.concat(out, ", "), true
Line 619: Line 616:
-- This is used to get a value like 'male' (for property p21) which won't be linked and numbers without the thousand separators
-- This is used to get a value like 'male' (for property p21) which won't be linked and numbers without the thousand separators
p.getRawValue = function(frame)
p.getRawValue = function(frame)
local go, claims = parseInput(frame)
local go, errorOrentity, claims, propertyID = parseInput(frame)
if not go then
if not go then
return claims
return errorOrentity
end
end
local result = {}
local entity = errorOrentity
local i = 1
local result = entity:formatPropertyValues(propertyID, mw.wikibase.entity.claimRanks).value
while claims[i] ~= nil do
-- if number type: remove thousand separators, bounds and units
-- if number type: remove thousand separators, bounds and units
if isType(claims, "quantity") then
if isType(claims[i], "quantity") then
result = mw.ustring.gsub(result, "(%d),(%d)", "%1%2")
result[#result +1] = mw.ustring.gsub(mw.wikibase.renderSnak(claims[i].mainsnak), "(%d),(%d)", "%1%2")
result = mw.ustring.gsub(result, "(%d)±.*", "%1")
result[#result +1] = mw.ustring.gsub(mw.wikibase.renderSnak(claims[i].mainsnak), "(%d)±.*", "%1")
else
result[#result + 1] = mw.wikibase.renderSnak(claims[i].mainsnak)
end
i = i + 1
end
end
return table.concat(result, ', ')
return result
end
end


-- This is used to get the unit name for the numeric value returned by getRawValue
-- This is used to get the unit name for the numeric value returned by getRawValue
p.getUnits = function(frame)
p.getUnits = function(frame)
local go, claims = parseInput(frame)
local go, errorOrentity, claims, propertyID = parseInput(frame)
if not go then
if not go then
return claims
return errorOrentity
end
end
local result = {}
local entity = errorOrentity
local i = 1
local result = entity:formatPropertyValues(propertyID, mw.wikibase.entity.claimRanks).value
while claims[i] ~= nil do
if isType(claims, "quantity") then
local i = 1
result = mw.ustring.sub(result, mw.ustring.find(result, " ")+1, -1)
if isType(claims[i], "quantity") then
result[#result +1] = mw.ustring.sub(mw.renderSnak(claims[i].mainsnak), mw.ustring.find(result, " ")+1, -1)
else
result[#result + 1] = mw.renderSnak(claims[i].mainsnak)
end
i = i + 1
end
end
return result
return result
Line 660: Line 646:
-- This is used to get the unit's QID to use with the numeric value returned by getRawValue
-- This is used to get the unit's QID to use with the numeric value returned by getRawValue
p.getUnitID = function(frame)
p.getUnitID = function(frame)
local go, claims = parseInput(frame)
local go, errorOrentity, claims = parseInput(frame)
if not go then
if not go then
return claims
return errorOrentity
end
end
local entity = errorOrentity
local result
local result
if isType(claims[1], "quantity") then
if isType(claims, "quantity") then
-- get the url for the unit entry on Wikidata:
-- get the url for the unit entry on Wikidata:
result = claims[1].mainsnak.datavalue.value.unit
result = claims[1].mainsnak.datavalue.value.unit
Line 696: Line 683:
local date_format = mw.text.trim(frame.args[3] or i18n["datetime"]["default-format"])
local date_format = mw.text.trim(frame.args[3] or i18n["datetime"]["default-format"])
local date_addon = mw.text.trim(frame.args[4] or i18n["datetime"]["default-addon"])
local date_addon = mw.text.trim(frame.args[4] or i18n["datetime"]["default-addon"])
local go, claims = parseInput(frame)
local go, errorOrentity, claims = parseInput(frame)
if not go then
if not go then
return claims
return errorOrentity
end
end
local entity = errorOrentity
local out = {}
local out = {}
local i = 1
for k, v in pairs(claims) do
while claims[i] ~= nil do
if v.mainsnak.datavalue.type == 'time' then
if claims[i].mainsnak.datavalue.type == 'time' then
local timestamp = v.mainsnak.datavalue.value.time
local timestamp = claims[i].mainsnak.datavalue.value.time
local dateprecision = v.mainsnak.datavalue.value.precision
local dateprecision = claims[i].mainsnak.datavalue.value.precision
-- A year can be stored like this: "+1872-00-00T00:00:00Z",
-- A year can be stored like this: "+1872-00-00T00:00:00Z",
-- which is processed here as if it were the day before "+1872-01-01T00:00:00Z",
-- which is processed here as if it were the day before "+1872-01-01T00:00:00Z",
Line 712: Line 699:
timestamp = timestamp:gsub("%-00%-00T", "-01-01T")
timestamp = timestamp:gsub("%-00%-00T", "-01-01T")
out[#out + 1] = parseDateFull(timestamp, dateprecision, date_format, date_addon)
out[#out + 1] = parseDateFull(timestamp, dateprecision, date_format, date_addon)
i = i + 1
end
end
end
end
Line 736: Line 722:
local sep = mw.text.trim(frame.args[3] or " ")
local sep = mw.text.trim(frame.args[3] or " ")
local imgsize = mw.text.trim(frame.args[4] or "frameless")
local imgsize = mw.text.trim(frame.args[4] or "frameless")
local go, claims = parseInput(frame)
local go, errorOrentity, claims = parseInput(frame)
if not go then
if not go then
return claims
return errorOrentity
end
end
local entity = errorOrentity
if (claims[1] and claims[1].mainsnak.datatype == "commonsMedia") then
if (claims[1] and claims[1].mainsnak.datatype == "commonsMedia") then
local out = {}
local out = {}
local i = 1
for k, v in pairs(claims) do
while claims[i] ~= nil do
local filename = v.mainsnak.datavalue.value
local filename = claims[i].mainsnak.datavalue.value
out[#out + 1] = "[[File:" .. filename .. "|" .. imgsize .. "]]"
out[#out + 1] = "[[File:" .. filename .. "|" .. imgsize .. "]]"
i = i + 1
end
end
return table.concat(out, sep)
return table.concat(out, sep)
Line 755: Line 740:


-- This is used to get the TA98 (Terminologia Anatomica first edition 1998) values like 'A01.1.00.005' (property P1323)
-- This is used to get the TA98 (Terminologia Anatomica first edition 1998) values like 'A01.1.00.005' (property P1323)
-- which are then linked to http://www.unifr.ch/ifaa/Public/EntryPage/TA98%20Tree/Entity%20TA98%20EN/01.1.00.005%20Entity%20TA98%20EN.htm
-- which are then linked to https://ifaa.unifr.ch/Public/EntryPage/TA98%20Tree/Entity%20TA98%20EN/01.1.00.005%20Entity%20TA98%20EN.htm
-- uses the newer mw.wikibase calls instead of directly using the snaks
-- uses the newer mw.wikibase calls instead of directly using the snaks
-- formatPropertyValues returns a table with the P1323 values concatenated with ", " so we have to split them out into a table in order to construct the return string
-- formatPropertyValues returns a table with the P1323 values concatenated with ", " so we have to split them out into a table in order to construct the return string
p.getTAValue = function(frame)
p.getTAValue = function(frame)
local entid = mw.wikibase.getEntityIdForCurrentPage()
local ent = mw.wikibase.getEntity()
local props = mw.wikibase.getEntity(entid):formatPropertyValues('P1323')
local props = ent:formatPropertyValues('P1323')
local out = {}
local out = {}
local t = {}
local t = {}
Line 767: Line 752:
t = mw.text.split( v, ", ")
t = mw.text.split( v, ", ")
for k2, v2 in pairs(t) do
for k2, v2 in pairs(t) do
out[#out + 1] = "[http://www.unifr.ch/ifaa/Public/EntryPage/TA98%20Tree/Entity%20TA98%20EN/" .. string.sub(v2, 2) .. "%20Entity%20TA98%20EN.htm " .. v2 .. "]"
out[#out + 1] = "[https://ifaa.unifr.ch/Public/EntryPage/TA98%20Tree/Entity%20TA98%20EN/" .. string.sub(v2, 2) .. "%20Entity%20TA98%20EN.htm " .. v2 .. "]"
end
end
end
end
Line 813: Line 798:
local input_parm = mw.text.trim(frame.args[1] or "")
local input_parm = mw.text.trim(frame.args[1] or "")
if input_parm == "FETCH_WIKIDATA" then
if input_parm == "FETCH_WIKIDATA" then
local ent = mw.wikibase.getEntity(id)
local imgs
if ent and ent.claims then
imgs = ent.claims.P18
end
local imglbl
local imglbl
if id and mw.wikibase.entityExists(id) and mw.wikibase.getBestStatements(id, "P18")[1] and  
if imgs then
mw.wikibase.getBestStatements(id, "P18")[1].mainsnak.datavalue and
-- look for an image with 'preferred' rank
mw.wikibase.getBestStatements(id, "P18")[1].rank == "preferred" then -- in getBestStatements if there is an preferred value, it is ordered first.
for k1, v1 in pairs(imgs) do
imglbl = mw.wikibase.getBestStatements(id, "P18")[1].mainsnak.datavalue.value
if v1.rank == "preferred" and v1.qualifiers and v1.qualifiers.P2096 then
elseif id and mw.wikibase.entityExists(id) and mw.wikibase.getBestStatements(id, "P18")[1] and
local imglbls = v1.qualifiers.P2096
mw.wikibase.getBestStatements(id, "P18")[1].mainsnak.datavalue then -- only normal and preferred rank values outputted in beststatements
for k2, v2 in pairs(imglbls) do
imglbl = mw.wikibase.getBestStatements(id, "P18")[1].mainsnak.datavalue.value
if v2.datavalue.value.language == lang then
imglbl = v2.datavalue.value.text
break
end
end
end
end
-- if we don't find one, look for an image with 'normal' rank
if (not imglbl) then
for k1, v1 in pairs(imgs) do
if v1.rank == "normal" and v1.qualifiers and v1.qualifiers.P2096 then
local imglbls = v1.qualifiers.P2096
for k2, v2 in pairs(imglbls) do
if v2.datavalue.value.language == lang then
imglbl = v2.datavalue.value.text
break
end
end
end
end
end
end
end
return imglbl
return imglbl
else
else
Line 834: Line 843:


p.getPropertyIDs = function(frame)
p.getPropertyIDs = function(frame)
local go, propclaims = parseInput(frame)
local go, errorOrentity, propclaims = parseInput(frame)
if not go then
if not go then
return propclaims
return errorOrentity
end
end
local entity = errorOrentity
-- if wiki-linked value collect the QID in a table
-- if wiki-linked value collect the QID in a table
if (propclaims[1] and propclaims[1].mainsnak.snaktype == "value" and propclaims[1].mainsnak.datavalue.type == "wikibase-entityid") then
if (propclaims[1] and propclaims[1].mainsnak.snaktype == "value" and propclaims[1].mainsnak.datavalue.type == "wikibase-entityid") then
local out = {}
local out = {}
local i = 1
for k, v in pairs(propclaims) do
while claims[i] ~= nil do
out[#out + 1] = "Q" .. v.mainsnak.datavalue.value["numeric-id"]
out[#out + 1] = "Q" .. claims[i].mainsnak.datavalue.value["numeric-id"]
i = i + 1
end
end
return table.concat(out, ", ")
return table.concat(out, ", ")
Line 860: Line 868:
function p.claim(frame)
function p.claim(frame)
local property = frame.args[1] or ""
local property = frame.args[1] or ""
local id = frame.args["id"] or mw.wikibase.getEntityIdForCurrentPage()
local id = frame.args["id"]
local qualifierId = frame.args["qualifier"]
local qualifierId = frame.args["qualifier"]
local parameter = frame.args["parameter"]
local parameter = frame.args["parameter"]
Line 869: Line 877:
if default then showerrors = nil end
if default then showerrors = nil end


-- check wikidata entity
-- get wikidata entity
local entity = mw.wikibase.getEntity(id)
if not mw.wikibase.entityExists(id) then
if not entity then
if showerrors then return printError("entity-not-found") else return default end
if showerrors then return printError("entity-not-found") else return default end
end
end
-- fetch the first claim of satisfying the given property
-- fetch the first claim of satisfying the given property
local claims = mw.wikibase.getBestStatements(id, property) or nil
local claims = findClaims(entity, property)
if not claims or not claims[1] then
if not claims or not claims[1] then
if showerrors then return printError("property-not-found") else return default end
if showerrors then return printError("property-not-found") else return default end
end
end


-- no need to sort, bestStatements orders preferred rank first
-- get initial sort indices
local sortindices = {}
for idx in pairs(claims) do
sortindices[#sortindices + 1] = idx
end
-- sort by claim rank
local comparator = function(a, b)
local rankmap = { deprecated = 2, normal = 1, preferred = 0 }
local ranka = rankmap[claims[a].rank or "normal"] .. string.format("%08d", a)
local rankb = rankmap[claims[b].rank or "normal"] .. string.format("%08d", b)
return ranka < rankb
end
table.sort(sortindices, comparator)


local result
local result
local error
local error
local i = 1
if list then
if list then
local value
local value
Line 890: Line 909:
result = {}
result = {}
for idx in pairs(claims) do
for idx in pairs(claims) do
local claim = claims[i]
local claim = claims[sortindices[idx]]
value, error = getValueOfClaim(claim, qualifierId, parameter)
value, error = getValueOfClaim(claim, qualifierId, parameter)
if not value and showerrors then value = error end
if not value and showerrors then value = error end
if value and references then value = value .. getReferences(frame, claim) end
if value and references then value = value .. getReferences(frame, claim) end
result[#result + 1] = value
result[#result + 1] = value
i = i + 1
end
end
result = table.concat(result, list)
result = table.concat(result, list)
else
else
-- return first element
-- return first element
local claim = claims[i]
local claim = claims[sortindices[1]]
result, error = getValueOfClaim(claim, qualifierId, parameter)
result, error = getValueOfClaim(claim, qualifierId, parameter)
if result and references then result = result .. getReferences(frame, claim) end
if result and references then result = result .. getReferences(frame, claim) end
Line 918: Line 936:
end
end
local data = mw.wikibase.getEntity(id)
local data = mw.wikibase.getEntity(id)
if not id or not mw.wikibase.entityExists(id) then
if not data then
return nil
return nil
end
end
Line 948: Line 966:
if qid == "" then qid = nil end
if qid == "" then qid = nil end
local f = mw.text.trim( frame.args[1] or "")
local f = mw.text.trim( frame.args[1] or "")
if not quid or not mw.wikibase.entityExists(qid) then
local entity = mw.wikibase.getEntity(qid)
if not entity then
return
return
end
end
local link = mw.wikibase.getSitelink( f )
local link = entity:getSitelink( f )
if not link then
if not link then
return
return