<?xml version="1.0"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="fr">
	<id>https://wiki.noethoumy.fr/index.php?action=history&amp;feed=atom&amp;title=Module%3AWikidata%2FChemin</id>
	<title>Module:Wikidata/Chemin - Historique des versions</title>
	<link rel="self" type="application/atom+xml" href="https://wiki.noethoumy.fr/index.php?action=history&amp;feed=atom&amp;title=Module%3AWikidata%2FChemin"/>
	<link rel="alternate" type="text/html" href="https://wiki.noethoumy.fr/index.php?title=Module:Wikidata/Chemin&amp;action=history"/>
	<updated>2026-04-27T17:01:03Z</updated>
	<subtitle>Historique des versions pour cette page sur le wiki</subtitle>
	<generator>MediaWiki 1.41.1</generator>
	<entry>
		<id>https://wiki.noethoumy.fr/index.php?title=Module:Wikidata/Chemin&amp;diff=340&amp;oldid=prev</id>
		<title>Jaggerwock : Page créée avec « local datastructure = require &quot;Module:Wikidata/Chemin/Path&quot; local parser = require &quot;Module:Wikidata/Chemin/parser&quot; local results = require &quot;Module:Wikidata/Chemin/Resultat&quot;  local iter = require &quot;Module:Iterateurs&quot; local props = require &quot;Module:Propriétés&quot;  local path = {}  -------------- -- TODO :  --        * Update the &quot;between&quot; path to handle it better epsilon paths --        * Test full path rendering --        *  --------------  -- Definition of a Propert... »</title>
		<link rel="alternate" type="text/html" href="https://wiki.noethoumy.fr/index.php?title=Module:Wikidata/Chemin&amp;diff=340&amp;oldid=prev"/>
		<updated>2024-09-20T14:20:22Z</updated>

		<summary type="html">&lt;p&gt;Page créée avec « local datastructure = require &amp;quot;Module:Wikidata/Chemin/Path&amp;quot; local parser = require &amp;quot;Module:Wikidata/Chemin/parser&amp;quot; local results = require &amp;quot;Module:Wikidata/Chemin/Resultat&amp;quot;  local iter = require &amp;quot;Module:Iterateurs&amp;quot; local props = require &amp;quot;Module:Propriétés&amp;quot;  local path = {}  -------------- -- TODO :  --        * Update the &amp;quot;between&amp;quot; path to handle it better epsilon paths --        * Test full path rendering --        *  --------------  -- Definition of a Propert... »&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Nouvelle page&lt;/b&gt;&lt;/p&gt;&lt;div&gt;local datastructure = require &amp;quot;Module:Wikidata/Chemin/Path&amp;quot;&lt;br /&gt;
local parser = require &amp;quot;Module:Wikidata/Chemin/parser&amp;quot;&lt;br /&gt;
local results = require &amp;quot;Module:Wikidata/Chemin/Resultat&amp;quot;&lt;br /&gt;
&lt;br /&gt;
local iter = require &amp;quot;Module:Iterateurs&amp;quot;&lt;br /&gt;
local props = require &amp;quot;Module:Propriétés&amp;quot;&lt;br /&gt;
&lt;br /&gt;
local path = {}&lt;br /&gt;
&lt;br /&gt;
--------------&lt;br /&gt;
-- TODO : &lt;br /&gt;
--        * Update the &amp;quot;between&amp;quot; path to handle it better epsilon paths&lt;br /&gt;
--        * Test full path rendering&lt;br /&gt;
--        * &lt;br /&gt;
--------------&lt;br /&gt;
&lt;br /&gt;
-- Definition of a PropertyPath class&lt;br /&gt;
&lt;br /&gt;
local PropertyPath = {}&lt;br /&gt;
PropertyPath.__index = PropertyPath&lt;br /&gt;
&lt;br /&gt;
--[[ Datastructure for the paths that will match a path pattern&lt;br /&gt;
A path matching the pattern &amp;quot;subclass of*&amp;quot; will be a chain of statements and snaks nodes.  &lt;br /&gt;
If we got statements of the form (no qualifiers here, just subject with the main statement snak) :&lt;br /&gt;
* &amp;lt;human&amp;gt; &amp;lt;subclass of&amp;gt; &amp;lt;ape&amp;gt;&lt;br /&gt;
* &amp;lt;ape&amp;gt; &amp;lt;subclass of&amp;gt; &amp;lt;mammal&amp;gt;&lt;br /&gt;
* &amp;lt;mammal&amp;gt; &amp;lt;subclass of&amp;gt; &amp;lt;animal&amp;gt;&lt;br /&gt;
&lt;br /&gt;
a matching path like &amp;quot;&amp;lt;human&amp;gt; -&amp;gt; &amp;lt;ape&amp;gt; -&amp;gt; &amp;lt;mammal&amp;gt; -&amp;gt; &amp;lt;animal&amp;gt;&amp;quot; will be reprensented by a linked list of &amp;quot;ResultNode&amp;quot; objects. &lt;br /&gt;
A result node object is a mw.wikibase &amp;quot;statement&amp;quot; standard object augmented with a few methods and a link that goes from the statement or snak to the previous node in the path.&lt;br /&gt;
{ &lt;br /&gt;
   &amp;lt;mammal&amp;gt; &amp;lt;subclass of&amp;gt; &amp;lt;animal&amp;gt;&lt;br /&gt;
   &amp;quot;parent&amp;quot; = {&lt;br /&gt;
      &amp;lt;ape&amp;gt; &amp;lt;subclass of&amp;gt; &amp;lt;mammal&amp;gt;&lt;br /&gt;
      &amp;quot;parent&amp;quot; = {&lt;br /&gt;
         &amp;lt;human&amp;gt; &amp;lt;subclass of&amp;gt; &amp;lt;ape&amp;gt;&lt;br /&gt;
         &amp;quot;parent&amp;quot; = EpsilonRNode(&amp;lt;human&amp;gt;, &amp;quot;parent&amp;quot; = nil)&lt;br /&gt;
      }&lt;br /&gt;
   }&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
--]]&lt;br /&gt;
&lt;br /&gt;
local ResultNode = results.ResultNode&lt;br /&gt;
local StatementRNode = results.StatementRNode&lt;br /&gt;
local QualifierRNode = results.QualifierRNode&lt;br /&gt;
local EpsilonRNode = results.EpsilonRNode&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
------------------------------------------------------------------------------------------------------&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
local function iterate_on_snaks(&lt;br /&gt;
	start_rnode, &lt;br /&gt;
	property_filter_criteria, &lt;br /&gt;
	snak_map_iterator,&lt;br /&gt;
	rnode_type)&lt;br /&gt;
    assert(snak_map_iterator)&lt;br /&gt;
	return iter.pair_map(&lt;br /&gt;
    	iter.flatten(&lt;br /&gt;
    		iter.select_vals(&lt;br /&gt;
    			iter.pair_filter(&lt;br /&gt;
    				snak_map_iterator, &lt;br /&gt;
    				property_filter_criteria&lt;br /&gt;
    			)&lt;br /&gt;
    		),&lt;br /&gt;
    		iter.on_vals&lt;br /&gt;
    	),&lt;br /&gt;
    	function(value) return rnode_type:create(value, start_rnode) end&lt;br /&gt;
    )&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- creates an iterator that will iterate over all the statements&lt;br /&gt;
-- of a specific property of an item&lt;br /&gt;
&lt;br /&gt;
local function iterate_on_statement(start_rnode, property_filter_criteria)&lt;br /&gt;
	local item = mw.wikibase.getEntity(start_rnode:item_value())&lt;br /&gt;
	return iterate_on_snaks(&lt;br /&gt;
		start_rnode, &lt;br /&gt;
		property_filter_criteria,&lt;br /&gt;
		iter.on_pairs(item.claims),&lt;br /&gt;
		StatementRNode&lt;br /&gt;
	)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function iterate_on_statement_qualifier(statement, qualifier_filter_criteria)&lt;br /&gt;
	if statement.qualifiers then&lt;br /&gt;
		return iterate_on_snaks(&lt;br /&gt;
			statement, &lt;br /&gt;
			 qualifier_filter_criteria,&lt;br /&gt;
			iter.on_pairs(statement.qualifiers),&lt;br /&gt;
			QualifierRNode&lt;br /&gt;
		)&lt;br /&gt;
	else&lt;br /&gt;
		-- no qualifier table when the statement has no qualifiers&lt;br /&gt;
		return function() return nil end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local iterate_on_statement_from_property = function(start_rnode, pid)&lt;br /&gt;
    local claims = mw.wikibase.getBestStatements(&lt;br /&gt;
    	start_rnode:item_value(),&lt;br /&gt;
      	props.normalize(pid)&lt;br /&gt;
    ) or {}&lt;br /&gt;
	&lt;br /&gt;
    return iter.pair_map(&lt;br /&gt;
    	iter.pair_filter(iter.on_pairs(claims), function(key, val) return true end),&lt;br /&gt;
    	function(key, value) return StatementRNode:create(value, start_rnode) end&lt;br /&gt;
    )&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
local function iterate_on_star(start_rnode, child_pnode, depth, iterated, max)&lt;br /&gt;
	&lt;br /&gt;
	-- start_rnode : the result node from which we will iterate&lt;br /&gt;
	-- child_pnode : the path within the star operator (for example P31/P31 if our node is (P31/P31)*&lt;br /&gt;
	iterated = iterated or {} -- iterated is the store of already iterated starting points items to avoid infinite loops&lt;br /&gt;
	-- max : the max number of iteration depth to go, nil for no limit&lt;br /&gt;
	&lt;br /&gt;
	depth = depth or 1&lt;br /&gt;
	&lt;br /&gt;
	--[[&lt;br /&gt;
	In pseudo code using a « yield » operator, the algorithm would be&lt;br /&gt;
	&lt;br /&gt;
	algo star(startnode)&lt;br /&gt;
	   for each value v which match child_pnode from startnode&lt;br /&gt;
	      yield v&lt;br /&gt;
	      for each value vchild in star(v)&lt;br /&gt;
	         yield vchild&lt;br /&gt;
	      end for&lt;br /&gt;
	   end &lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	But we can’t use a yield operator if the « coroutine » module on lua is not activated. &lt;br /&gt;
	So we must translate this into something more complicated.&lt;br /&gt;
	&lt;br /&gt;
	Luckily the approach to write iterators in term of composition seems to pay off and&lt;br /&gt;
	it seem possible to write code structurally similar to this algorithm thanks to the &lt;br /&gt;
	« flatten » iterator and a recursive closure that creates iterator to handle the&lt;br /&gt;
	recursivity implied by the « star » operator nature.&lt;br /&gt;
&lt;br /&gt;
	--]]&lt;br /&gt;
	&lt;br /&gt;
	function creator()&lt;br /&gt;
		return function(start_rnode)&lt;br /&gt;
			local depth_overflow = not (not max or depth &amp;lt; max)&lt;br /&gt;
			&lt;br /&gt;
			if not iterated[start_rnode:item_value()] and not depth_overflow then&lt;br /&gt;
				iterated[start_rnode:item_value()] = true&lt;br /&gt;
				return iterate_on_star(start_rnode, child_pnode, depth + 1, iterated, max)&lt;br /&gt;
			else&lt;br /&gt;
				return function() end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
		&lt;br /&gt;
	return iter.chain(&lt;br /&gt;
		iter.singleton(start_rnode),&lt;br /&gt;
		iter.flatten(&lt;br /&gt;
			child_pnode:iterate(start_rnode), &lt;br /&gt;
			creator()&lt;br /&gt;
		)&lt;br /&gt;
	)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local iterate_on_plus = function(start_rnode, child_pnode, max_depth)&lt;br /&gt;
	local first = true&lt;br /&gt;
	iterated = iterated or {}&lt;br /&gt;
	&lt;br /&gt;
	return iter.flatten(&lt;br /&gt;
		child_pnode:iterate(start_rnode),&lt;br /&gt;
		function(rnode)&lt;br /&gt;
			return iterate_on_star(rnode, child_pnode, 1, iterated, max_depth)&lt;br /&gt;
		end&lt;br /&gt;
	)&lt;br /&gt;
&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
Test :&lt;br /&gt;
p.test(&amp;quot;Q5&amp;quot;, &amp;quot;subclass of+&amp;quot;) -- at the time writing, &amp;quot;Q215627&amp;quot; is the only direct superclass of human. It does not show up, but there is numerous superclass in the result&lt;br /&gt;
--]]&lt;br /&gt;
&lt;br /&gt;
--[[ an iteraton to handle &amp;quot;/&amp;quot; operator sequences, for example « P31/P279* »&lt;br /&gt;
 &amp;quot;creators&amp;quot; is a table of functions that needs to create iterators of child nodes.&lt;br /&gt;
 In our example, the first cretors element will be a function that takes an item object and&lt;br /&gt;
   will return an iterator over P31-statements of this item&lt;br /&gt;
 the second one will create an iterator over the path « P279* » and so on.&lt;br /&gt;
 The resulting iteratior will iterate on each elements of the second iterator starting from each iterator over the second one&lt;br /&gt;
 for each elements in the first one.&lt;br /&gt;
--]]&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
local function iterate_on_iterator_creators(start_rnode, creators, i)&lt;br /&gt;
	i = i or 1&lt;br /&gt;
	if not(tonumber(i)) then i = 1 end&lt;br /&gt;
	-- main iterator : the iterator that will iterate on the values on this node of the path&lt;br /&gt;
	local main_iterator = creators[i]:iterate(start_rnode)&lt;br /&gt;
	&lt;br /&gt;
	if i &amp;lt; #creators then&lt;br /&gt;
		--trying to initialize the iterator for the next node with a value of the current one, if we can&lt;br /&gt;
		local rnode = main_iterator()&lt;br /&gt;
		&lt;br /&gt;
		while rnode and not(rnode:has_an_item()) do&lt;br /&gt;
			rnode = main_iterator()&lt;br /&gt;
		end&lt;br /&gt;
&lt;br /&gt;
		-- could not initialize the next iterator with a proper item ; returnun the empty iterator function&lt;br /&gt;
		if not rnode then return function() return end end&lt;br /&gt;
		&lt;br /&gt;
		-- we found a proper value to iterate on for the next node in the path&lt;br /&gt;
		&lt;br /&gt;
		-- final iterator : the iterator that will iterate &lt;br /&gt;
		-- on elems that will be returned by each iterations &lt;br /&gt;
		-- on the iterator created by the main client&lt;br /&gt;
		&lt;br /&gt;
		local final_iterator = iterate_on_iterator_creators(rnode, creators, i+1)&lt;br /&gt;
		return function()&lt;br /&gt;
			while final_iterator ~= nil do&lt;br /&gt;
				-- pulling the element from the next node iterator in the sequence&lt;br /&gt;
				local final_elem = final_iterator()&lt;br /&gt;
				if final_elem then&lt;br /&gt;
					return final_elem&lt;br /&gt;
				else&lt;br /&gt;
					-- we pulled the last elem for this value, getting a new value &lt;br /&gt;
					-- for this node path and regenerate the next node iterator to pull new final values&lt;br /&gt;
					&lt;br /&gt;
					local rnode_value = main_iterator()&lt;br /&gt;
					&lt;br /&gt;
					-- return the element pulled from the next node iterator&lt;br /&gt;
					-- if the property has item datatype is not a special value and has the right snaktype&lt;br /&gt;
					-- as we can&amp;#039;t continue path on other kind of values&lt;br /&gt;
					&lt;br /&gt;
					if rnode_value then&lt;br /&gt;
						if rnode_value:has_an_item() then&lt;br /&gt;
							final_iterator = iterate_on_iterator_creators(rnode_value, creators, i+1)&lt;br /&gt;
						end&lt;br /&gt;
					else&lt;br /&gt;
						--we&amp;#039;re over, no next value for this node to continue the path&lt;br /&gt;
						return&lt;br /&gt;
					end&lt;br /&gt;
				end&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	elseif i == #creators then&lt;br /&gt;
		return main_iterator&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[ JSBach : Q1339 ;&lt;br /&gt;
Testing with :&lt;br /&gt;
test(&amp;quot;Q1339&amp;quot;, &amp;quot;child/child&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
wikidata query equivalent query : &lt;br /&gt;
select ?grandchild where {&lt;br /&gt;
  wd:Q1339 wdt:P40/wdt:P40 ?grandchild&lt;br /&gt;
}&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
Adam : wd:Q70899 &lt;br /&gt;
test(&amp;quot;Q70899&amp;quot;, &amp;quot;child/child/child&amp;quot;)&lt;br /&gt;
wikidata query equivalent query : &lt;br /&gt;
select ?grandgrandchild where {&lt;br /&gt;
  wd:Q70899 wdt:P40/wdt:P40/wdt:P40 ?grandgrandchild&lt;br /&gt;
}&lt;br /&gt;
--]]&lt;br /&gt;
&lt;br /&gt;
local iterate_on_alternatives = function(start_rnode, pnodes)&lt;br /&gt;
	local i=1&lt;br /&gt;
	local current_iter = pnodes[i]:iterate(start_rnode)&lt;br /&gt;
	&lt;br /&gt;
    return function ()&lt;br /&gt;
    	-- loop to go to next iterator if there is empty one in the list&lt;br /&gt;
        while true do&lt;br /&gt;
	        local res = current_iter()&lt;br /&gt;
	        -- res is an iterator itself ; getting its result&lt;br /&gt;
	        if res then&lt;br /&gt;
	        	return res&lt;br /&gt;
	        else&lt;br /&gt;
	        	i = i + 1&lt;br /&gt;
	        	if i &amp;lt;= #pnodes then &lt;br /&gt;
	        		-- following to next iterator and resume loop&lt;br /&gt;
	        		current_iter = pnodes[i]:iterate(start_rnode)&lt;br /&gt;
	        	else&lt;br /&gt;
	        		-- no current iterator : ending&lt;br /&gt;
	        		return nil&lt;br /&gt;
	        	end&lt;br /&gt;
	        end&lt;br /&gt;
        end&lt;br /&gt;
    end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
Adam&amp;#039;s father or mother : no value of course&lt;br /&gt;
p.test(&amp;#039;Q70899&amp;#039;, &amp;quot;P22|P25&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
JS Bach&amp;#039;s&lt;br /&gt;
p.test(&amp;quot;Q1339&amp;quot;, &amp;quot;P22|P25&amp;quot;)&lt;br /&gt;
&lt;br /&gt;
--]]&lt;br /&gt;
&lt;br /&gt;
local function iterate_on_nodes_beetween(start_rnode, pnode, min, max)&lt;br /&gt;
	local seq = {}&lt;br /&gt;
	local i  = 1&lt;br /&gt;
&lt;br /&gt;
	while i &amp;lt;= min do&lt;br /&gt;
		table.insert(seq, pnode)&lt;br /&gt;
		i = i + 1&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	local sequence_obj = {}&lt;br /&gt;
	function sequence_obj:iterate(next_rnode)&lt;br /&gt;
		return iterate_on_iterator_creators(next_rnode, seq, min)&lt;br /&gt;
	end&lt;br /&gt;
	if max then&lt;br /&gt;
		local star_obj = {}&lt;br /&gt;
		function star_obj:iterate(next_rnode)&lt;br /&gt;
			return iterate_on_star(next_rnode, pnode, 1, iterated, max-min)&lt;br /&gt;
		end&lt;br /&gt;
		return iterate_on_iterator_creators(&lt;br /&gt;
			start_rnode,&lt;br /&gt;
			{&lt;br /&gt;
				sequence_obj,&lt;br /&gt;
				star_obj&lt;br /&gt;
			}&lt;br /&gt;
		)&lt;br /&gt;
	else&lt;br /&gt;
		return sequence_obj:iterate()&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function iterate_maybe(start_rnode, pnode)&lt;br /&gt;
	local iterator = pnode:iterate(start_rnode)&lt;br /&gt;
	local self_done = false&lt;br /&gt;
	return function()&lt;br /&gt;
		if not self_done then&lt;br /&gt;
			local val = iterator()&lt;br /&gt;
			if val then return val else&lt;br /&gt;
				self_done = true&lt;br /&gt;
				return start_rnode&lt;br /&gt;
			end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function PropertyPath:new(str)&lt;br /&gt;
    local obj = {[&amp;quot;path&amp;quot;]=str} &lt;br /&gt;
    setmetatable(obj, self)&lt;br /&gt;
    &lt;br /&gt;
    local ast = parser.parse_path(str)&lt;br /&gt;
    assert(ast, &amp;quot;parser did not return a node&amp;quot;)&lt;br /&gt;
    obj.node  = ast&lt;br /&gt;
    &lt;br /&gt;
    return obj&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local function entityId(entity)&lt;br /&gt;
	if type(entity) == &amp;#039;string&amp;#039; then&lt;br /&gt;
		return entity&lt;br /&gt;
	end&lt;br /&gt;
	return entity.id&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
local function norm_start_point(start_point)&lt;br /&gt;
	if type(start_point) == &amp;quot;string&amp;quot; then&lt;br /&gt;
		return EpsilonRNode:create(start_point)&lt;br /&gt;
	elseif type(start_point) == &amp;quot;table&amp;quot; then&lt;br /&gt;
		if start_point[&amp;quot;claims&amp;quot;] ~= nil then&lt;br /&gt;
			-- assume this is an item or entity object&lt;br /&gt;
			return EpsilonRNode:create(start_point.id)&lt;br /&gt;
		elseif start_point[&amp;quot;is_RNode&amp;quot;] then&lt;br /&gt;
			return start_point&lt;br /&gt;
		elseif start_point[&amp;quot;qualifiers&amp;quot;] or start_point[&amp;quot;mainsnak&amp;quot;] then&lt;br /&gt;
			local itemid = string.gmatch(start_point.id, &amp;quot;^.*[^$]&amp;quot;)() -- extract the item id from the starting statement&lt;br /&gt;
			return StatementRNode:create(start_point, EpsilonRNode:create(itemid))&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
	mw.logObject(start_point)&lt;br /&gt;
	error(&amp;quot;from function norm_start_point of module PropertyPath : wrong type for start_point&amp;quot;, tostring(start_point)) -- TODO : Log a better error&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function PropertyPath:iterate(start_point)&lt;br /&gt;
	start_point = norm_start_point(start_point)&lt;br /&gt;
	return self.node:iterate(start_point)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
local PropertyNode = datastructure.PropertyNode&lt;br /&gt;
local AlternativeNode = datastructure.AlternativeNode&lt;br /&gt;
local SequenceNode = datastructure.SequenceNode&lt;br /&gt;
local QualifiedStatementNode = datastructure.QualifiedStatementNode&lt;br /&gt;
local NegatedPropertySetNode = datastructure.NegatedPropertySetNode&lt;br /&gt;
local PlusNode = datastructure.PlusNode&lt;br /&gt;
local StarNode = datastructure.StarNode&lt;br /&gt;
local BetweenNode = datastructure.BetweenNode&lt;br /&gt;
local MaybeNode = datastructure.MaybeNode&lt;br /&gt;
local QualifierSnakNode = datastructure.QualifierSnakNode&lt;br /&gt;
&lt;br /&gt;
function PropertyNode:iterate(rnode)&lt;br /&gt;
	return iterate_on_statement_from_property(rnode, self.property)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
test(&amp;quot;Q5&amp;quot;, &amp;quot;subclass of&amp;quot;)&lt;br /&gt;
--]]&lt;br /&gt;
&lt;br /&gt;
function AlternativeNode:iterate(rnode) &lt;br /&gt;
	return iterate_on_alternatives(rnode, self.nodes)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function NegatedPropertySetNode:iterate(rnode)&lt;br /&gt;
	return iterate_on_statement(rnode,&lt;br /&gt;
		function (property, val) return self:matches(property) end&lt;br /&gt;
	)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
test(&amp;quot;Q90, &amp;quot;&amp;quot;!(P150)&amp;quot;)&lt;br /&gt;
--]]&lt;br /&gt;
&lt;br /&gt;
function SequenceNode:iterate(rnode) &lt;br /&gt;
	return iterate_on_iterator_creators(rnode, self.nodes)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function QualifiedStatementNode:iterate(rnode)&lt;br /&gt;
	local statement_iterator = iterate_on_statement(&lt;br /&gt;
		rnode,&lt;br /&gt;
		function (key, value)&lt;br /&gt;
			return self.property:matches(key)&lt;br /&gt;
		end&lt;br /&gt;
	)&lt;br /&gt;
	local qualifier_iterator_creator = function(statement) &lt;br /&gt;
		return iterate_on_statement_qualifier(&lt;br /&gt;
			statement, &lt;br /&gt;
			function (key, value) return self.qualifier:matches(key) end&lt;br /&gt;
		)&lt;br /&gt;
	end&lt;br /&gt;
	&lt;br /&gt;
	return iter.flatten(statement_iterator, qualifier_iterator_creator)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[ to test with :&lt;br /&gt;
p.test(&amp;quot;Q79529&amp;quot;, &amp;quot;union of&amp;gt;of&amp;quot;)&lt;br /&gt;
p.test(&amp;quot;Q105019&amp;quot;,&amp;#039;P22{1,6}&amp;#039;&lt;br /&gt;
--]]&lt;br /&gt;
&lt;br /&gt;
function QualifierSnakNode:iterate(statementnode)&lt;br /&gt;
		return iterate_on_statement_qualifier(&lt;br /&gt;
			statementnode, &lt;br /&gt;
			function (key, value) return self:matches(key) end&lt;br /&gt;
	)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
--[[ to test with :&lt;br /&gt;
for x in p.iterate(&amp;quot;Q79529&amp;quot;, &amp;quot;union of&amp;quot;) do p.test(x, &amp;quot;&amp;gt;of&amp;quot;) end&lt;br /&gt;
--]]&lt;br /&gt;
&lt;br /&gt;
function StarNode:iterate(rnode)&lt;br /&gt;
	return iterate_on_star(rnode, self.node)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function PlusNode:iterate(rnode)&lt;br /&gt;
	return iterate_on_plus(rnode, self.node)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function BetweenNode:iterate(rnode)&lt;br /&gt;
	return iterate_on_nodes_beetween(rnode, self.node, self.min, self.max)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
function MaybeNode:iterate(rnode)&lt;br /&gt;
	return iterate_maybe(rnode, self.node)&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- returns an iterator on the result set of a path from a specific node&lt;br /&gt;
-- ppath acn either be a string representing a path or a compiled path&lt;br /&gt;
function path.iterate(start_node, ppath)&lt;br /&gt;
	if start_node == nil then error(&amp;quot;the start node is mandatory to get result on a path, it is nil&amp;quot;) end&lt;br /&gt;
		&lt;br /&gt;
	if type(ppath) == &amp;quot;table&amp;quot; then&lt;br /&gt;
		return ppath:iterate(start_node)&lt;br /&gt;
	else&lt;br /&gt;
		return path.PropertyPath:new(ppath):iterate(start_node)&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- function that return a boolean&lt;br /&gt;
-- true if there is a path matching ppath from start_node that ends with the value &amp;quot;value&amp;quot;&lt;br /&gt;
-- (currently only works if &amp;quot;value&amp;quot; is a Qid string)&lt;br /&gt;
function path.matches(start_node, ppath, value)&lt;br /&gt;
        for val in path.iterate(start_node, ppath) do&lt;br /&gt;
                if val:item_value() == value then&lt;br /&gt;
                       return true&lt;br /&gt;
                end&lt;br /&gt;
        end&lt;br /&gt;
        return false&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
----------------------------&lt;br /&gt;
&lt;br /&gt;
--[[&lt;br /&gt;
p.test(&amp;quot;Q5&amp;quot;, &amp;quot;P279&amp;quot;)&lt;br /&gt;
p.test(mw.wikibase.getEntity(&amp;quot;Q5&amp;quot;),  &amp;quot;P279&amp;quot;)&lt;br /&gt;
for x in p.iterate(mw.wikibase.getEntity(&amp;quot;Q5&amp;quot;), &amp;quot;P279&amp;quot;) do p.test(x,  &amp;quot;P279&amp;quot;) end -- test if we can continue iteration of an RNode object&lt;br /&gt;
Complex test : &lt;br /&gt;
p.test(&amp;quot;Q27929033&amp;quot;,&amp;quot;P1552&amp;gt;!()/P31&amp;quot;) =&amp;gt; OK&lt;br /&gt;
p.test(&amp;quot;Q27929033&amp;quot;,&amp;quot;subclass of/P1552&amp;gt;!()/P31&amp;quot;) =&amp;gt; NOK&lt;br /&gt;
&lt;br /&gt;
--]]&lt;br /&gt;
function path.test(start_point, ppath)&lt;br /&gt;
	for x in path.iterate(start_point, ppath) do &lt;br /&gt;
		mw.log(&amp;quot;woot&amp;quot;)&lt;br /&gt;
		if x then&lt;br /&gt;
			mw.log(x:item_value())&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-----------------&lt;br /&gt;
-- fonctions retournant une déclaration ou un snak qualificatif en fonction d’un chemin de propriété&lt;br /&gt;
-- utilisé pour les tris, retourner une clé de tri pour une déclaration choisie par un chemin ou un ensemble de chemins&lt;br /&gt;
&lt;br /&gt;
function path.snak_key_by_path(path)&lt;br /&gt;
	local path_to_key = path.PropertyPath:new(path)&lt;br /&gt;
	return function(claim)&lt;br /&gt;
		return (path_to_key:iterate(claim)())&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
-- takes several property paths and creates a function that returns &lt;br /&gt;
-- the first value with a match&lt;br /&gt;
&lt;br /&gt;
-- example : local get_key = wd.snak_key_by_paths{&amp;quot;&amp;gt;P80&amp;quot;,&amp;quot;P800|P801&amp;quot;}&lt;br /&gt;
--           get_key(claim)&lt;br /&gt;
-- returns the qualifier value of P80 of the claim if it exists, if not returns the main statement value&lt;br /&gt;
-- of P800 of the main value of the « claim » statement, if not the P801 one&lt;br /&gt;
-- (used in Module:Infobox/fonctions/personne)&lt;br /&gt;
&lt;br /&gt;
-- Note on the example : TODO : would be equivalent to a single path &amp;quot;&amp;gt;P80|P800|P801&amp;quot; but it’s not possible yet&lt;br /&gt;
&lt;br /&gt;
function path.snak_key_by_paths(paths)&lt;br /&gt;
	local paths_to_key = {} &lt;br /&gt;
	for k, pat in ipairs(paths) do&lt;br /&gt;
		paths_to_key[#paths_to_key + 1] = path.PropertyPath:new(pat)&lt;br /&gt;
	end&lt;br /&gt;
	return function(claim)&lt;br /&gt;
		-- returns the first value of the first matching path starting from « claim »&lt;br /&gt;
		for k, path_to_key in ipairs(paths_to_key) do&lt;br /&gt;
			local res = path_to_key:iterate(claim)()&lt;br /&gt;
			if res then return res end&lt;br /&gt;
		end&lt;br /&gt;
	end&lt;br /&gt;
end&lt;br /&gt;
&lt;br /&gt;
&lt;br /&gt;
----------------------------&lt;br /&gt;
&lt;br /&gt;
path.PropertyPath = PropertyPath&lt;br /&gt;
&lt;br /&gt;
return path&lt;/div&gt;</summary>
		<author><name>Jaggerwock</name></author>
	</entry>
</feed>