Module:Wikidata/Filterers
Εμφάνιση
Τεκμηρίωση module[δημιουργία] [ανανέωση]
--require "Module:No globals"
local p = {}
local lib = require 'Module:Wikidata/lib'
local function in_array(value, array)
for _, val in ipairs(array) do
if val == value then
return true
end
end
return false
end
local function checkLimit(array, limit)
local limit = limit and tonumber(limit)
if limit then
return #array >= limit
end
return true
end
local function applyLimit(array, limit)
local limit = limit and tonumber(limit)
while limit and #array > limit do
table.remove(array)
end
end
local function IsInLanguage(snak, langs)
local langs = lib.textToTable(langs)
if snak.datatype ~= 'monolingualtext' then
return error(lib.raiseInvalidDatatype('IsInLanguage', snak.datatype, 'monolingualtext'))
else
return lib.IsSnakValue(snak) and in_array(snak.datavalue.value.language, langs)
end
end
local function filterSnaktype(snak, somevalue, novalue)
local snaktype = snak.snaktype
if snaktype == 'somevalue' then
return somevalue or false
elseif snaktype == 'novalue' then
return novalue or false
end
return lib.IsSnakValue(snak)
end
local function filterBySnaktype(statement, somevalue, novalue)
return filterSnaktype(statement.mainsnak, somevalue, novalue)
end
local function hasSnakTarget(snak, target)
local Formatters = require 'Module:Wikidata/Formatters'
return tostring(Formatters.getRawValue(snak)) == target
end
local function filterHasTarget(statement, target)
return hasSnakTarget(statement.mainsnak, target)
end
local function filterHasQualifier(statement, prop, value)
if statement.qualifiers then
prop = prop:upper()
for _, snak in ipairs(statement.qualifiers[prop] or {}) do
if not value or hasSnakTarget(snak, value) then
return true
end
end
end
return false
end
local function filterHasRanks(statement, ranks)
return in_array(statement.rank, ranks)
end
local function filterHasReferences(statement, options)
if statement.references then
if #p.filterReferences(statement.references, options) > 0 then
return true
end
end
return false
end
local function filterSnakHasLabel(snak)
local datatype = snak.datatype
if datatype ~= 'wikibase-item' and datatype ~= 'wikibase-property' then
return error(lib.raiseInvalidDatatype('filterSnakHasLabel', datatype, { 'wikibase-item', 'wikibase-property' }))
end
if lib.IsSnakValue(snak) then
local langs = { 'cs', 'el', 'en' }
local Formatters = require 'Module:Wikidata/Formatters'
if lib.getLabelInLanguage(Formatters.getRawValue(snak), langs) then
return true
end
end
return false
end
local function filterHasLabel(statement)
return filterSnakHasLabel(statement.mainsnak)
end
local function filterItemIsInstance(statement, options)
local datatype = statement.mainsnak.datatype
if datatype ~= 'wikibase-item' and datatype ~= 'wikibase-property' then
return error(lib.raiseInvalidDatatype('filterItemIsInstance', datatype, { 'wikibase-item', 'wikibase-property' }))
end
if lib.IsSnakValue(statement.mainsnak) then
local Module = require 'Module:Wikidata/Tree'
local Formatters = require 'Module:Wikidata/Formatters'
local item = Formatters.getRawValue(statement.mainsnak)
if Module.IsInstance(item, options) then
return true
end
end
return false
end
local function filterMainsnakInLanguage(statement, withlang)
return IsInLanguage(statement.mainsnak, withlang)
end
local function filterMainsnakHasUnit(statement, unit)
local datatype = statement.mainsnak.datatype
if datatype ~= 'quantity' then
return error(lib.raiseInvalidDatatype('filterItemIsInstance', datatype, { 'quantity' }))
end
return lib.IsSnakValue(statement.mainsnak) and lib.getItemIdFromURI(statement.mainsnak.datavalue.value.unit) == unit
end
local function filter(array, callback, ...)
local i = #array
while i > 0 do
if not callback(array[i], ...) then
table.remove(array, i)
end
i = i - 1
end
end
local function getValuesFromQualifiers(qualifiers)
local Values = {}
local Formatters = require 'Module:Wikidata/Formatters'
for key, array in pairs(lib.props) do
for _, prop in ipairs(array) do
for _, snak in ipairs(qualifiers[prop] or {}) do
if lib.IsSnakValue(snak) then
Values[key] = Formatters.getRawValue(snak)
break
end
end
end
end
return Values
end
function p.filterStatementsFromEntity(entity, options)
if not options.property or options.property == '' then
return error(lib.formatError('param-not-provided', 'property'))
end
if not entity or not entity.claims then
return {}
end
local property = mw.ustring.upper(options.property)
local statements = mw.clone(entity.claims[property])
if not statements then
return {}
end
p.filterStatements(statements, options)
return statements
end
function p.filterStatements(statements, options)
local options = lib.common.cleanArgs(options)
-- apply filter by rank
local rank = options.rank or "valid"
if rank ~= "all" then
if rank == "valid" or rank == "best" then
filter(statements, filterHasRanks, { "normal", "preferred" })
if rank == "best" and #statements > 0 then
for _, statement in ipairs(statements) do
if statement.rank == "preferred" then
filter(statements, filterHasRanks, { "preferred" })
break
end
end
end
else
filter(statements, filterHasRanks, { rank })
end
if #statements == 0 then return end
end
-- apply filter by source
if options.ref then
filter(statements, filterHasReferences, options)
if #statements == 0 then return end
end
-- apply filter by snak type
filter(statements, filterBySnaktype, options.somevalue and true, options.novalue and true)
if #statements == 0 then return end
-- apply filter by target value
if options.withtarget then
filter(statements, filterHasTarget, options.withtarget)
if #statements == 0 then return end
end
-- apply filter by qualifier property
if options.withqualifier then
filter(statements, filterHasQualifier, options.withqualifier, options.withqualifiervalue)
if #statements == 0 then return end
end
-- apply filter by language
if options.withlang then
filter(statements, filterMainsnakInLanguage, options.withlang)
if #statements == 0 then return end
end
-- apply filter by unit
if options.withunit then
filter(statements, filterMainsnakHasUnit, options.withunit)
if #statements == 0 then return end
end
-- apply filter by time
if options.date then
local date
local Time = require 'Module:Time'
if type(options.date) == 'table' then
date = options.date
elseif options.date == '#now' then
date = Time.new(os.date('!*t'))
else
date = Time.newFromIso8601(options.date)
end
if not date then
return error(lib.formatError('invalid-date', tostring(options.date)))
end
local oldStatements = mw.clone(statements)
while #statements > 0 do table.remove(statements) end
for _, statement in ipairs(oldStatements) do
local Values = getValuesFromQualifiers(statement.qualifiers or {})
if Values.point then
if date == Values.point then
filter(statements, function(st)
local val = getValuesFromQualifiers(st.qualifiers).point
if val then
return val == Values.point
end
return true
end)
table.insert(statements, statement)
elseif Values.point < date then
if #statements == 0 then
table.insert(statements, statement)
else
local same, ins
for _, st in ipairs(statements) do
local val = getValuesFromQualifiers(st.qualifiers).point
if val then
if date == Values.point then
same = true
break
end
if val == Values.point or val < Values.point then
ins = true
end
end
end
if ins and not same then
filter(statements, function(st)
local val = getValuesFromQualifiers(st.qualifiers).point
return not val or val == Values.point
end)
table.insert(statements, statement)
end
end
end
else
if Values.begin then
if Values.begin < date then
if not Values.ending then
table.insert(statements, statement)
elseif date < Values.ending then
table.insert(statements, statement)
end
end
elseif Values.ending then
if date < Values.ending then
if not Values.begin then
table.insert(statements, statement)
elseif Values.begin < date then
table.insert(statements, statement)
end
end
end
end
end
if #statements == 0 then return end
end
if lib.IsOptionTrue(options, 'withlabel') then
filter(statements, filterHasLabel)
if #statements == 0 then return end
end
-- apply filter by class
if options.instance then
filter(statements, filterItemIsInstance, options)
if #statements == 0 then return end
end
-- sort statements if needed
if options.sort then -- patří to sem?
local Sorters = require 'Module:Wikidata/Sorters'
Sorters.sortStatements(statements, options)
end
-- apply filter by limit
applyLimit(statements, options.limit)
end
function p.filterQualifiers(qualifiers, options)
local options = lib.common.cleanArgs(options)
filter(qualifiers, filterSnaktype, options['qualifiers somevalue'] and true, options['qualifiers novalue'] and true)
if #qualifiers == 0 then return end
if options['qualifiers withlang'] then
filter(qualifiers, IsInLanguage, options['qualifiers withlang'])
if #qualifiers == 0 then return end
end
if lib.IsOptionTrue(options, 'qualifiers withlabel') then
filter(qualifiers, filterSnakHasLabel)
if #qualifiers == 0 then return end
end
if options['qualifiers class'] then
--[[ todo
local datatype = Qualifiers[math.random(#Qualifiers)].datatype
if datatype == 'wikibase-item' or datatype == 'wikibase-property' then
oldQualifiers, Qualifiers = Qualifiers, {}
local Module = require 'Module:Wikidata/Tree'
local Formatters = require 'Module:Wikidata/Formatters'
for _, snak in ipairs(oldQualifiers) do
if lib.IsSnakValue(snak) then
local item = Formatters.getRawValue(snak)
if Module.IsInTree(item, options['qualifiers class'], 'P279', 20, {}) then
table.insert(Qualifiers, snak)
end
end
end
if #Qualifiers == 0 then return {} end
else
return error(lib.raiseInvalidDatatype('inClass', datatype, { 'wikibase-item', 'wikibase-property' }))
end
]]--
end
if options['qualifiers sort'] then
local Sorters = require 'Module:Wikidata/Sorters'
Sorters.sortQualifiers(qualifiers, options)
end
applyLimit(qualifiers, options['qualifiers limit'])
end
function p.filterReferences(references, options)
local options = lib.common.cleanArgs(options)
if options.ref == '#any' then
-- @deprecated
return references
end
local oldReferences, References = references, {}
if options.ref == 'valid' then
local map = (require 'Module:Wikidata/cite').props
for _, ref in ipairs(oldReferences) do
for _, props in pairs(map) do
for _, prop in ipairs(props) do
if ref.snaks[prop] then
table.insert(References, ref)
end
end
end
end
end
if options.min_ref and not checkLimit(References, options.min_ref) then
return {}
end
-- @deprecated
return References
end
return p