« Module:Wikidata/Analyse transitive » : différence entre les versions
Nouvelle page : -- Helpers for queries using transitive properties local p = {} local wd = require "Module:Wikidata" local function getids(item, query) query.excludespecial = true query.displ... |
m A changé le niveau de protection pour « Module:Wikidata/Analyse transitive » ([Modifier=Autoriser uniquement les utilisateurs autopatrolled] (infini) [Renommer=Autoriser uniquement les administrateurs] (infini)) |
||
| (16 versions intermédiaires par le même utilisateur non affichées) | |||
| Ligne 3 : | Ligne 3 : | ||
local p = {} | local p = {} | ||
local wd = require "Module:Wikidata" | local wd = require "Module:Wikidata" | ||
local tools = require "Module:Wikidata/Outils" | |||
local function getids(item, query) | local function getids(item, query) | ||
query.excludespecial = true | query.excludespecial = true | ||
query.displayformat = 'raw' | query.displayformat = 'raw' | ||
| Ligne 11 : | Ligne 12 : | ||
end | end | ||
-- add new items to a list, avoiding duplicates | -- add new items to a list, avoiding duplicates | ||
local function addnewvalues(olditems, newitems) | local function addnewvalues(olditems, newitems, maxnum, stopval) | ||
if not newitems then | if not newitems then | ||
return olditems | return olditems | ||
end | end | ||
for _, qid in pairs(newitems) do | for _, qid in pairs(newitems) do | ||
if not | if stopval and (qid == stopval) then | ||
table.insert(olditems, qid) | |||
return olditems | |||
end | |||
if maxnum and (#olditems >= maxnum) then | |||
return olditems | |||
end | |||
if not tools.isHere(olditems, qid) then | |||
table.insert(olditems, qid) | table.insert(olditems, qid) | ||
end | end | ||
| Ligne 33 : | Ligne 33 : | ||
end | end | ||
-- recursively adds a list of qid to an existing list, based on the results of a query | -- recursively adds a list of qid to an existing list, based on the results of a query | ||
function p.addVals(list, query, maxdepth, maxnodes, stopval) | |||
maxdepth = maxdepth or 10 | maxdepth = tonumber(maxdepth) or 10 | ||
maxnodes = maxnodes or 100 | maxnodes = tonumber(maxnodes) or 100 | ||
if (maxdepth < 0) then | if (maxdepth < 0) then | ||
return | return list | ||
end | end | ||
if stopval and tools.isHere(list, stopval) then | |||
return list | |||
end | end | ||
local origsize = #list | |||
for i, | for i = 1, origsize do | ||
local candidates = getids( | -- tried a "checkpos" param instead of starting to 1 each time, but no impact on performance | ||
list = addnewvalues(list, candidates) | local candidates = getids(list[i], query) | ||
list = addnewvalues(list, candidates, maxnodes, stopval) | |||
if list[#list] == stopval then | |||
return list | |||
end | |||
if #list >= maxnodes then | if #list >= maxnodes then | ||
return list | return list | ||
end | end | ||
end | end | ||
if (#list == | if (#list == origsize) then | ||
return list | return list | ||
end | end | ||
return | return p.addVals(list, query, maxdepth - 1, maxnodes, stopval, origsize + 1) | ||
end | end | ||
-- returns a list of items transitively matching a query | -- returns a list of items transitively matching a query (orig item is not included in the list) | ||
function p.transitiveVals(item, query, maxdepth, maxnodes) | function p.transitiveVals(item, query, maxdepth, maxnodes, stopval, astring) | ||
maxdepth = tonumber(maxdepth) or 5 | |||
if type(query) == "string" then | |||
query = {property = query} | |||
end | |||
-- récupération des valeurs | |||
local vals = getids(item, query) | local vals = getids(item, query) | ||
if not vals then | if not vals then | ||
return nil | return nil | ||
end | end | ||
local v = p.addVals(vals, query, maxdepth - 1, maxnodes, stopval) | |||
if not v then | |||
return nil | |||
end | |||
-- réarrangement des valeurs | |||
if query.valorder == "inverted" then | |||
local a = {} | |||
for i, j in pairs(v) do | |||
table.insert(a, 1, j) | |||
end | |||
v = a | |||
end | |||
-- mise en forme | |||
-- soit sous forme de chaîne | |||
if astring and (astring ~= "-") then | |||
for i, j in pairs(v) do | |||
v[i] = wd.formatEntity(j) | |||
-- il faudrait avoir les optins de mise en forme wd.formatEntity(j, query) mais getids ajoute displayformat = "raw", il faudrait faire d'abord une copie de la table query | |||
end | |||
return wd.tableToText(v, query) | |||
end | |||
--- soit sous forme de table | |||
return v | |||
end | end | ||
-- returns true if an item is the value of a query, transitively | -- returns true if an item is the value of a query, transitively | ||
function p. | function p.inTransitiveVals(searchedval, sourceval, query, maxdepth, maxnodes ) | ||
local vals = p.transitiveVals(sourceval, query, maxdepth, maxnodes, searchedval ) | |||
if vals and vals[#vals] == searchedval then | |||
local | |||
if | |||
return true | return true | ||
end | end | ||
return false | return false | ||
| Ligne 102 : | Ligne 112 : | ||
-- returns true if an item is a superclass of another, based on P279 | -- returns true if an item is a superclass of another, based on P279 | ||
function p.isSubclass(class, item, maxdepth) | function p.isSubclass(class, item, maxdepth) | ||
query = {property = 'P279'} | local query = {property = 'P279'} | ||
if class == item then -- item is a subclass of itself iff it is a class | if class == item then -- item is a subclass of itself iff it is a class | ||
if getids(item, query) then | if getids(item, query) then | ||
| Ligne 109 : | Ligne 119 : | ||
return false | return false | ||
end | end | ||
return p. | return p.inTransitiveVals(class, item, query, maxdepth ) | ||
end | end | ||
| Ligne 119 : | Ligne 129 : | ||
if not directclasses then | if not directclasses then | ||
return false | return false | ||
end | end | ||
for i, class in pairs(directclasses) do | for i, class in pairs(directclasses) do | ||
if p.isSubclass(targetclass, class, maxdepth - 1) then | if p.isSubclass(targetclass, class, maxdepth - 1) then | ||
| Ligne 127 : | Ligne 137 : | ||
return false | return false | ||
end | end | ||
-- return the first value in a transitive query that belongs to a particular class. For instance find a value of P131 that is a province of Canada | |||
function p.findVal(sourceitem, targetclass, query, recursion, instancedepth) | |||
if type(query) == "string" then | |||
query = {property = query} | |||
end | |||
local candidates = getids(sourceitem, query) | |||
if candidates then | |||
for i, j in pairs(candidates) do | |||
if p.isInstance(targetclass, j, instancedepth) then | |||
return j | |||
end | |||
end | |||
if not recursion then | |||
recursion = 3 | |||
else | |||
recursion = recursion - 1 | |||
end | |||
if recursion < 0 then | |||
return nil | |||
end | |||
for i, candidate in pairs(candidates) do | |||
return p.findVal(candidate, targetclass, query, recursion, instancedepth) | |||
end | |||
end | |||
end | |||
return p | return p | ||
Dernière version du 17 mai 2017 à 13:47
-- Helpers for queries using transitive properties
local p = {} local wd = require "Module:Wikidata" local tools = require "Module:Wikidata/Outils"
local function getids(item, query) query.excludespecial = true query.displayformat = 'raw' query.entity = item return wd.stringTable(query) end
-- add new items to a list, avoiding duplicates
local function addnewvalues(olditems, newitems, maxnum, stopval)
if not newitems then
return olditems
end
for _, qid in pairs(newitems) do
if stopval and (qid == stopval) then
table.insert(olditems, qid)
return olditems
end
if maxnum and (#olditems >= maxnum) then
return olditems
end
if not tools.isHere(olditems, qid) then
table.insert(olditems, qid)
end
end
return olditems
end
-- recursively adds a list of qid to an existing list, based on the results of a query function p.addVals(list, query, maxdepth, maxnodes, stopval) maxdepth = tonumber(maxdepth) or 10 maxnodes = tonumber(maxnodes) or 100 if (maxdepth < 0) then return list end if stopval and tools.isHere(list, stopval) then return list end local origsize = #list for i = 1, origsize do -- tried a "checkpos" param instead of starting to 1 each time, but no impact on performance local candidates = getids(list[i], query) list = addnewvalues(list, candidates, maxnodes, stopval) if list[#list] == stopval then return list end if #list >= maxnodes then return list end end if (#list == origsize) then return list end return p.addVals(list, query, maxdepth - 1, maxnodes, stopval, origsize + 1) end
-- returns a list of items transitively matching a query (orig item is not included in the list) function p.transitiveVals(item, query, maxdepth, maxnodes, stopval, astring)
maxdepth = tonumber(maxdepth) or 5 if type(query) == "string" then query = {property = query} end
-- récupération des valeurs local vals = getids(item, query) if not vals then return nil end local v = p.addVals(vals, query, maxdepth - 1, maxnodes, stopval) if not v then return nil end
-- réarrangement des valeurs if query.valorder == "inverted" then local a = {} for i, j in pairs(v) do table.insert(a, 1, j) end v = a end
-- mise en forme
-- soit sous forme de chaîne
if astring and (astring ~= "-") then for i, j in pairs(v) do v[i] = wd.formatEntity(j) -- il faudrait avoir les optins de mise en forme wd.formatEntity(j, query) mais getids ajoute displayformat = "raw", il faudrait faire d'abord une copie de la table query end return wd.tableToText(v, query) end --- soit sous forme de table return v end
-- returns true if an item is the value of a query, transitively function p.inTransitiveVals(searchedval, sourceval, query, maxdepth, maxnodes ) local vals = p.transitiveVals(sourceval, query, maxdepth, maxnodes, searchedval ) if vals and vals[#vals] == searchedval then return true end return false end
-- returns true if an item is a superclass of another, based on P279 function p.isSubclass(class, item, maxdepth) local query = {property = 'P279'} if class == item then -- item is a subclass of itself iff it is a class if getids(item, query) then return true end return false end return p.inTransitiveVals(class, item, query, maxdepth ) end
-- returns true if one of the best ranked P31 values of an item is the target or a subclass of the target -- rank = 'valid' would seem to make sense, but it would need to check for date qualifiers as some P31 values have begin or end date function p.isInstance(targetclass, item, maxdepth) maxdepth = maxdepth or 10 local directclasses = p.transitiveVals(item, {property = 'P31'}, 1) if not directclasses then return false end for i, class in pairs(directclasses) do if p.isSubclass(targetclass, class, maxdepth - 1) then return true end end return false end
-- return the first value in a transitive query that belongs to a particular class. For instance find a value of P131 that is a province of Canada function p.findVal(sourceitem, targetclass, query, recursion, instancedepth) if type(query) == "string" then query = {property = query} end local candidates = getids(sourceitem, query) if candidates then for i, j in pairs(candidates) do if p.isInstance(targetclass, j, instancedepth) then return j end end if not recursion then recursion = 3 else recursion = recursion - 1 end if recursion < 0 then return nil end for i, candidate in pairs(candidates) do return p.findVal(candidate, targetclass, query, recursion, instancedepth) end end end
return p