Module:Wikidata statements

From Wikimedia Commons, the free media repository
Jump to navigation Jump to search
Lua

CodeDiscussionEditHistoryLinksLink count Subpages:DocumentationTestsResultsSandboxLive code All modules


The Wikidata statements module provides a number of helper functions to access selected statements from Wikidata. It is intended to be used by other modules; calling these functions directly from Wikitext is not possible.

Usage[edit]

local wdStatements = require "Module:Wikidata statements"
values = getValueList(entityId, propertyId)
items = getItemIdList(entityId, propertyId)
value = getOneValue(entityId, propertyId)
property = getOnePropertyId(entityId, propertyId)
item = getOneItemId(entityId, propertyId)

Parameters[edit]

All public functions have the same two parameters:

entityId
The ID of the entity whose statements are queried. This can be any valid Wikidata entity ID, either an item ID (like "Q1") or a property ID (like "P373").
propertyId
The ID of the property of the statements which are queried. This can be any valid Wikidata property ID (like "P373").

For example, passing the parameters ("Q30", "P36") will query the property capital (P36) of the item United States of America (Q30).

Functions[edit]

All functions will discard the following statements before returning any result:

  • All statements with a "deprecated" rank.
  • All statements with a "normal" rank if there is at least one statement with a "preferred" rank.
  • All statements with qualifiers P580 (start time) and/or P582 (end time) which indicate that the statement's validity has either not yet started or already expired at the time of the query.
getValueList(itemId, propertyId)
Return a Lua table of statements filtered according to the rules described above, each of them formatted as Wikitext.
getItemIdList(itemId, propertyId)
Return a Lua table of Wikidata item IDs for a property which is expected to actually hold references to other Wikidata items. If the property holds values other than references to other Wikidata items, an error is generated.
getOneValue(itemId, propertyId)
Return a single statement formatted as Wikitext. If the queried item has multiple statements for the given property (even after filtering according to the rules described above), an error is generated.
getOnePropertyId(itemId, propertyId)
Return a single Wikidata item ID for a property which is expected to actually hold references to Wikidata properties. If the property holds values other than such references, or the queried item has multiple statements for the given property (even after filtering according to the rules described above), an error is generated.
getOneItemId(itemId, propertyId)
Return a single Wikidata item ID for a property which is expected to actually hold references to other Wikidata items. If the property holds values other than such references, or the queried item has multiple statements for the given property (even after filtering according to the rules described above), an error is generated.

Code

-- =============================================================================
-- Routines for accessing statements from Wikidata
-- =============================================================================

local p = {}

-- -----------------------------------------------------------------------------
-- Return information about a statement, usable for error messages
-- -----------------------------------------------------------------------------

local function statementInfo(statement)
	return (
		"Item " .. string.match(statement.id, "^(.*)%$")
		.. ", Property " .. statement.mainsnak.property
	)
end

-- -----------------------------------------------------------------------------
-- Return the item id for a statement that points to a data item
-- -----------------------------------------------------------------------------

local function getAnyId(statement, datatype, entitytype)
	assert(
		statement.mainsnak.datatype == datatype,
		statementInfo(statement) .. " is not of datatype " .. datatype
	)
	local datavalue = assert(
		statement.mainsnak.datavalue,
		statementInfo(statement) .. " has no datavalue"
	)
	assert(
		datavalue.type == "wikibase-entityid",
		statementInfo(statement) .. "'s value is not of type wikibase-entityid"
	)
	local value = assert(
		datavalue.value,
		statementInfo(statement) .. " has no value"
	)
	assert(
		value["entity-type"] == entitytype,
		statementInfo(statement) .. "'s value's entity-type is not " .. entitytype
	)
	return assert(
		value.id,
		statementInfo(statement) .. "'s value has no id field"
	)
end

-- -----------------------------------------------------------------------------
-- Return the item id for a statement that points to a data item
-- -----------------------------------------------------------------------------

local function getItemId(statement)
	return getAnyId(statement, "wikibase-item", "item")
end

-- -----------------------------------------------------------------------------
-- Return the property id for a statement that points to a property
-- -----------------------------------------------------------------------------

local function getPropertyId(statement)
	return getAnyId(statement, "wikibase-property", "property")
end

-- -----------------------------------------------------------------------------
-- Return a list of statements for a property, filter out obsolete ones
-- -----------------------------------------------------------------------------

local function getStatementList(entityId, propertyId)
	local result = {}
	for index, statement in ipairs(mw.wikibase.getBestStatements(entityId, propertyId)) do
		local useThis = true
		-- Filter out statements with start time in the future
		local startTime = statement.qualifiers and statement.qualifiers.P580
		if startTime then
			assert(#startTime == 1, statementInfo(statement) .. " has more than one start time")
			-- FIXME: Is there a better way to check whether a time value is in the future?
			local lang = mw.getContentLanguage()
			if startTime[1].datavalue and tonumber(lang:formatDate("U", "now")) < tonumber(lang:formatDate("U", startTime[1].datavalue.value.time)) then
				useThis = false
			end
		end
		-- Filter out statements with end time in the past
		local endTime = statement.qualifiers and statement.qualifiers.P582
		if endTime then
			assert(#endTime == 1, statementInfo(statement) .. " has more than one end time")
			-- FIXME: Is there a better way to check whether a time value is in the past?
			local lang =  mw.getContentLanguage()
			if endTime[1].datavalue and tonumber(lang:formatDate("U", "now")) > tonumber(lang:formatDate("U", endTime[1].datavalue.value.time)) then
				useThis = false
			end
		end
		if useThis then
			table.insert(result, statement)
		end
	end
	return result
end

-- -----------------------------------------------------------------------------
-- Return the rendered value of a single statement
-- -----------------------------------------------------------------------------

function p.getValueList(entityId, propertyId)
	local result = {}
	for index, statement in ipairs(getStatementList(entityId, propertyId)) do
		local value = mw.wikibase.renderSnak(statement.mainsnak)
		table.insert(result, value)
	end
	return result
end

-- -----------------------------------------------------------------------------
-- Return the item ids for statements that point to a data item
-- -----------------------------------------------------------------------------

function p.getItemIdList(entityId, propertyId)
	local result = {}
	for index, statement in ipairs(getStatementList(entityId, propertyId)) do
		local itemId = getItemId(statement)
		table.insert(result, itemId)
	end
	return result
end

-- -----------------------------------------------------------------------------
-- Return a single statement for a property, throw error if more than one
-- -----------------------------------------------------------------------------

local function getOneStatement(entityId, propertyId)
	local statements = getStatementList(entityId, propertyId)
	if #statements > 0 then
		assert(#statements == 1, entityId .. " has more than one statement for " .. propertyId)
		return statements[1]
	else
		return nil
	end
end

-- -----------------------------------------------------------------------------
-- Return the rendered value of a single statement
-- -----------------------------------------------------------------------------

function p.getOneValue(entityId, propertyId)
	local statement = getOneStatement(entityId, propertyId)
	if statement then
		return mw.wikibase.renderSnak(statement.mainsnak)
	else
		return nil
	end
end

-- -----------------------------------------------------------------------------
-- Return the property id for a single statement that point to a property
-- -----------------------------------------------------------------------------

function p.getOnePropertyId(entityId, propertyId)
	local statement = getOneStatement(entityId, propertyId)
	if statement then
		return getPropertyId(statement)
	else
		return nil
	end
end

-- -----------------------------------------------------------------------------
-- Return the item id for a single statement that point to a data item
-- -----------------------------------------------------------------------------

function p.getOneItemId(entityId, propertyId)
	local statement = getOneStatement(entityId, propertyId)
	if statement then
		return getItemId(statement)
	else
		return nil
	end
end

-- =============================================================================

return p