Modul:Wikidata/Test
Die Dokumentation für dieses Modul kann unter Modul:Wikidata/Test/Doku erstellt werden
local Wd = {
-- project configuration
wiki = {
langcode = mw.language.getContentLanguage().code
},
-- internationalisation
i18n = {
["datetime"] = {
-- $s is a placeholder for the actual number
[0] = "%s Mrd. Jahren", -- precision: billion years
[1] = "%s00 Mio. Jahren", -- precision: hundred million years
[2] = "%s0 Mio. Jahren", -- precision: ten million years
[3] = "%s Mio. Jahren", -- precision: million years
[4] = "%s00.000 Jahren", -- precision: hundred thousand years
[5] = "%s0.000 Jahren", -- precision: ten thousand years
[6] = "%s. Jahrtausend", -- precision: millenium
[7] = "%s. Jahrhundert", -- precision: century
[8] = "%ser", -- precision: decade
-- the following use the format of #time parser function
[9] = "Y", -- precision: year,
[10] = "F Y", -- precision: month
[11] = "j. F Y", -- precision: day
[12] = 'j. F Y, G "Uhr"', -- precision: hour
[13] = "j. F Y G:i", -- precision: minute
[14] = "j. F Y G:i:s", -- precision: second
["beforenow"] = "vor %s", -- how to format negative numbers for precisions 0 to 5
["afternow"] = "in %s", -- how to format positive numbers for precisions 0 to 5
["bc"] = '%s "v.Chr."', -- how print negative years
["ad"] = "%s" -- how print positive years
},
["errors"] = {
["deprecated-function"] = "Aufruf veralteter Funktion",
["entity-not-found"] = "Wikidata-Eintrag nicht gefunden.",
["entity-not-valid"] = "Die an die Wikidata-Schnittstelle übergebene Item-ID ist nicht gültig",
["invalid-parameters"] = "Ungültige Parameter",
["module-not-loaded"] = "Loading of additional module failed",
["property-not-found"] = "Eigenschaft nicht gefunden",
["qualifier-not-found"] = "Qualifikator nicht gefunden",
["site-not-found"] = "Wikimedia-Projekt nicht gefunden",
["unknown-claim-type"] = "Unbekannter Aussagentyp",
["unknown-entity-type"] = "Unbekannter Entity-Typ",
},
["errortext"] = '<span class="error">%s</span>',
["FETCH_WIKIDATA"] = "ABFRAGE_WIKIDATA",
["maintenance-pages"] = {
["entity-not-found"] = "Wikidata/Wartung/Fehlendes Datenobjekt",
["entity-not-valid"] = "Wikidata/Wartung/Ungültige Datenobjekt-Identifikationsnummer",
["property-not-found"] = "Wikidata/Wartung/Eigenschaft existiert nicht"
},
["monolingualtext"] = '<span lang="%s">%s</span>',
},
-- global value to count calls of expensive function isParent, including recursive calls
numberIsParentCalls = 0,
-- important properties
propertyId = {
["starttime"] = "P580",
["endtime"] = "P582",
["pointoftime"] = "P585"
},
formatchar = {
[10] = {"n","m","M","F","xg"}, --precision: month
[11] = {"W","j","d","z","D","l","N","w"}, --precision: day
[12] = {"a","A","g","h","G","H"}, --precision: hour
[13] = {"i"}, --precision: minute
[14] = {"s","U"} --precision: second
}
}
--[=[
==============================================================================
GENERAL HELPERS
==============================================================================
]=]
--[=[
print an error with the given error code in case of template call
parameters:
- frame (opt, table): template call frame for determining the error mode
- code (opt, string): error code
- info (opt, string): additional information
returns: (string) error text
]=]
Wd.templateCallError = function( frame, code, info )
local mode
local text
-- get error mode
mode = Wd.getFrameArgument( frame, "errors", false, "empty" )
-- output error depending on mode
text = ""
if mode == "show" then
-- show the error, reachable with #iferror in template calls
text = Wd.i18n.errors[ code ] or code or ""
if info then
text = text .. ": " .. info
end
text = mw.ustring.format( Wd.i18n.errortext, text )
elseif mode == "empty" then
-- output empty string in case of error
text = ""
elseif mode == "link" then
-- create maintenance link and output empty string
Wd.createMaintenanceLink( code )
text = ""
elseif mode == "text" then
-- output text given in errorsText parameter
text = Wd.getFrameArgument( frame, "errorsText", false, "" )
end
return text
end
--[=[
create a new error object
parameters:
- code (string): error code
- info (opt, string): additional information
returns: (table) error table
]=]
Wd.newError = function( code, info )
return {
code = code,
info = tostring( info )
}
end
--[=[
parse the given error object
parameters:
- error (table): error object created with Wd.newError
returns:
- (string): error code
- (string|nil): additional information if available
]=]
Wd.parseError = function( error )
return error.code, error.info
end
--[=[
the "qualifiers" and "snaks" field have a respective "qualifiers-order" and "snaks-order" field
use these as the second parameter and this function instead of the built-in "pairs" function
to iterate over all qualifiers and snaks in the intended order.
parameters:
- array (table): table to get items from
- order (opt, table): order table
returns: (function) iterator function
]=]
Wd.orderedPairs = function( array, order )
if not order then
return pairs( array )
end
-- return iterator function
local i = 0
return function()
i = i + 1
if order[ i ] then
return order[ i ], array[ order[ i ] ]
end
end
end
--[=[
return the size of the given table
parameters:
- tbl (table): table to get size of
returns: (number) number of pairs in table
]=]
Wd.getTableSize = function( tbl )
if type( tbl ) ~= "table" then
return 0
end
local count = 0
for _ in pairs( tbl ) do
count = count + 1
end
return count
end
--[=[
create a silent maintenance link
parameters:
- key (string): key to maintenance link title
returns: (boolean) link title exists or not (to record usage)
]=]
Wd.createMaintenanceLink = function( key )
if type( key ) == "string" and Wd.i18n[ "maintenance-pages" ][ key ] then
return mw.title.new( Wd.i18n[ "maintenance-pages" ][ key ], "Modul" ).exists
end
end
--[=[
get an argument of the invocation frame with options
parameters:
- frame (table): invocation frame
- key (string|number|table) argument key or table of keys
- allowEmpty (opt, boolean): if true, empty strings count as valid arguments
- default (opt, any): default value to return if argument is invalid
returns: (boolean) link title exists or not (to record usage)
]=]
Wd.getFrameArgument = function( frame, key, allowEmpty, default )
-- if frame is invalid, directly return default value
if type( frame ) ~= "table" then
return default
end
-- default allowEmpty to false
if not allowEmpty then
allowEmpty = false
end
-- get keys
local keys
if type( key ) == "string" or type( key ) == "number" then
keys = { key }
elseif type( key ) == "table" then
keys = key
end
-- get frame argument
local ret = nil
for i, v in ipairs( keys ) do
local arg = frame.args[ v ]
if arg and ( allowEmpty == true or ( allowEmpty == false and arg ~= "") ) then
ret = arg
break
end
end
-- return frame argument or default value
if ret ~= nil then
return ret
else
return default
end
end
--[=[
==============================================================================
WIKIBASE CLIENT LUA API HELPERS
==============================================================================
]=]
--[=[
check wheter the given identifier is a valid entity id, typesafe
parameters:
- id (any): entity id
returns: (bool) entity id valid or invalid
]=]
Wd.isValidEntityIdTypesafe = function( id )
return ( type( id ) == "string" and mw.wikibase.isValidEntityId( id ) )
end
--[=[
check wheter the entity with the given id exists, typesafe
parameters:
- id (any): entity id
returns: (bool) entity id exists or not
]=]
Wd.entityExistsTypesafe = function( id )
return ( Wd.isValidEntityIdTypesafe( id ) and mw.wikibase.entityExists( id ) )
end
--[=[
return the entity id of the current page if given id is invalid
parameters:
- id (string|nil): entity id
returns: (string|nil) entity id of current page or nil if page is not connected
]=]
Wd.getConnectedEntityIdIfInvalid = function( id )
if Wd.isValidEntityIdTypesafe( id ) then
return id
else
return mw.wikibase.getEntityIdForCurrentPage()
end
end
--[=[
return the entity id of the current page if given id does not exist
parameters:
- id (string|nil): entity id
returns: (string|nil) entity id of current page or nil if page is not connected
]=]
Wd.getConnectedEntityIdIfInexisting = function( id )
if Wd.entityExistsTypesafe( id ) then
return id
else
return mw.wikibase.getEntityIdForCurrentPage()
end
end
--[=[
return the entity id by the given title and site if given id does not exist
parameters:
- id (string|nil): entity id
- title (string|nil): page title
- titleSite (string|nil): site for page title, or current site
returns: (string|nil)
- if given id is existing, entity id
- if given id is inexisting and title has a connected entity on titleSite, entity id
- if given id is inexisting and title has no connected entity on titleSite, nil
- if given id is inexisting, no title was given and there is a connected entity, entity id
- if given id is inexisting, no title was given and there is no connected entity, nil
]=]
Wd.getEntityIdFromTitleIfInexisting = function( id, title, titleSite )
if Wd.entityExistsTypesafe( id ) then
-- return existing id
return id
elseif title then
-- no valid id given but title
return mw.wikibase.getEntityIdForTitle( title, titleSite )
else
-- get connected entity id
return mw.wikibase.getEntityIdForCurrentPage()
end
end
--[=[
extract the first entity id from the given string
parameters:
- text (string): input string
- etype (opt, string): entity type, "Q" for items and "P" for properties
returns: (string|nil) entity id or nil if no qid found
]=]
Wd.extractEntityId = function( text, etype )
if not etype then
etype = "Q"
end
return mw.ustring.match( text, etype .. "%d+" )
end
--[=[
==============================================================================
DATETIME HELPERS
==============================================================================
]=]
--[=[
transform date to normalized form
parameters:
- date (string): date
returns: (string) normalized date
(int) year
]=]
Wd.normalizeDate = function( date )
date = mw.text.trim( date, "+" )
-- extract year
local yearstr = mw.ustring.match( date, "^-?%d+" )
local year = tonumber( yearstr )
-- remove leading zeros of year
return year .. mw.ustring.sub( date, #yearstr + 1 ), year
end
--[=[
create date string from date
parameters:
- date (string): date string
- precision (number): date precision
- timezone (string): date timezone
- formatstr (string): formatter string for MediaWiki's formatDate function
returns: (string) date string
]=]
Wd.formatDate = function( date, precision, timezone, formatstr )
-- precisions: 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
-- standard precision is days
precision = precision or 11
-- get normalized date and year
date, year = Wd.normalizeDate( date )
-- set to first day
date = string.gsub( date, "-00%f[%D]", "-01" )
-- min year precision required, but date has no year given
if precision <= 9 and year == 0 then
return ""
end
-- precision is 10000 years or more
if precision <= 5 then
local factor = 10 ^ ( ( 5 - precision ) + 4 )
local y2 = math.ceil( math.abs( year ) / factor )
local relative = mw.ustring.format( Wd.i18n.datetime[ precision ], tostring( y2 ) )
if year < 0 then
relative = mw.ustring.format( Wd.i18n.datetime.beforenow, relative )
else
relative = mw.ustring.format( Wd.i18n.datetime.afternow, relative )
end
return relative
end
-- precision is decades, centuries and millenia
local era
if precision == 6 then
era = mw.ustring.format( Wd.i18n.datetime[ 6 ], tostring( math.floor( ( math.abs( year ) - 1 ) / 1000 ) + 1 ) )
end
if precision == 7 then
era = mw.ustring.format( Wd.i18n.datetime[ 7 ], tostring( math.floor( ( math.abs( year ) - 1 ) / 100 ) + 1 ) )
end
if precision == 8 then
era = mw.ustring.format( Wd.i18n.datetime[ 8 ], tostring( math.floor( math.abs( year ) / 10 ) * 10 ) )
end
if era then
if year < 0 then
era = mw.ustring.format( mw.ustring.gsub( Wd.i18n.datetime.bc, '"', "" ), era )
elseif year > 0 then
era = mw.ustring.format( mw.ustring.gsub( Wd.i18n.datetime.ad, '"', "" ), era )
end
return era
end
-- precision is years or less
if precision >= 9 then
if formatstr then
for i = ( precision + 1 ), 14 do
for _, ch in pairs( Wd.formatchar[ i ] ) do
if formatstr:find( ch ) then
formatstr = Wd.i18n.datetime[ precision ]
end
end
end
else
formatstr = Wd.i18n.datetime[ precision ]
end
if year == 0 then
formatstr = mw.ustring.gsub( formatstr, Wd.i18n.datetime[ 9 ], "" )
elseif year < 0 then
-- MediaWiki's formatDate doesn't support negative years
date = mw.ustring.sub( date, 2 )
formatstr = mw.ustring.gsub( formatstr, Wd.i18n.datetime[ 9 ], mw.ustring.format( Wd.i18n.datetime.bc, Wd.i18n.datetime[ 9 ] ) )
elseif year > 0 and Wd.i18n.datetime.ad ~= "%s" then
formatstr = mw.ustring.gsub( formatstr, Wd.i18n.datetime[ 9 ], mw.ustring.format( Wd.i18n.datetime.ad, Wd.i18n.datetime[ 9 ] ) )
end
return mw.language.new( Wd.wiki.langcode ):formatDate( formatstr, date )
end
-- return empty string by default
return ""
end
--[=[
split time datavalue to separated date object
parameters:
- data (table): time datavalue object
returns: (table) date object
]=]
Wd.datavalueTimeToDateObject = function( data )
-- parse timestamp
local sign, year, month, day, hour, minute, second = string.match( data.time, "(.)(%d+)%-(%d+)%-(%d+)T(%d+):(%d+):(%d+)Z" )
-- fill date object
local result = {
year = tonumber(year),
month = tonumber(month),
day = tonumber(day),
hour = tonumber(hour),
min = tonumber(minute),
sec = tonumber(second),
timezone = data.timezone,
julian = data.calendarmodel and string.match( data.calendarmodel, "Q11184$" )
}
-- handle ac/bc
if sign == "-" then
result.year = -result.year
end
return result
end
--[=[
handle julian calendar
parameters:
- dateObject (table): date object, e.g. retrieved from Wd.datavalueTimeToDateObject()
returns: (number) datetime representation
]=]
Wd.handleJulianDay = function( dateObject )
local year = dateObject.year
local month = dateObject.month or 0
local day = dateObject.day or 0
if month == 0 then
month = 1
end
if day == 0 then
day = 1
end
if month <= 2 then
year = year - 1
month = month + 12
end
local time = ( ( ( ( dateObject.sec or 0) / 60 + ( dateObject.min or 0 ) + ( dateObject.timezone or 0 ) ) / 60 ) + ( dateObject.hour or 0 ) ) / 24
local b
if dateObject.julian then
b = 0
else
local century = math.floor( year / 100 )
b = 2 - century + math.floor( century / 4 )
end
return math.floor( 365.25 * ( year + 4716 ) ) + math.floor( 30.6001 * ( month + 1 ) ) + day + time + b - 1524.5
end
--[=[
==============================================================================
SNAK RENDERERS
==============================================================================
]=]
--[=[
print datavalue type string
parameters:
- data (table): value data
- parameter (string): data parameter to return
returns: (string) parameter value
]=]
Wd.printDatavalueString = function( data, parameter )
return data
end
--[=[
print datavalue type coordinate
parameters:
- data (table): value data
latitude [double], longitude [double], altitude [double], precision [double], globe [wikidata URI, usually http://www.wikidata.org/entity/Q2 [earth]]
- parameter (string): data parameter to return
returns: (string) parameter value
]=]
Wd.printDatavalueCoordinate = function( data, parameter )
if parameter then
if parameter == "globe" then
-- extract entity id from the globe URI
data.globe = Wd.extractEntityId( data.globe )
end
return data[ parameter ]
else
-- combine latitude and longitude, which can be decomposed using the #titleparts wiki function
return data.latitude .. "/" .. data.longitude
end
end
--[=[
print datavalue type quantity
parameters:
- data (table): value data
amount [number], unit [string], upperBound [number], lowerBound [number]
- parameter (string): data parameter to return
returns: (string) parameter value
]=]
Wd.printDatavalueQuantity = function( data, parameter )
if not parameter or parameter == "amount" then
return tonumber( data.amount )
elseif parameter == "unit" then
return Wd.extractEntityId( data.unit )
else
return data[ parameter ]
end
end
--[=[
print datavalue type time
parameters:
- data (table): value data
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
- parameter (string): data parameter to return
returns: (string) parameter value
]=]
Wd.printDatavalueTime = function( data, parameter )
if parameter then
-- check if format is specified
local para, formatstr = parameter:match( "([^:]+):([^:]+)" )
if parameter == "calendarmodel" then
-- extract entity id from the calendar model URI
data.calendarmodel = Wd.extractEntityId( data.calendarmodel )
elseif para and para == "time" then
-- output formatted time string
return Wd.formatDate( data.time, data.precision, data.timezone, formatstr )
elseif parameter == "time" then
-- output standard date format
data.time = Wd.normalizeDate( data.time )
end
return data[ parameter ]
else
-- return full date
return Wd.formatDate( data.time, data.precision, data.timezone )
end
end
--[=[
print datavalue type entity
parameters:
- data (table): value data
entity-type [string], numeric-id [int, Wikidata id]
- parameter (string): data parameter to return
returns: (string) parameter value
]=]
Wd.printDatavalueEntity = function( data, parameter )
local id
-- get entity type
if data[ "entity-type" ] == "item" then
id = "Q" .. data[ "numeric-id" ]
elseif data[ "entity-type" ] == "property" then
id = "P" .. data[ "numeric-id" ]
else
-- TODO: return error object instead
return Wd.templateCallError( false, "unknown-entity-type" )
end
if parameter then
if parameter == "link" then
-- create link
local linkTarget = mw.wikibase.getSitelink( id )
local linkName = mw.wikibase.getLabel( id )
if linkTarget then
-- if there is a local Wikipedia page linking to it, use the label or the page title
local link = linkTarget
if linkName and ( linkName ~= linkTarget ) then
link = link .. "|" .. linkName
end
return "[[" .. link .. "]]"
else
-- if there is no local Wikipedia article output the label or link to the Wikidata object to input a proper label
if linkName then
return linkName
else
return "[[:d:" .. id .. "|" .. id .. "]]"
end
end
else
return data[ parameter ]
end
else
return mw.wikibase.getLabel( id ) or id
end
end
--[=[
print datavalue type monolingual text
parameters:
- data (table): value data
language [string], text [string]
- parameter (string): data parameter to return
returns: (string) parameter value
]=]
Wd.printDatavalueMonolingualText = function( data, parameter )
if parameter then
return data[ parameter ]
else
return mw.ustring.format( Wd.i18n.monolingualtext, data[ "language" ], data[ "text" ] )
end
end
--[=[
==============================================================================
CLAIMS
==============================================================================
]=]
--[=[
get the value of a snak. snaks have three types: "novalue" for null/nil,
"somevalue" for not null/not nil, or "value" for actual data
parameters:
- snak (table): snak data
- parameter (string): data parameter to return
returns: (string) rendered snak value
]=]
Wd.getSnakValue = function( snak, parameter )
if snak.snaktype == "value" then
-- define snak renderers
local snakRendererList = {
["string"] = Wd.printDatavalueString,
["globecoordinate"] = Wd.printDatavalueCoordinate,
["quantity"] = Wd.printDatavalueQuantity,
["time"] = Wd.printDatavalueTime,
["wikibase-entityid"] = Wd.printDatavalueEntity,
["monolingualtext"] = Wd.printDatavalueMonolingualText
}
-- get the respective snak renderer and call it
local snakRenderer = snakRendererList[ snak.datavalue.type ]
if snakRenderer then
return snakRenderer( snak.datavalue.value, parameter )
end
end
-- any other snak type or datavalue type
return mw.wikibase.renderSnak( snak )
end
--[=[
get the snak of the given qualifier of the claim or its mainsnak.
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
parameters:
- claim (table): claim data
- qualifierId (opt, string): qualifier to get the snak from
returns: (table|nil) snak data or nil if error
(string) error message if needed
]=]
Wd.getQualifierSnak = function( claim, qualifierId )
-- return nil if claim is invalid
if not claim then
return nil
end
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
-- TODO: return error object instead
return nil, Wd.templateCallError( false, "qualifier-not-found" )
else
-- otherwise return the main snak
return claim.mainsnak
end
end
--[=[
get the sort value of the given qualifier of the claim or its mainsnak.
parameters:
- claim (table): claim data
- qualifierId (opt, string): qualifier to get the snak from
returns: (string|nil) sort value or nil if error
]=]
Wd.getQualifierSortValue = function( claim, qualifierId )
local snak = Wd.getQualifierSnak( claim, qualifierId )
if snak and snak.snaktype == "value" then
if snak.datavalue.type == "time" then
-- use datetime representation vor time datavalue
return Wd.handleJulianDay( Wd.datavalueTimeToDateObject( snak.datavalue.value ) )
else
-- use snak value for other datavalue types
return Wd.getSnakValue( snak )
end
end
end
--[=[
get the value of the mainsnak of the claim or the value of the given qualifier
parameters:
- claim (table): claim data
- qualifierId (opt, string): qualifier to get the data from
returns: (string|nil) value or nil if error
(string) error message if needed
]=]
Wd.getClaimValue = function( claim, qualifierId, parameter )
local error
local snak
snak, error = Wd.getQualifierSnak( claim, qualifierId )
if snak then
return Wd.getSnakValue( snak, parameter )
end
return nil, error
end
--[=[
checks if a claim has the given qualifier, and optionally, with the given value
parameters:
- claim (table): claim data
- property (string): qualifier property
- value (opt, string): value of qualifier
returns: (boolean) check result
]=]
Wd.claimHasQualifier = function( claim, property, value )
local invert = false
-- allow inversion of the qualifier check
if string.sub( property, 1, 1 ) == "!" then
invert = true
property = string.sub( property, 2 )
end
-- check if claim has any qualifiers.
-- if property is empty string or literal true, check for existence of any
-- qualifiers only, without inversion - invert is always false in this case
-- so will return false in the first condition
if not claim.qualifiers then
return invert
elseif property == "" or property == "true" then
return true
end
-- check if qualifier with property exists
if not claim.qualifiers[ property ] then
return invert
end
-- if check is only for qualifier existence return true or false inverted
if not value then
return ( not invert )
end
-- check for existence of the given value
local found = false
for key, snak in pairs( claim.qualifiers[ property ] ) do
if snak.snaktype == "value" then
if snak.datavalue.type == "wikibase-entityid" then
-- wikibase id
if snak.datavalue.value.id == value then
found = true
break
end
--TODO: elseif other types
end
end
end
-- return true or false inverted
return ( found ~= invert )
end
--[=[
checks if a claim has the given source
parameters:
- claim (table): claim data
- property (string): source property
returns: (boolean) check result
]=]
Wd.claimHasSource = function( claim, property )
-- check if claim has any references.
-- if property is empty string or literal true, check for existence of any
-- references only
if not claim.references then
return false
elseif property == "" or property == "true" then
return true
end
-- allow inversion of the reference property check
local invert = false
if string.sub( property, 1, 1 ) == "!" then
invert = true
property = string.sub( property, 2 )
end
-- check for existence of the given source property
for _, source in pairs( claim.references ) do
if source.snaks[ property ] then
return ( not invert )
end
end
-- return true or false inverted
return invert
end
--[=[
checks if a claim is valid at the given date
parameters:
- claim (table): claim data
- checkdate (opt, string): date to check, or current date
returns: (boolean) check result
]=]
Wd.claimValidAtDate = function( claim, checkdate )
local refdate, checkdateyear
if not checkdate or checkdate == "" then
-- date not given, use current date
refdate = os.date( "!*t" )
checkdateyear = 0
else
-- parse given date
if string.match( checkdate, "^%d+$" ) then
-- only year given
refdate = { year = tonumber( checkdate ) }
checkdateyear = tonumber( checkdate )
else
-- exact date given
refdate = Wd.datavalueTimeToDateObject( { time = mw.language.getContentLanguage():formatDate( "+Y-m-d\\TH:i:s\\Z", checkdate ) } )
checkdateyear = 0
end
end
local refjd = Wd.handleJulianDay( refdate )
-- get date qualifiers for claim
local exactdate = Wd.getQualifierSortValue( claim, Wd.propertyId[ "pointoftime" ] )
local mindate = Wd.getQualifierSortValue( claim, Wd.propertyId[ "starttime" ] )
local maxdate = Wd.getQualifierSortValue( claim, Wd.propertyId[ "endtime" ] )
if exactdate then
-- if there is an exact date in the qualifier, and the atdate parameter
-- is on year precision, mindate is the beginning of the year and maxdate
-- is 31st Dec of that particular year
local refmaxjd
if checkdateyear > 0 then
refmaxjd = Wd.handleJulianDay( { year = tonumber( checkdate ), month = 12, day = 31 } )
else
refmaxjd = refjd
end
-- return false if exact date is out of bounds
if exactdate < refjd or exactdate > refmaxjd then
return false
end
else
-- return false if date is before mindate or after maxdate
if mindate and mindate > refjd then
return false
end
if maxdate and maxdate < refjd then
return false
end
end
-- success, the claim was valid at "checkdate"
return true
end
--[=[
checks if a claim is not deprecated
parameters:
- claim (table): claim data
returns: (boolean) check result
]=]
Wd.claimNotDeprecated = function( claim )
return claim.rank ~= "deprecated"
end
--[=[
return a table of claims excluding claims not passed the filters
parameters:
- frame (table): call arguments
- claims (table): claims to filter
returns: (table) filtered claim table
]=]
Wd.filterClaims = function( frame, claims )
-- subfunction that calls the check functions and does the filtering
-- parameters:
-- - condition (string): call argument that contains the filter condition
-- - filterfunction (function): check function for the condition
local function filter( condition, filterfunction )
-- if condition not found in call arguments, do nothing
if not frame.args[ condition ] then
return
end
-- filter claim table
local newclaims = {}
for i, claim in pairs( claims ) do
-- call filter function and check for result
if filterfunction( claim, frame.args[ condition ] ) then
table.insert( newclaims, claim )
end
end
claims = newclaims
end
-- call available filters
filter( "hasqualifier", Wd.claimHasQualifier )
filter( "hassource", Wd.claimHasSource )
filter( "atdate", Wd.claimValidAtDate )
if not frame.args.includedeprecated then
frame.args.notdeprecated = true
filter( "notdeprecated", Wd.claimNotDeprecated )
end
-- use additional unnamed parameters as qualifier conditions (in pairs)
for key in pairs( frame.args ) do
if type( key ) == "number" and key > 2 and key % 2 == 1 then
-- key = 3, 5, 7 and so on
local newclaims = {}
local values = frame.args[ key ]
-- allow inversion of values
local invert = string.sub( values, 1, 1 ) == "!"
if invert then
values = string.sub( values, 2 )
end
-- filter claims
for i, claim in pairs( claims ) do
local hasvalue = false
for val in mw.text.gsplit( values, "," ) do
-- check if qualifier has current value
if Wd.claimHasQualifier( claim, frame.args[ key - 1 ], val ) then
hasvalue = true
break
end
end
if hasvalue ~= invert then
table.insert( newclaims, claim )
end
end
-- replace claims table
claims = newclaims
end
end
-- return filtered claim table
return claims
end
--[=[
convert single reference to its string representation
parameters:
- ref (table): ref data
returns: (string|nil) reference text or nil if error
]=]
Wd.formatReference = function( ref )
-- "imported from"-references are useless, skip them:
if ref[ "P143" ] or ref[ "P4656" ] then
return nil
end
-- load [[Modul:Zitation]]
local ZitationSuccess, r = pcall( require, "Modul:Zitation" )
if type( r ) == "table" then
Zitation = r.Zitation()
-- clear Zitation state from previous invocations
Zitation.o = nil
end
-- assert (ZitationSuccess, Wd.i18n["errors"]["module-not-loaded"])
-- assignments of Wikidata properties to Zitation parameters
local wdZmap = {
P1433 = { "bas", "Werk" },
P248 = { "bas", "Werk" },
P1476 = { "bas", "Titel" },
P1680 = { "bas", "TitelErg" },
P407 = { "bas", "Sprache" },
P364 = { "bas", "Sprache" },
P2439 = { "bas", "Sprache" },
P123 = { "bas", "Verlag" },
P577 = { "bas", "Datum" },
P98 = { "bas", "Hrsg" },
P2093 = { "bas", "Autor" },
P50 = { "bas", "Autor" },
P1683 = { "bas", "Zitat" },
P854 = { "www", "URL" },
P813 = { "www", "Abruf" },
P1065 = { "www", "ArchivURL" },
P2960 = { "www", "ArchivDatum" },
P2701 = { "www", "Format" },
P393 = { "print", "Auflage" },
P291 = { "print", "Ort" },
P304 = { "fragment", "Seiten" },
P792 = { "fragment", "Kapitel" },
P629 = { "orig", "Titel" }
}
for prop, value in pairs( ref ) do
if wdZmap[ prop ] then
if type( value ) == "table" then
-- more snaks with same property, we concatenate using a comma
value = table.concat( value, ", " )
end
-- value should be string now, so we can call Zitation
if type( value ) == "string" and string.len( value ) > 0 then
Zitation.fill( wdZmap[ prop ][ 1 ], wdZmap[ prop ][ 2 ], value, prop )
end
end
end
-- if no title on Wikidata, try to use the URL as title
if ( not ref[ "P1476" ] ) and ref[ "P854" ] then
local URLutil = Zitation.fetch( "URLutil" )
Zitation.fill( "bas", "Titel", URLutil.getHost( ref[ "P854" ] ) )
end
return Zitation.format()
end
--[=[
return references of the given claim as reference string
parameters:
- frame (table): invocation frame
- claim (table): claim data
returns: (string) reference text
]=]
Wd.getReferences = function( frame, claim )
local result = ""
-- loop through all references
for ref in pairs( claim.references or {} ) do
-- put snaks to table for later formatting with Wd.formatReference()
local refTable = {}
for snakkey, snakval in Wd.orderedPairs( claim.references[ ref ].snaks or {}, claim.references[ ref ][ "snaks-order" ] ) do
if #snakval == 1 then
-- only one value in snak
refTable[ snakkey ] = Wd.getSnakValue( snakval[ 1 ] )
else
-- multiple values in snak
local multival = {}
for snakidx = 1, #snakval do
table.insert( multival, Wd.getSnakValue( snakval[ snakidx ] ) )
end
refTable[ snakkey ] = multival
end
end
-- format reference with data in refTable
local formattedRef, f = Wd.formatReference( refTable )
if formattedRef and formattedRef ~= "" then
-- reference formatting successful, create hash from text to avoid double refs
local hash = mw.hash.hashValue( "fnv164", formattedRef )
-- output reference
result = result .. frame:extensionTag( "ref", formattedRef, { name = "_" .. hash } )
end
end
return result
end
--[=[
checks whether a certain item is a parent of a given item. A parent is
connected via P31 or P279. Attention: very intensive function, use carefully!
parameters:
- item (string|number): start item
- parent (string): parent item
- exitItem (string): item to exit check at
- maxDepth (number): maximum search depth
- depth (opt, number): current search depth
returns: (boolean) check result
]=]
Wd.isParent = function( item, parent, exitItem, maxDepth, depth )
-- increment call number
Wd.numberIsParentCalls = Wd.numberIsParentCalls + 1
-- initial depth is zero
if not depth then
depth = 0
end
-- cast start item number to string
if type( item ) == "number" then
item = "Q" .. item
end
-- check if start entity exists
if not Wd.entityExistsTypesafe( item ) then
return false
end
-- get entity
local entity = mw.wikibase.getEntity( item )
if not entity then
return false
end
-- if entity has no claims, end check
if not entity.claims then
return false
end
-- resolve property ids
local claims31 = mw.wikibase.resolvePropertyId( "P31" )
local claims279 = mw.wikibase.resolvePropertyId( "P279" )
if not claims31 or not claims279 then
return false
end
-- get connector claims, if both don't exist end check
claims31 = entity.claims[ claims31 ]
claims279 = entity.claims[ claims279 ]
if not claims31 and not claims279 then
return false
end
-- retrieve parent entity ids
local parentIds = {}
if claims31 and #claims31 > 0 then
for i, v in ipairs( claims31 ) do
parentIds[ #parentIds + 1] = Wd.getSnakValue( v.mainsnak, "numeric-id" )
end
end
if claims279 and #claims279 > 0 then
for i, v in ipairs( claims279 ) do
parentIds[ #parentIds + 1 ] = Wd.getSnakValue( v.mainsnak, "numeric-id" )
end
end
-- if no parent ids found, end check
if not parentIds[ 1 ] or #parentIds == 0 then
return false
end
-- check if searched parent or exit item is reached or do recursive call
local itemString = ""
local result = nil
for i, v in ipairs( parentIds ) do
-- create item string and check if it is valid
itemString = "Q" .. v
if not Wd.isValidEntityIdTypesafe( itemString ) then
return false
end
if itemString == parent then
-- parent item found
return true
elseif itemString == exitItem or itemString == "Q35120" then
-- exit if either exit item or node item "entity" (Q35120) is reached
return false
else
-- resursive call on parents if within maxDepth bounds
if depth + 1 < maxDepth then
result = Wd.isParent( itemString, parent, exitItem, maxDepth, depth + 1 )
else
return false
end
-- return true if recursive call returned true
if result == true then
return result
end
end
end
-- return false
do return false end
end
--[=[
==============================================================================
ENTITY PROPERTIES
==============================================================================
]=]
--[=[
return the badges of the given entity for the given site
parameters (frame):
- id (opt, string): entity id
- title (opt, string): title of a local page that is connected to the entity
- titleSite (opt, string): site name to look for title, or current site
- site (opt, string): site name, or current site
One of id and title has to be specified. id takes precedence over title.
returns:
- (boolean) success indicator
- (table|boolean) badges list if successful or error object
]=]
Wd.getBadges = function( id, title, titleSite, site )
-- determine and validate entity id
id = Wd.getEntityIdFromTitleIfInexisting( id, title, titleSite )
if not Wd.entityExistsTypesafe( id ) then
-- entity not found
return false, Wd.newError( "entity-not-found", id )
end
-- if site is nil, the badges of the current wiki will be returned
return true, mw.wikibase.getBadges( id, site ) or false
end
--[=[
return the description of a Wikidata entity in the given language or the default language of this Wikipedia site
parameters:
- id (opt, string): entity id
- title (opt, string): title of a local page that is connected to the entity
- titleSite (opt, string): site name to look for title, or current site
- langcode (opt, string): language code, or language code of current site
- noFallback (opt, boolean): if true, suppress language fallbacks
One of id and title has to be specified. id takes precedence over title.
returns:
- (boolean) success indicator
- (string|boolean|table) description text if successful or error object
]=]
Wd.getDescription = function( id, title, titleSite, langcode, noFallback )
-- determine and validate entity id
id = Wd.getEntityIdFromTitleIfInexisting( id, title, titleSite )
if not Wd.entityExistsTypesafe( id ) then
-- entity not found
return false, Wd.newError( "entity-not-found", id )
end
-- get description
if noFallback then
-- in given language or wiki language without fallbacks
return true, mw.wikibase.getDescriptionByLang( id, langcode or Wd.wiki.langcode ) or false
elseif not langcode then
-- in wiki language with fallbacks
return true, mw.wikibase.getDescription( id ) or false
else
-- in given language with fallbacks
local entity = mw.wikibase.getEntity( id )
if entity then
return true, entity:getDescription( langcode ) or false
else
return false, Wd.newError( "entity-not-found", id )
end
end
end
--[=[
return the label of a Wikidata entity in the given language or the default language of this Wikipedia site
parameters:
- id (opt, string): entity id
- title (opt, string): title of a local page that is connected to the entity
- titleSite (opt, string): site name to look for title, or current site
- langcode (opt, string): language code, or language code of current site
- noFallback (opt, boolean): if true, suppress language fallbacks
One of id and title has to be specified. id takes precedence over title.
returns:
- (boolean) success indicator
- (string|boolean|table) label text if successful or error object
]=]
Wd.getLabel = function( id, title, titleSite, langcode, noFallback )
-- determine and validate entity id
id = Wd.getEntityIdFromTitleIfInexisting( id, title, titleSite )
if not Wd.entityExistsTypesafe( id ) then
-- entity not found
return false, Wd.newError( "entity-not-found", id )
end
-- get label
if noFallback then
-- in given language or wiki language without fallbacks
return true, mw.wikibase.getLabelByLang( id, langcode or Wd.wiki.langcode ) or false
elseif not langcode then
-- in wiki language with fallbacks
return true, mw.wikibase.getLabel( id ) or false
else
-- in given language with fallbacks
local entity = mw.wikibase.getEntity( id )
if entity then
return true, entity:getLabel( langcode ) or false
else
return false, Wd.newError( "entity-not-found", id )
end
end
end
--[=[
return the entity id of the current page, or check the given entity id
for redirects and return the redirect target, if existing
parameters:
- id (opt, string): entity id
- title (opt, string): title of a local page that is connected to the entity
- titleSite (opt, string): site name to look for title, or current site
One of id and title has to be specified. id takes precedence over title.
returns:
- (boolean) success indicator
- (string|boolean|table) page id if successful or error object
]=]
Wd.getPageId = function( id, title, titleSite )
-- determine page id
if Wd.entityExistsTypesafe( id ) then
-- get the given entity to check for redirects
local entity = mw.wikibase.getEntity( id )
if entity then
id = entity:getId()
else
return false, Wd.newError( "entity-not-found", id )
end
elseif title then
id = mw.wikibase.getEntityIdForTitle( title, titleSite )
else
id = mw.wikibase.getEntityIdForCurrentPage()
end
-- return determined id or false if id not found
return true, id or false
end
--[=[
return the sitelink name of the given entity on the given site.
parameters:
- id (opt, string): entity id
- title (opt, string): title of a local page that is connected to the entity
- titleSite (opt, string): site name to look for title, or current site
- site (opt, string): site name, or current site
One of id and title has to be specified. id takes precedence over title.
returns:
- (boolean) success indicator
- (string|boolean|table) sitelink if successful or error object
]=]
Wd.getSitelink = function( id, title, titleSite, site )
-- determine and validate entity id
id = Wd.getEntityIdFromTitleIfInexisting( id, title, titleSite )
if not Wd.entityExistsTypesafe( id ) then
-- entity not found
return false, Wd.newError( "entity-not-found", id )
end
-- if site is nil, the sitelink to the current wiki will be returned
return true, mw.wikibase.getSitelink( id, site ) or false
end
--[=[
return the number of sitelinks in the given entity.
parameters:
- id (opt, string): entity id
- title (opt, string): title of a local page that is connected to the entity
- titleSite (opt, string): site name to look for title, or current site
- filter (opt, string): filter regexp
One of id and title has to be specified. id takes precedence over title.
returns:
- (boolean) success indicator
- (number|table) sitelink count if successful or error object
]=]
Wd.getSitelinkCount = function( id, title, titleSite, filter )
-- determine and validate entity id
id = Wd.getEntityIdFromTitleIfInexisting( id, title, titleSite )
if not Wd.entityExistsTypesafe( id ) then
-- entity not found
return false, Wd.newError( "entity-not-found", id )
end
-- get entity
local entity = mw.wikibase.getEntity( id )
if not entity then
return false, Wd.newError( "entity-not-found", id )
end
-- create filter regexp
if filter then
filter = "^.*" .. filter .. "$"
else
filter = false
end
-- count sitelinks
local count = 0
if entity.sitelinks then
if filter == false then
count = Wd.getTableSize( entity.sitelinks )
else
for project, _ in pairs( entity.sitelinks ) do
if string.find( project, filter ) then
count = count + 1
end
end
end
end
return true, count
end
--[=[
==============================================================================
TEMPLATE EXPORT
==============================================================================
]=]
-- export table
local p = {}
--[=[
checks whether a certain item is a subclass of a given item.
parameters (frame):
- id (string): start item
- parent (string): parent item
- exitItem (string): item to exit check at
- maxDepth (opt, string): maximum search depth
- returnInt (opt, string): if set, return 1 or empty instead of true/false
returns: (boolean|number) check result in
]=]
p.isSubclass = function( frame )
local result
-- check for validity of start and parent item
if Wd.entityExistsTypesafe( frame.args[ "id" ] ) and Wd.entityExistsTypesafe( frame.args[ "parent" ] ) then
-- check if id and parent are same
if frame.args[ "id" ] ~= frame.args[ "parent" ] then
-- set maximum depth
local maxDepth
maxDepth = tonumber( frame.args[ "maxDepth" ] ) or 5
-- getParent() call
result = Wd.isParent( frame.args[ "id" ], frame.args[ "parent" ], frame.args[ "exitItem" ], maxDepth)
-- mw.log(Wd.numberIsParentCalls) --uncomment to load number of isParent() calls into log
else
result = true
end
else
result = false
end
-- return result
if frame.args[ "returnInt" ] then
if result == true then
return 1
else
return ""
end
else
if result then
return result
else
return false
end
end
end
--[=[
get a claim
parameters (frame):
- 1 (string): property of claim
- id (string): entity id
- qualifier (string): qualifier to return
- parameter (string): value parameter to return
- language (string): value language to return
- countValues (string): return number of results instead of returning the actual result
- list (string): concatenate all results with the given separator
- listMaxItems (string): maximum items to list
- includeempty (string): also include empty values
- references (string): return also references, if "only", return references only
- sort (string): sort results
- sortEmptiesFirst (string): sort empty values first
- sortInItem (string): sort based on property value in given item
- inverse (string): inverse sorting order
- showerrors (string): show errors instead of returning empty string
- default (string): default return value if empty or error
returns: (string) claim or empty or error
]=]
p.claim = function( frame )
-- (A) PARAMETER ASSIGNMENTS --
local property = frame.args[ 1 ] or ""
local id = frame.args[ "id" ]
local qualifierId = frame.args[ "qualifier" ]
local parameter = frame.args[ "parameter" ]
local language = frame.args[ "language" ]
local countValues = frame.args[ "countValues" ]
local list = frame.args[ "list" ]
local includeempty = frame.args[ "includeempty" ]
local listMaxItems = tonumber( frame.args[ "listMaxItems" ] ) or 0
local references = frame.args[ "references" ]
local sort = frame.args[ "sort" ]
local sortEmptiesFirst = frame.args[ "sortEmptiesFirst" ]
local sortInItem = frame.args[ "sortInItem" ]
local inverse = frame.args[ "inverse" ]
local showerrors = frame.args[ "showerrors" ]
local default = frame.args[ "default" ]
-- don't show errors if default value is set
if default then
showerrors = nil
end
-- (B) VALIDITY CHECKS --
-- get wikidata entity
if id then
if not Wd.isValidEntityIdTypesafe( id ) then
-- invalid entity id
if showerrors then
return Wd.templateCallError( frame, "entity-not-valid" )
else
Wd.createMaintenanceLink( false, "entity-not-valid" )
return default
end
elseif not Wd.entityExistsTypesafe( id ) then
-- entity id does not exist
if showerrors then
return Wd.templateCallError( frame, "entity-not-found" )
else
-- create maintenance link
Wd.createMaintenanceLink( "entity-not-found" )
return default
end
end
end
-- get entity object
local entity = mw.wikibase.getEntity( id )
if not entity then
if showerrors then
return Wd.templateCallError( frame, "entity-not-found" )
else
return default
end
end
-- check if property exists
local realProp = mw.wikibase.resolvePropertyId( property )
if not realProp then
Wd.createMaintenanceLink( "property-not-found" )
end
-- fetch the first claim satisfying the given property
local claims
if entity.claims then
claims = entity.claims[ realProp ]
end
if not claims or not claims[ 1 ] then
if countValues then
return 0
elseif showerrors then
return Wd.templateCallError( frame, "property-not-found" )
else
return default
end
end
-- (C) FILTERING AND SORTING --
-- filter claims
claims = Wd.filterClaims( frame, claims )
if not claims[ 1 ] then
if countValues then
return 0
else
return default
end
end
-- get initial sort indices
local sortindices = {}
for idx in pairs( claims ) do
sortindices[ #sortindices + 1 ] = idx
end
-- get comparator for sorting
local comparator
if sort then
-- comparator function for sorting statements based on qualifier value
comparator = function( a, b )
-- load qualifier values
local qualSortValA = Wd.getQualifierSortValue( claims[ a ], sort )
local qualSortValB = Wd.getQualifierSortValue( claims[ b ], sort )
-- if either of the two statements does not have this qualifer:
---- if sortEmptiesFirst=true: sort it to the beginning
---- else: always sort it to the end
if not qualSortValB then
if not qualSortValA then
-- if neither of the two statements has this qualifier, arbitrarily but consistently return a < b
return a < b
else
-- true if sortEmptiesFirst is false
return ( not sortEmptiesFirst )
end
elseif not qualSortValA then
-- true if sortEmptiesFirst is not false
return ( not not sortEmptiesFirst )
end
if type( qualSortValA ) ~= type( qualSortValB ) and not ( tonumber( qualSortValA ) and tonumber( qualSortValB ) ) then
if tonumber( qualSortValA ) then
return true
elseif tonumber( qualSortValB ) then
return false
elseif tostring( qualSortValA ) and tostring( qualSortValB ) then
if inverse then
return tostring( qualSortValA ) > tostring( qualSortValB )
else
return tostring( qualSortValA ) < tostring( qualSortValB )
end
else
-- different types, neither numbers nor strings, no chance to compare => random result to avoid script error
return false
end
elseif tonumber( qualSortValA ) and tonumber( qualSortValB ) then
qualSortValA = tonumber( qualSortValA )
qualSortValB = tonumber( qualSortValB )
end
if inverse then
return qualSortValA > qualSortValB
else
return qualSortValA < qualSortValB
end
end
elseif sortInItem then
-- get sortkeys of claims in referenced entity and given property
local sortkeys = {}
local snakSingle
local claimContainingValue
local claimContainingProperty
local claimContainingEntity
-- check if given property is valid
claimContainingProperty = mw.wikibase.resolvePropertyId( sortInItem )
if not claimContainingProperty then
if showerrors then
return Wd.templateCallError( frame, "property-not-found" )
else
return default
end
end
-- loop trough all claims and retrieve the sortkeys
for idx, claim in pairs( claims ) do
-- get referenced entity
snakSingle = Wd.getQualifierSnak( claim )
claimContainingEntity = "Q" .. Wd.getSnakValue( snakSingle, "numeric-id" )
-- get value if entity exists and has the property
if Wd.entityExistsTypesafe( claimContainingEntity ) then
claimContainingEntity = mw.wikibase.getEntity( claimContainingEntity )
if claimContainingEntity and claimContainingEntity.claims and claimContainingEntity.claims[ claimContainingProperty ] then
claimContainingValue = claimContainingEntity.claims[ claimContainingProperty ]
end
end
-- use value as sortkey, or empty string if no property value found
if claimContainingValue then
sortkeys[ #sortkeys + 1 ] = Wd.getClaimValue( claimContainingValue[ 1 ] )
else
sortkeys[ #sortkeys + 1 ] = ""
end
end
-- comparator function based on retrieved sortkeys
comparator = function( a, b )
if inverse then
return sortkeys[ a ] > sortkeys[ b ]
else
return sortkeys[ a ] < sortkeys[ b ]
end
end
else
-- sort by claim rank
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
end
-- use comparator to sort indices table
table.sort( sortindices, comparator )
-- (D) RETURN VALUE --
local result
local error
if countValues then
-- return claim count
result = Wd.getTableSize( claims )
elseif list then
-- list claims
-- if a newline is provided (whose backslash will be escaped) unescape it
list = string.gsub( list, "\\n", "\n" )
-- loop through all elements and return their value (if existing)
local value
result = {}
for idx in pairs( claims ) do
local claim = claims[ sortindices[ idx ] ]
-- get claim value and handle result
value, error = Wd.getClaimValue( claim, qualifierId, parameter )
if not value then
if showerrors then
value = error
end
if includeempty then
-- overwrite error to empty string
value = ""
end
end
-- add references
if value and references then
value = value .. Wd.getReferences( frame, claim )
end
-- add to result list
result[ #result + 1 ] = value
end
-- concat result table to string
if listMaxItems and listMaxItems > 0 then
-- return until maximum results is reached
result = table.concat( result, list, 1, math.min( #result, listMaxItems ) )
else
-- return everything
result = table.concat( result, list )
end
else
-- return first element only
local claim = claims[ sortindices[ 1 ] ]
-- get value with language support
if language and claim.mainsnak.datatype == "monolingualtext" then
-- iterate over claims to find adequate language
for idx, claim in pairs( claims ) do
if claim.mainsnak.datavalue.value.language == language then
result, error = Wd.getClaimValue( claim, qualifierId, parameter )
break
end
end
else
-- no language given, get claim value
result, error = Wd.getClaimValue( claim, qualifierId, parameter )
end
-- handle references
if references == "only" then
-- only return references
result = Wd.getReferences( frame, claim )
elseif result and references then
-- add references
result = result .. Wd.getReferences( frame, claim )
end
end
-- return result
if result then
return result
else
if showerrors then
return error
else
return default
end
end
end
--[=[
returns the given value or runs claim() if keyword is found
parameters (frame):
- 2 (opt, string): value to return or keyword
returns: (string) value or return of claim()
]=]
p.getValue = function( frame )
local param = frame.args[ 2 ]
if param == "FETCH_WIKIDATA" or param == Wd.i18n["FETCH_WIKIDATA"] then
return p.claim( frame )
else
return param
end
end
--[=[
return the badges of the given entity for the given site
parameters (frame):
- id (opt, string): entity id, or entity id of current page
- title (opt, string): page name to retrieve entity id from
- titleSite (opt, string): sitename to title
- site (opt, string): site id, or current site
id takes precedence over title.
returns: (string) badges
]=]
p.badges = function( frame )
local id = Wd.getFrameArgument( frame, "id" )
local title = Wd.getFrameArgument( frame, "title" )
local titleSite = Wd.getFrameArgument( frame, "titleSite" )
local site = Wd.getFrameArgument( frame, "site" )
-- get badges, site is allowed to be nil
local success, result = Wd.getBadges( id, title, titleSite, site )
if not success then
return Wd.templateCallError( frame, Wd.parseError( result ) )
elseif type( result ) == "table" then
-- concatenate all badges with "/" delimiter for usage with #titleparts
return table.concat( result, "/" )
end
-- return empty string by default
return ""
end
--[=[
return description of a Wikidata entity in the given language or the default language of this Wikipedia site
parameters (frame):
- id (opt, string): entity id
- title (opt, string): page name to retrieve entity id from
- titleSite (opt, string): sitename to title
- language (opt, string): language code
- noFallback (opt, string): suppress language fallbacks
id takes precedence over title.
returns: (string) description text or empty string
]=]
p.descriptionIn = function( frame )
local id = Wd.getFrameArgument( frame, "id" )
local title = Wd.getFrameArgument( frame, "title" )
local titleSite = Wd.getFrameArgument( frame, "titleSite" )
local langcode = Wd.getFrameArgument( frame, "language" )
local noFallback = Wd.getFrameArgument( frame, "noFallback" )
-- get the description
local success, result = Wd.getDescription( id, title, titleSite, langcode, noFallback )
if not success then
return Wd.templateCallError( frame, Wd.parseError( result ) )
else
return result or ""
end
end
--[=[
return label of a Wikidata entity in the given language or the default language of this Wikipedia site
parameters (frame):
- id (opt, string): entity id
- title (opt, string): page name to retrieve entity id from
- titleSite (opt, string): sitename to title
- language (opt, string): language code
- noFallback (opt, string): suppress language fallbacks
id takes precedence over title.
returns: (string) label text or empty string
]=]
p.labelIn = function( frame )
local id = Wd.getFrameArgument( frame, "id" )
local title = Wd.getFrameArgument( frame, "title" )
local titleSite = Wd.getFrameArgument( frame, "titleSite" )
local langcode = Wd.getFrameArgument( frame, "language" )
local noFallback = Wd.getFrameArgument( frame, "noFallback" )
-- get the label
local success, result = Wd.getLabel( id, title, titleSite, langcode, noFallback )
if not success then
return Wd.templateCallError( frame, Wd.parseError( result ) )
else
return result or ""
end
end
--[=[
[DEPRECTAED] return the label of the given entity or property id
parameters (frame):
- 1 (opt, string): entity id, or entity id of current page
returns: (string) error text
]=]
p.labelOf = function( frame )
-- soft-deprecate labelOf in favor of labelIn
return Wd.templateCallError( frame, "deprecated-function", "labelOf" )
end
--[=[
return the entity id of the current page, or check the given entity id
for redirects and return the redirect target, if existing
parameters (frame):
- id (opt, string): entity id
- title (opt, string): page name to retrieve entity id from
- titleSite (opt, string): sitename to title
id takes precedence over title.
returns: (string) entity id or empty string
]=]
p.pageId = function( frame )
local id = Wd.getFrameArgument( frame, "id" )
local title = Wd.getFrameArgument( frame, "title" )
local titleSite = Wd.getFrameArgument( frame, "titleSite" )
-- get the id
local success, result = Wd.getPageId( id, title, titleSite )
if not success then
return Wd.templateCallError( frame, Wd.parseError( result ) )
else
return result or ""
end
end
--[=[
return the number of sitelinks in the given entity
parameters (frame):
- id (opt, string): entity id, or entity id of current page
- title (opt, string): page name to retrieve entity id from
- titleSite (opt, string): sitename to title
- filter (opt, string): sitelink filter for projects
id takes precedence over title.
returns: (number) sitelink count
]=]
p.sitelinkCount = function( frame )
local id = Wd.getFrameArgument( frame, "id" )
local title = Wd.getFrameArgument( frame, "title" )
local titleSite = Wd.getFrameArgument( frame, "titleSite" )
local filter = Wd.getFrameArgument( frame, "filter" )
-- get the sitelink count
local success, result = Wd.getSitelinkCount( id, title, titleSite, filter )
if not success then
return Wd.templateCallError( frame, Wd.parseError( result ) )
else
return result or ""
end
end
--[=[
return the Wikipedia page name of the given entity on the given site.
parameters (frame):
- id (opt, string): entity id, or entity id of current page
- title (opt, string): page name to retrieve entity id from
- titleSite (opt, string): sitename to title
- site (opt, string): site name, or current site
id takes precedence over title.
returns: (string) page name, error text or empty string
]=]
p.sitelinkOf = function( frame )
local id = Wd.getFrameArgument( frame, "id" )
local title = Wd.getFrameArgument( frame, "title" )
local titleSite = Wd.getFrameArgument( frame, "titleSite" )
local site = Wd.getFrameArgument( frame, "site" )
-- get the sitelink
local success, result = Wd.getSitelink( id, title, titleSite, site )
if not success then
return Wd.templateCallError( frame, Wd.parseError( result ) )
else
return result or ""
end
end
--[=[
==============================================================================
DEBUGGING
==============================================================================
]=]
--[=[
call this in cases of script errors within a function:
instead of {{#invoke:Wikidata|<method>|...}} call {{#invoke:Wikidata|debug|<method>|...}}
parameters (frame):
- (...) call parameters of function to debug
returns: (...) return value of function to debug
]=]
p.debug = function( frame )
-- get function name
local func = frame.args[ 1 ]
if not func then
return Wd.templateCallError( frame, "invalid-parameters" )
end
-- create new parameter set, where the first parameter with the function name is removed
local newargs = {}
for key, val in pairs( frame.args ) do
if type( key ) == "number" then
-- skip first unnamed param
if key > 1 then
newargs[ key - 1 ] = val
end
else
newargs[ key ] = val
end
end
-- replace frame args and call the given function
frame.args = newargs
local status, result = pcall( p[ func ], frame )
-- output return value or state
if status then
return result
else
return mw.ustring.format( "<span class=\"error\">%s</span>", result )
end
end
--[=[
print the content of an entity
parameters (frame):
- 1 (opt, string): entity id, or entity id of current page
returns: (string) entity json content
]=]
p.printEntity = function( frame )
local id = Wd.getConnectedEntityIdIfInexisting( frame.args[ 1 ] );
if id then
-- get entity and dump it
local entity = mw.wikibase.getEntity( id )
if entity then
return mw.ustring.format( "<pre>%s</pre>", mw.dumpObject( entity ) )
end
end
-- return empty string by default
return ""
end
--[=[
==============================================================================
COORDINATE TEMPLATE HELPERS
==============================================================================
]=]
-- formfill Template:Coordinate (NS, EW, name from WikidataEntity) and expand it
-- füllt Vorlage:Coordinate (NS, EW, name mit Wikidata-Werten) + expandiert sie
-- 1st frame.arg .. Q prefixed entity id (mandatory)
-- named frame.arg "type", "region", "text" .. see doc of 'Coordinate' template
p.ffCoordinate = function(frame)
local f = frame
local id = f.args[1] or f.args.Q
local name = f.args.name or p.labelIn{ args = { nil, id, id = id }}
local coord = mw.text.split(p.claim{ args = { "P625", id, id = id }}, "/")
coord[1] = tonumber(coord[1])
coord[2] = tonumber(coord[2])
local t, r = f.args.type, f.args.region
if not t
then t = p.claim{ args = { "P31", id, id = id, parameter = "numeric-id", default = "" }}
if t and t ~= "" then
t = "Q" .. t
t = t:gsub("Q.*", {
Q8502 = "mountain",
Q54050 = "landmark"
})
end
if not t or t and t:find("Q", 1, true)
then t="" -- no default, let Coordinate warn about unset type= param
end
end
if not r
then r = p.claim{ args = { "P17", id, id = id, parameter = "numeric-id", default = "" }}
if r and r ~= "" then
r = "Q" .. r
r = p.claim{ args = { "P297", r, id = r }}
else
r="" -- no default, let Coordinate warn about unset region= param
end
end
return ('<span data-sort-value="%010.6f"></span>'):format((f.args.sortkey
or "EW"):find("EW", 1, true) and coord[2]+360.0 or coord[1]+180.0
) .. f:expandTemplate{ title = "Coordinate", args = {
NS = coord[1], EW = coord[2], type = t, region = r,
text = f.args.text or (f.args.maplink and "ICON0" or "/"),
name = name, simple = f.args.simple
}} .. (not f.args.maplink and "" or (" " ..
--f:callParserFunction{ name="#statements", args={ "P625", from = id } }
f:callParserFunction{ name="#tag:maplink", args={ "",
class = "no-icon", text = f.args.mlname and name,
zoom = 12, latitude = coord[1], longitude = coord[2]
}}
))
end
p.ffCoordinateAndLatLonMaplink = function(frame)
frame.args.maplink = 1
--frame.args.mlname = nil
return p.ffCoordinate(frame)
end
p.ffCoordinateAndMaplink = function(frame)
frame.args.maplink = 1
frame.args.mlname = 1
return p.ffCoordinate(frame)
end
return p
Content Disclaimer
Informasi ini disarikan dari Wikipedia dan disajikan kembali untuk tujuan edukasi. Konten tersedia di bawah lisensi CC BY-SA 3.0. Kami tidak bertanggung jawab atas ketidakakuratan data yang bersumber dari kontribusi publik tersebut.
- The information displayed on this website is sourced in part or in whole from Wikipedia and has been adapted for the purpose of restating it. We strive to provide accurate and relevant information, however:
- There is no guarantee of absolute accuracy. Wikipedia is an open, collaborative project that can be edited by anyone, so information is subject to change.
- It is not intended to constitute professional advice. The content displayed is for informational and educational purposes only. For important decisions (e.g., medical, legal, or financial), please consult a professional.
- Content copyright. Wikipedia is licensed under the Creative Commons Attribution-ShareAlike License (CC BY-SA). This means that content may be reused with appropriate attribution and shared under a similar license.
- Responsible use. Any risk arising from the use of information from this website is entirely the responsibility of the user.