Encyclopædia Wiki
Advertisement

Die Dokumentation für dieses Modul kann unter Modul:Wikidata/Doku erstellt werden

-- module local variables
local wiki = 
{
	langcode = mw.language.getContentLanguage().code
}

-- internationalisation
local i18n = {
    ["errors"] = {
        ["property-not-found"] = "Eigenschaft nicht gefunden.",
        ["entity-not-found"] = "Entity nicht gefunden.",
        ["unknown-claim-type"] = "Unbekannter Aussagentyp.",
        ["unknown-snak-type"] = "Unbekannter Snak-Typ.",
        ["unknown-datavalue-type"] = "Unbekannter Datentyp.",
        ["unknown-entity-type"] = "Unbekannter Entity-Typ.",
        ["qualifier-not-found"] = "Qualifikator nicht gefunden."
    },
    ["somevalue"] = "''unbekannter Wert''",
    ["novalue"] = "''kein Wert''"
}

local p = { }

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

function p.descriptionIn(frame)
	local langcode = frame.args[1]
	-- return description of a Wikidata entity in the given language or the default language of this Wikipedia site
	return mw.wikibase.getEntityObject().descriptions[langcode or wiki.langcode].value
end

function p.labelIn(frame)
	local langcode = frame.args[1]
	-- return label of a Wikidata entity in the given language or the default language of this Wikipedia site
	return mw.wikibase.getEntityObject().labels[langcode or wiki.langcode].value
end

local function printDatavalueCoordinate(data, parameter)
	-- data fields: latitude [double], longitude [double], altitude [double], precision [double], globe [wikidata URI, usually http://www.wikidata.org/entity/Q2 [earth]]
	if parameter then
		if parameter == "globe" then data.globe = mw.ustring.match(data.globe, "Q%d+") end -- extract entity id from the globe URI
		return data[parameter]
	else
		return data.latitude .. "/" .. data.longitude -- combine latitude and longitude, which can be decomposed using the #titleparts wiki function
	end
end

local function printDatavalueQuantity(data, parameter)
	-- data fields: amount [number], unit [string], upperBound [number], lowerBound [number]
	if parameter then
		return data[paramater]
	else
		return tonumber(data.amount)
	end
end

local function printDatavalueTime(data, parameter)
	-- data fields: time [ISO 8601 time], timezone [int in minutes], before [int], after [int], precision [int], calendarmodel [wikidata URI]
	--   precision: 0 - billion years, 1 - hundred million years, ..., 6 - millenia, 7 - century, 8 - decade, 9 - year, 10 - month, 11 - day, 12 - hour, 13 - minute, 14 - second
	--   calendarmodel: e.g. http://www.wikidata.org/entity/Q1985727 for the proleptic Gregorian calendar or http://www.wikidata.org/wiki/Q11184 for the Julian calendar]
	data.time = mw.text.trim(data.time, " +0")
	if parameter then
		if parameter == "calendarmodel" then data.calendarmodel = mw.ustring.match(data.calendarmodel, "Q%d+") end -- extract entity id from the calendar model URI
		return data[parameter]
	else
		return data.time
	end
end

local function printDatavalueEntity(data, parameter)
	-- data fields: entity-type [string], numeric-id [int, Wikidata id]
	if parameter then
		return data[parameter]
	else
		if data["entity-type"] == "item" then return mw.wikibase.label("Q" .. data["numeric-id"]) else printError("unknown-entity-type") end
	end
end

function findClaims(entity, property)
	if not property or not entity or not entity.claims then return end
	
	if mw.ustring.match(property, "^P%d+$") then
		-- if the property is given by an id (P..) access the claim list by this id
		return entity.claims[property]
	else
		-- otherwise, iterate over all properties, fetch their labels and compare this to the given property name
		for k,v in pairs(entity.claims) do
			if mw.wikibase.label(k) == property then return v end
		end
		return
	end
end

function getSnakValue(snak, parameter)
	-- snaks have three types: "novalue" for null/nil, "somevalue" for not null/not nil, or "value" for actual data
	if snak.snaktype == "novalue" then return i18n["novalue"]
	elseif snak.snaktype == "somevalue" then return i18n["somevalue"]
	elseif snak.snaktype ~= "value" then return nil, printError("unknown-snak-type")
	end
		
	-- call the respective snak parser
	if snak.datavalue.type == "string" then return snak.datavalue.value
	elseif snak.datavalue.type == "globecoordinate" then return printDatavalueCoordinate(snak.datavalue.value, parameter)
	elseif snak.datavalue.type == "quantity" then return printDatavalueQuantity(snak.datavalue.value, parameter)
	elseif snak.datavalue.type == "time" then return printDatavalueTime(snak.datavalue.value, parameter)
	elseif snak.datavalue.type == "wikibase-entityid" then return printDatavalueEntity(snak.datavalue.value, parameter)
	else return nil, printError("unknown-datavalue-type")
	end
end

function getQualifierSnak(claim, qualifierId)
	-- a "snak" is Wikidata terminology for a typed key/value pair
	-- a claim consists of a main snak holding the main information of this claim,
	-- as well as a list of attribute snaks and a list of references snaks
	if qualifierId then
		-- search the attribute snak with the given qualifier as key
		if claim.qualifiers then
			local qualifier = claim.qualifiers[qualifierId]
			if qualifier then return qualifier[1] end
		end
		return nil, printError("qualifier-not-found")
	else
		-- otherwise return the main snak
		return claim.mainsnak
	end
end

function getValueOfClaim(claim, qualifierId, parameter)
	local error
	local snak
	snak, error = getQualifierSnak(claim, qualifierId)
	if snak then
		return getSnakValue(snak, parameter)
	else
		return nil, error
	end
end

function p.claim(frame)
	local property = frame.args[1] or ""
	local qualifierId = frame.args["qualifier"]
	local parameter = frame.args["parameter"]
	local list = frame.args["list"]
	local showerrors = frame.args["showerrors"]

	-- get wikidata entity
	local entity = mw.wikibase.getEntityObject()
	if not entity then
		if showerrors then return printError("entity-not-found") else return end
	end
	-- fetch the first claim of satisfying the given property
	local claims = findClaims(entity, property)
	if not claims or not claims[1] then
		if showerrors then return printError("property-not-found") else return end
	end
		
	-- 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 = -1, normal = 0, preferred = 1 } -- not needed as the ranks are coincidentally in alphanumeric order 
		local ranka = claims[a].rank or "normal"
		local rankb = claims[b].rank or "normal"
		return ranka > rankb
		--return ranka and rankb and rankmap[ranka] > rankmap[rankb] -- normal sort order is "<", but high priority needs to be sorted first (descending sort)
		
		--return mw.wikibase.label("Q" .. .mainsnak.datavalue.value["numeric-id"]) < mw.wikibase.label("Q" .. claims[b].mainsnak.datavalue.value["numeric-id"])
	end
	table.sort(sortindices, comparator)

	local result
	local error
	if list then
		local value
		-- iterate over all elements and return their value (if existing)
		for idx = 1, #claims do
			value, error =  getValueOfClaim(claims[sortindices[idx]], qualifierId, parameter)
			if not value and showerrors then value = error end
			if result then
				if value then result = result .. list .. value end
			else result = value end
		end
	else
		-- return first element	
		result, error = getValueOfClaim(claims[sortindices[1]], qualifierId, parameter)
	end
	if not result and showerrors then return error else return result end
end

function p.labelOf(frame)
	local id = frame.args[1]
	-- returns the label of the given entity/property id
	-- if no id is given, the one from the entity associated with the calling Wikipedia article is used
	if not id then
		local entity = mw.wikibase.getEntityObject()
		if not entity then return printError("entity-not-found") end
		id = entity.id
	end
	return mw.wikibase.label(id)
end

function p.sitelinkOf(frame)
	local id = frame.args[1]
	-- returns the Wikipedia article name of the given entity
	-- if no id is given, the one from the entity associated with the calling Wikipedia article is used
	if not id then
		local entity = mw.wikibase.getEntityObject()
		if not entity then return printError("entity-not-found") end
		id = entity.id
	end
	return mw.wikibase.sitelink(id)
end

-- call this in cases of script errors within a function instead of {{#invoke:Wikidata|<method>|...}} call {{#invoke:Wikidata|debug|<method>|...}}
function p.debug(frame)
	local func = frame.args[1]
	if func then
		table.remove(frame.args, 1)
		local status, result = pcall(p[func], frame)
		if status then return result else return '<span class="error">' .. result .. '</span>' end
	end
end

function printTable(data, level)
	level = tonumber(level) or 0
	local result
	if level == 0 then result = "<pre>\n" else result = "" end
	local prefix = ""
	for idx = 1, level do prefix = prefix .. " " end
	
	if type(data) == "table" then
		for key, val in pairs(data) do
			result = result .. prefix .. key .. ": "
			if type(val) == "table" then result = result .. "\n" .. printTable(val, level + 1) else result = result .. tostring(val) .. "\n" end
		end
	else
		result = prefix .. tostring(data)
	end
	if level == 0 then result = result .. "</pre>" end
	return result
end

function p.printEntity(frame)
	local entity = mw.wikibase.getEntityObject()
	return printTable(entity)
end

return p
Advertisement