Module:MathModDBHelperMethods: Difference between revisions

From MaRDI portal
No edit summary
No edit summary
 
(29 intermediate revisions by 2 users not shown)
Line 20: Line 20:


-- Function to generate a table listing a type of individuals
-- Function to generate a table listing a type of individuals
-- test with =p.getList{args={'Model'}}
function p.getList(frame)
function p.getList(frame)
Line 46: Line 47:
     -- Q6534265 refers to MathModDB community
     -- Q6534265 refers to MathModDB community
     local sparqlQuery = [[
     local sparqlQuery = [[
SELECT ?itemLabel ?modelURL
SELECT ?itemLabel ?modelURL ?item
     WHERE {
     WHERE {
       ?item wdt:P31 wd:]] .. config.qid .. [[;
       ?item wdt:P31 wd:]] .. config.qid .. [[;
Line 74: Line 75:
-- Convert the JSON results into a Lua table
-- Convert the JSON results into a Lua table
     local fieldOrder = {"modelURL", "itemLabel"}
     local fieldOrder = {"modelURL", "itemLabel", "item"}
local dataTable = helper.convertJsonToTableOrdered(jsonResults, fieldOrder)
local dataTable = helper.convertJsonToTableOrdered(jsonResults, fieldOrder)
-- Create and return HTML table from the data
-- Create and return HTML table from the data
     local headers = {entityType}
     local headers = {entityType}
     local htmlTable =  helper.createHtmlTableWithMergedCols(dataTable, headers, {{1, 2}})
     local htmlTable =  helper.createHtmlTableWithMergedCols(dataTable, headers, {{3}})
-- Create a parent container for the table
-- Create a parent container for the table
Line 96: Line 97:
     return tostring(parentContainer)
     return tostring(parentContainer)
end
end


-- Function to get linked items
-- Function to get linked items
Line 152: Line 152:
-- Validate results
-- Validate results
if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
       return " "
       return ""
     end
     end
Line 255: Line 255:




-- Function to get subclass of items
-- Function to get described by source
function p.getDescribedBySource(frame)
function p.getDescribedBySource(frame)
local entityId = frame.args[1]
local entityId = frame.args[1]
Line 315: Line 315:
-- Property ID for the image
-- Property ID for the image
     local pidImage  = "P356"  
     local pidImage  = "P356"  
    -- Property ID for the (qualifier) media legend
    local pidMediaLegend = "P401" 
    local defaultLegend = "No legend available."
 
local entityId = frame.args[1]
   
    -- Validate input parameter
    if not entityId or entityId == '' then
        return "Error: No entity ID provided"
    end
   
    -- Attempt to retrieve entity data
    local entity = mw.wikibase.getEntity(entityId)
    local imageClaims = entity.claims[pidImage]
    local imageStrings = {}
if imageClaims and type(imageClaims) == "table" then
    local numClaims = #imageClaims
    -- Loop through the image claims
-- for index = 1, numClaims  do
local index = 1
for _, claim in ipairs(imageClaims) do
-- Extract the image filename
    -- local imageFilename = imageClaims[index].mainsnak.datavalue.value
    local imageFilename = claim.mainsnak.datavalue.value
    -- Default legend (empty string)
        local imageLegend = ""
    -- Check if the media legend qualifier exists
        if claim.qualifiers and claim.qualifiers[pidMediaLegend]
        and #claim.qualifiers[pidMediaLegend] > 0
        and claim.qualifiers[pidMediaLegend][1].datavalue
        and claim.qualifiers[pidMediaLegend][1].datavalue.value
        and claim.qualifiers[pidMediaLegend][1].datavalue.value.text then
            imageLegend = claim.qualifiers[pidMediaLegend][1].datavalue.value.text
        end
-- local imageLegend = imageClaims[index].qualifiers[pidMediaLegend][1].datavalue.value.text
-- Add this image line to the list
-- table.insert(imageStrings, {filename = imageFilename, legend = imageLegend})
        table.insert(imageStrings, string.format("[[File:%s|thumb|380px|%s]]", imageFilename, imageLegend))
       
        if index < numClaims then
        -- spacer column
        table.insert(imageStrings, '&nbsp;') 
        end
index = index + 1
end   
-- Combine all image cells into one row of a wikitable
local imageTable = '{| class="wikitable"\n| ' .. table.concat(imageStrings, ' || ') .. '\n|}'
return imageTable .. "\n\n"
else
    return ""
end
end
function p.getVideoWithLegend(frame)
-- Property ID for the video
    local pidVideo  = "P797"
    -- Property ID for the (qualifier) media legend
    local pidMediaLegend = "P401" 
    local defaultLegend = "No legend available."
 
local entityId = frame.args[1]
   
    -- Validate input parameter
    if not entityId or entityId == '' then
        return "Error: No entity ID provided"
    end
   
    -- Attempt to retrieve entity data
    local entity = mw.wikibase.getEntity(entityId)
    local videoClaims = entity.claims[pidVideo]
    local videoStrings = {}
if videoClaims and type(videoClaims) == "table" then
    local numClaims = #videoClaims
    -- Loop through the image claims
for index = 1, numClaims  do
-- Extract the image filename
    local videoFilename = videoClaims[index].mainsnak.datavalue.value
local videoLegend = videoClaims[index].qualifiers[pidMediaLegend][1].datavalue.value.text
-- Add this image line to the list
        table.insert(videoStrings, string.format("[[File:%s|thumb|340px|%s]]", videoFilename, videoLegend))
       
        if index < numClaims then
        -- spacer column
        table.insert(videoStrings, '&nbsp;') 
    end
end   
-- Combine all image cells into one row of a wikitable
local videoTable = '{| class="wikitable"\n| ' .. table.concat(videoStrings, ' || ') .. '\n|}'
return videoTable .. "\n\n"
else
    return " "
end
end
function p.getLocalImageWithLegend(frame)
-- Property ID for the image
    local pidImage  = "P1640"
     -- Property ID for the (qualifier) media legend
     -- Property ID for the (qualifier) media legend
     local pidMediaLegend = "P401"   
     local pidMediaLegend = "P401"   
Line 337: Line 440:
-- Extract the image filename
-- Extract the image filename
     local imageFilename = imageClaims[index].mainsnak.datavalue.value
     local imageFilename = imageClaims[index].mainsnak.datavalue.value
local imageLegend = imageClaims[index].qualifiers[pidMediaLegend][1].datavalue.value.text
    -- Default legend (empty string)
        local imageLegend = ""
    -- Check if the media legend qualifier exists
        if imageClaims[index].qualifiers and imageClaims[index].qualifiers[pidMediaLegend]
        and #imageClaims[index].qualifiers[pidMediaLegend] > 0
        and imageClaims[index].qualifiers[pidMediaLegend][1].datavalue
        and imageClaims[index].qualifiers[pidMediaLegend][1].datavalue.value
        and imageClaims[index].qualifiers[pidMediaLegend][1].datavalue.value.text then
 
            imageLegend = imageClaims[index].qualifiers[pidMediaLegend][1].datavalue.value.text
        end
-- Add this image line to the list
-- Add this image line to the list
         table.insert(imageStrings, string.format("[[File:%s|thumb|380px|%s]]", imageFilename, imageLegend))
         table.insert(imageStrings, string.format("[[File:%s|thumb|380px|%s]]", imageFilename, imageLegend))
Line 356: Line 469:




function p.getVideoWithLegend(frame)
function p.getLocalVideoWithLegend(frame)
-- Property ID for the video
-- Property ID for the video
     local pidVideo  = "P797"  
     local pidVideo  = "P1675"  
     -- Property ID for the (qualifier) media legend
     -- Property ID for the (qualifier) media legend
     local pidMediaLegend = "P401"   
     local pidMediaLegend = "P401"   
Line 399: Line 512:
end
end


-- Function to get model assumptions
-- Function to get list with qualifier values only
function p.getListWithQualifiers(frame)
function p.getListWithQualifierValues(frame)
local entityId = frame.args[1]
local entityId = frame.args[1]
     local propertyId = frame.args[2]
     local propertyId = frame.args[2]
Line 408: Line 521:
         return " "
         return " "
     end
     end
 
    -- Constructing the SPARQL query with dynamic entity entityId
    local sparqlQuery = [[
PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
SELECT ?URL ?Label ?qualPropEntity ?qualPropLabel ?qualValue ?qualValueLabel
WHERE {
entityId: p:]] .. propertyId .. [[  ?statement .
?statement ps:]] .. propertyId .. [[ ?URL .
?URL rdfs:label ?Label
FILTER(LANG(?Label) = "en")
OPTIONAL {
    ?statement ?qualProp ?qualValue .
    FILTER(STRSTARTS(STR(?qualProp), STR(pq:)))  # only qualifiers
    # Map qualifier property to its property entity
    BIND(IRI(REPLACE(STR(?qualProp), "prop/qualifier", "entity")) AS ?qualPropEntity)
    OPTIONAL {
    ?qualPropEntity rdfs:label ?qualPropLabel .
    FILTER(LANG(?qualPropLabel) = "en")
    }
    OPTIONAL {
    ?qualValue rdfs:label ?qualValueLabel .
    FILTER(LANG(?qualValueLabel) = "en")
    }
}
}
ORDER BY ?Label
]]
-- Executing the SPARQL query and retrieving results in JSON format
local jsonResults = sparql.runQuery(sparqlQuery)
-- Validate results
if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
      return "No specialized research fields found"
    end
local listItems = {}
    -- Get the number of specialized research fields
local totallistItems = #jsonResults.results.bindings
-- Loop through the bindings
for index = 0, totallistItems do
    local item = jsonResults.results.bindings[index]
    if not item.Label.value then
        return "Error: Missing item.Label.value"
    elseif not item.URL.value then
        return "Error: Missing item.URL.value"
    else
    local label = item.Label.value
        local url = item.URL.value
        local numericId = url:match("Q(%d+)")
        local urlRendered = "https://portal.mardi4nfdi.de/wiki/Model:" .. numericId
        local qualValue = item.qualValueLabel or item.qualValue or ""
        local labelWithUrl = string.format('[%s %s]', tostring(url), tostring(label))
        if qualValue ~= "" then
      local qualValueWithUrl = string.format('[%s %s]', tostring(item.qualValue.value), tostring(item.qualValueLabel.value))
        local row = "| " .. labelWithUrl ..  " || (" ..  qualValueWithUrl .. ")"
    table.insert(listItems, row)
        else
        table.insert(listItems, "| " .. labelWithUrl)
        end
    end
end
-- Construct the Wikitext table
local wikitextTable = "{| class='wikitable'\n" .. table.concat(listItems, "\n|-\n") .. "\n|}"
return wikitextTable
end
-- Function to get list with qualifier values and qualifier labels
function p.getListWithQualifierValuesLabels(frame)
local entityId = frame.args[1]
    local propertyId = frame.args[2]
      
      
    -- Validate input parameter
    if not entityId or entityId == '' then
        return " "
    end
 
     -- Constructing the SPARQL query with dynamic entity entityId
     -- Constructing the SPARQL query with dynamic entity entityId
     local sparqlQuery = [[
     local sparqlQuery = [[
PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
SELECT ?AssumptionURL ?AssumptionLabel
SELECT ?URL ?Label ?qualPropEntity ?qualPropLabel ?qualValue ?qualValueLabel
WHERE {
WHERE {
    entityId: p:]] .. propertyId .. [[ ?statement.
entityId: p:]] .. propertyId .. [[ ?statement .
    ?statement ps:]] .. propertyId .. [[ ?AssumptionURL.
?statement ps:]] .. propertyId .. [[ ?URL .
    ?AssumptionURL rdfs:label ?AssumptionLabel.
?URL rdfs:label ?Label
FILTER(LANG(?Label) = "en")
 
OPTIONAL {
    ?statement ?qualProp ?qualValue .
    FILTER(STRSTARTS(STR(?qualProp), STR(pq:)))  # only qualifiers
 
    # Map qualifier property to its property entity
    BIND(IRI(REPLACE(STR(?qualProp), "prop/qualifier", "entity")) AS ?qualPropEntity)
 
    OPTIONAL {
    ?qualPropEntity rdfs:label ?qualPropLabel .
    FILTER(LANG(?qualPropLabel) = "en")
    }
 
    OPTIONAL {
    ?qualValue rdfs:label ?qualValueLabel .
    FILTER(LANG(?qualValueLabel) = "en")
    }
}
}
}
ORDER BY ?AssumptionLabel
ORDER BY ?Label
]]
]]


-- Executing the SPARQL query and retrieving results in JSON format
-- Executing the SPARQL query and retrieving results in JSON format
Line 426: Line 638:
-- Validate results
-- Validate results
if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
       return "No computational task found"
       return "No specialized research fields found"
     end
     end
local assumptions = {}
local listItems = {}
     -- Get the number of computational tasks
     -- Get the number of specialized research fields
local totalAssumptions = #jsonResults.results.bindings
local totallistItems = #jsonResults.results.bindings
-- Loop through the bindings
-- Loop through the bindings
for index = 0, totalAssumptions  do
for index = 0, totallistItems do
     local item = jsonResults.results.bindings[index]
     local item = jsonResults.results.bindings[index]
     if not item.AssumptionLabel.value then
     if not item.Label.value then
         return "Error: Missing item.Label.value"
         return "Error: Missing item.Label.value"
     elseif not item.AssumptionURL.value then
     elseif not item.URL.value then
         return "Error: Missing item.URL.value"
         return "Error: Missing item.URL.value"
     else
     else
        local label = item.AssumptionLabel.value
    local label = item.Label.value
         local url = item.AssumptionURL.value
         local url = item.URL.value
         local numericId = url:match("Q(%d+)")
         local numericId = url:match("Q(%d+)")
    local urlRendered = "https://portal.mardi4nfdi.de/wiki/Formula:" .. numericId
        local urlRendered = "https://portal.mardi4nfdi.de/wiki/Model:" .. numericId
         local labelWithUrl = string.format('[%s %s]', tostring(urlRendered), tostring(label))
         local qualValue = item.qualValueLabel or item.qualValue or ""
        local ordinal = item.Ordinal and item.Ordinal.value or nil
        local qualPropLabel = item.qualPropLabel or ""
local prefix = ordinal and (ordinal .. ". ") or ""
        local labelWithUrl = string.format('[%s %s]', tostring(url), tostring(label))
table.insert(assumptions, "| " .. prefix .. labelWithUrl)
        if qualValue ~= "" then
      local qualValueWithUrl = string.format('[%s %s]', tostring(item.qualValue.value), tostring(item.qualValueLabel.value))
        local row = "| " .. labelWithUrl .. " || " ..  qualPropLabel.value .. " || " .. qualValueWithUrl
    table.insert(listItems, row)
        else
        table.insert(listItems, "| " .. labelWithUrl)
        end
    end
end
 
-- Construct the Wikitext table
local wikitextTable = "{| class='wikitable'\n" .. table.concat(listItems, "\n|-\n") .. "\n|}"
return wikitextTable
end
 
 
-- Function to get instance of types
function p.getInstanceOfTypes(frame)
local entityId = frame.args[1]
   
    -- Validate input parameter
    if not entityId or entityId == '' then
        return "Error: No entity ID provided"
    end
   
    -- Constructing the SPARQL query with dynamic entity entityId
    -- P31: instance of property id
    local sparqlQuery = [[
PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
SELECT  ?InstanceOfTypeLabel WHERE {
  entityId: p:P31 ?statement .
  ?statement ps:P31 ?InstanceOfType .
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
ORDER BY ?InstanceOfTypeLabel
]]
 
 
-- Executing the SPARQL query and retrieving results in JSON format
local jsonResults = sparql.runQuery(sparqlQuery)
-- Validate results
if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
    end
local InstanceOfTypes = {}
    -- Get the number of model types
local totalInstanceOfTypes = #jsonResults.results.bindings
-- Loop through the bindings
for index = 0, totalInstanceOfTypes  do
    local item = jsonResults.results.bindings[index]
    if item and item.InstanceOfTypeLabel and item.InstanceOfTypeLabel.value then
        local label = item.InstanceOfTypeLabel.value
        table.insert(InstanceOfTypes, label)
     end
     end
end
end


-- Construct the Wikitext table
-- Construct the Wikitext table
local wikitextTable = "{| class='wikitable'\n" .. table.concat(assumptions, "\n|-\n") .. "\n|}"
local wikitextTable = "{| class='wikitable'\n|-\n| " .. table.concat(InstanceOfTypes, " || ") .. "\n|}"
return wikitextTable
return wikitextTable


end
end
-- Function to get instance of types
function p.getListNamedAfter(frame)
local entityId = frame.args[1]
   
    -- Validate input parameter
    if not entityId or entityId == '' then
        return "Error: No entity ID provided"
    end
   
    -- Constructing the SPARQL query with dynamic entity entityId
    -- P31: instance of property id
    local sparqlQuery = [[
PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
SELECT ?namedAfterLabel ?namedAfter
WHERE {
  entityId: p:P558 ?statement .
  ?statement ps:P558 ?namedAfter .
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
ORDER BY ?namedAfterLabel
]]
-- Executing the SPARQL query and retrieving results in JSON format
local jsonResults = sparql.runQuery(sparqlQuery)
-- Validate results
if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
end
local ListNamedAfter = {}
    -- Get the number of persons named after
local totalPersons = #jsonResults.results.bindings
-- Loop through the bindings
for index = 0, totalPersons  do
    local item = jsonResults.results.bindings[index]
    if item and item.namedAfterLabel and item.namedAfterLabel.value then
        local label = item.namedAfterLabel.value
        local url = item.namedAfter.value
        local numericId = url:match("Q(%d+)")
    local urlRendered = "https://portal.mardi4nfdi.de/wiki/Person:" .. numericId
        local labelWithUrl = string.format('[%s %s]', tostring(urlRendered), tostring(label))
        table.insert(ListNamedAfter,  labelWithUrl)
    end
end
return table.concat(ListNamedAfter, ', ')
   
-- end of function getListNamedAfter
end
   


return p
return p

Latest revision as of 21:32, 16 December 2025

Documentation for this module may be created at Module:MathModDBHelperMethods/doc

-- Module for executing SPARQL queries
local sparql = require('SPARQL')
-- Required module containing helper methods
local helper = require('Module:HelperMethods')
-- MediaWiki library for logging and utilities
local mw = require('mw')
local json = require("mw.text") 

-- Main table to hold all functions
local p = {}

-- Function to replace pattern in the comma pattern separated list 
function p.replace_pattern(frame)
    local input = frame.args[1] or ""
    local sep = frame.args[2] or " "  -- default to space if no separator given
    -- Replace comma+pattern (,xxxx) with sep
    local result = string.gsub(input, ",xxxx%s*", sep)
    return result
end

-- Function to generate a table listing a type of individuals
-- test with =p.getList{args={'Model'}}
function p.getList(frame)
	
	local entityType = frame.args[1] or 'Model'
	local height = frame.args[2] or '400px' -- Default height if not specified
    local width = frame.args[3] or '800px' -- Default width if not specified
    local baseUrl = mw.site.server -- Get the current URL
    
    -- Define mapping of entity types to their corresponding Q IDs and URL prefixes
    local entityConfig = {
        ['Model'] = {qid = 'Q68663', urlPrefix = 'Model:', title = 'mathematical models'},
        ['Academic discipline'] = {qid = 'Q60231', urlPrefix = 'Academic_discipline:', title = 'academic disciplines'},
        ['Research problem'] = {qid = 'Q6534292', urlPrefix = 'Research_problem:', title = 'research problems'},
        ['Task'] = {qid = 'Q6534247', urlPrefix = 'Task:', title = 'computational tasks'},
        ['Quantity'] = {qid = 'Q6534237', urlPrefix = 'Quantity:', title = 'quantities'},
        ['Quantity kind'] = {qid = 'Q6534245', urlPrefix = 'Quantity:', title = 'quantity kind items'},
        ['Formula'] = {qid = 'Q6481152', urlPrefix = 'Formula:', title = 'mathematical expressions'}
    }
    
    -- Get configuration for the specified entity type
    local config = entityConfig[entityType]
    if not config then
        return "Invalid entity type. Valid options are: Model, Academic discipline, Research problem, Task, Quantity, Quantity kind, Formula"
    end

    -- Q6534265 refers to MathModDB community
    local sparqlQuery = [[
	SELECT ?itemLabel ?modelURL ?item
    WHERE {
      ?item wdt:P31 wd:]] .. config.qid .. [[;
            wdt:P1495 wd:Q6534265 .
      ?item rdfs:label ?itemLabel .
      FILTER(LANG(?itemLabel) = "en")
      BIND(REPLACE(STR(?item), "^.*/Q", "]] .. baseUrl .. [[/wiki/]] .. config.urlPrefix .. [[") AS ?modelURL)
    }
    ORDER BY LCASE(?itemLabel)
    ]]

    local jsonResults = sparql.runQuery(sparqlQuery)

	-- Handle error in SPARQL query execution
	if jsonResults and jsonResults.error then
    	mw.log("Error in SPARQL query: " .. tostring(jsonResults.error))
    	return nil
	end

	if not jsonResults then
        return "Could not fetch data."
	end

	if helper.countElementsInBindings(jsonResults.results.bindings) == 0 then
        return "No records found."
	end
	
	-- Convert the JSON results into a Lua table
    local fieldOrder = {"modelURL", "itemLabel", "item"}
	local dataTable = helper.convertJsonToTableOrdered(jsonResults, fieldOrder)
	
	-- Create and return HTML table from the data
    local headers = {entityType}
    local htmlTable =  helper.createHtmlTableWithMergedCols(dataTable, headers, {{3}})
	
	-- Create a parent container for the table
	local parentContainer = mw.html.create('div')
    	:addClass('parent-container')
    	:css('width', width)

	local heading = mw.html.create('h2')
    	:wikitext('List of ' .. config.title)

    -- Add the table and chart to the parent container
	parentContainer
	    :node(heading)
    	:node(htmlTable)

    return tostring(parentContainer)
end

-- Function to get linked items
function p.getLinkedItems(frame)
	local entityId = frame.args[1]
    
    -- Validate input parameter
    if not entityId or entityId == '' then
        return "Error: No entity ID provided"
    end
    
    local sparqlQuery = [[
PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>

SELECT DISTINCT ?itemLabel ?item ?propertyLabel ?property 
WHERE {
  # Replace with your specific entity
  ?itemInter ?ps entityId: .

  # Convert property URL to entity-style URL
 BIND(
    IRI(REPLACE(STR(?ps),
                 "^https://portal.mardi4nfdi.de/prop/(direct|qualifier|statement)/",
                 "https://portal.mardi4nfdi.de/entity/"))
    AS ?property
 )
 # Skip unwanted property
 FILTER(?property != <http://schema.org/about>)

  # Clean URL: keep only QID, remove /statement/ and trailing UUID
  BIND(
    IRI(
      REPLACE(
        STR(?itemInter),
        ".*/(Q[0-9]+).*",
        "https://portal.mardi4nfdi.de/entity/$1"
      )
    ) AS ?item
  )

  # Get labels
  SERVICE wikibase:label { 
    bd:serviceParam wikibase:language "en". 
    ?item rdfs:label ?itemLabel .
    ?property rdfs:label ?propertyLabel .
  }
}
ORDER BY LCASE(?itemLabel)

]]


	-- Executing the SPARQL query and retrieving results in JSON format
	local jsonResults = sparql.runQuery(sparqlQuery)
	-- Validate results
	if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
       	return ""
    end
	
	local linkedItems = {}
	local totalLinkedItems = #jsonResults.results.bindings

	if totalLinkedItems >= 0 then
    	-- Loop through the bindings 
    	for index = 0, totalLinkedItems do
        	local item = jsonResults.results.bindings[index]
        	
        	if not item then
        		return ""
    		end

        	if not item.itemLabel or not item.itemLabel.value then
        		return ""
        	elseif not item.item or not item.item.value then
            	return ""
        	else
            	local itemLabel = item.itemLabel.value
            	local itemURL = item.item.value
            	local propertyLabel = item.propertyLabel and item.propertyLabel.value or ""
            	local propertyURL = item.property and item.property.value or ""

            	local itemWithURL = string.format('[%s %s]', tostring(itemURL), tostring(itemLabel))
            	local propertyWithURL = string.format('[%s %s]', tostring(propertyURL), tostring(propertyLabel))

            	table.insert(linkedItems, '| ' .. itemWithURL .. ' || ' .. propertyWithURL)
        	end
    	end
    	-- if there are linked items 
    	-- Construct the Wikitext table
		local wikitextTable = "{| class='wikitable'\n" ..
    	"! Item\n! Property\n" ..          -- header row
    	"|-\n" ..                          -- separator before first data row
    	table.concat(linkedItems, "\n|-\n") ..
    	"\n|}"
		return wikitextTable
	else
		return ""
	end

end

-- Function to get subclass of items
function p.getSubclassOf(frame)
	local entityId = frame.args[1]
    
    -- Validate input parameter
    if not entityId or entityId == '' then
        return "Error: No entity ID provided"
    end
    
    -- Constructing the SPARQL query with dynamic entity entityId
    -- P36: subclass of property id
    local sparqlQuery = [[
PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
	SELECT ?URL ?Label  
	WHERE {
		entityId: wdt:P36 ?URL.
		?URL rdfs:label ?Label
		FILTER(LANG(?Label) = "en")
	}
	ORDER BY ?Label
	]]

	-- Executing the SPARQL query and retrieving results in JSON format
	local jsonResults = sparql.runQuery(sparqlQuery)
	-- Validate results
	if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
       	return "No specialized academic discipline found"
    end
	
	local subClasses = {}
    -- Get the number of specialized academic disciplines
	local totalSubClasses = #jsonResults.results.bindings
	-- Loop through the bindings
	for index = 0, totalSubClasses  do
    	local item = jsonResults.results.bindings[index]
    	if not item then
        		return ""
    	end
    	if not item.Label.value then
        	return ""
    	elseif not item.URL.value then
        	return ""
    	else
    		local label = item.Label.value
        	local url = item.URL.value
        	local numericId = url:match("Q(%d+)")
        	local urlRendered = "https://portal.mardi4nfdi.de/wiki/Academic_discipline:" .. numericId
        	local labelWithUrl = string.format('[%s %s]', tostring(url), tostring(label))
        	table.insert(subClasses, "| " .. labelWithUrl)
    	end
	end

	-- Construct the Wikitext table
	local wikitextTable = "{| class='wikitable'\n" .. table.concat(subClasses, "\n|-\n") .. "\n|}"
	return wikitextTable
end	


-- Function to get described by source
function p.getDescribedBySource(frame)
	local entityId = frame.args[1]
    
    -- Validate input parameter
    if not entityId or entityId == '' then
        return "Error: No entity ID provided"
    end
    
    -- Constructing the SPARQL query with dynamic entity entityId
    -- P286: described by source property id
    local sparqlQuery = [[
PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
	SELECT ?URL ?Label  
	WHERE {
		entityId: wdt:P286 ?URL.
		?URL rdfs:label ?Label
		FILTER(LANG(?Label) = "en")
	}
	ORDER BY ?Label
	]]

	-- Executing the SPARQL query and retrieving results in JSON format
	local jsonResults = sparql.runQuery(sparqlQuery)
	-- Validate results
	if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
       	return "No specialized academic discipline found"
    end
	
	local describedBySources = {}
    -- Get the number of specialized academic disciplines
	local totalSources = #jsonResults.results.bindings
	-- Loop through the bindings
	for index = 0, totalSources  do
    	local item = jsonResults.results.bindings[index]
    	if not item then
        		return ""
    	end
    	if not item.Label.value then
        	return ""
    	elseif not item.URL.value then
        	return ""
    	else
    		local label = item.Label.value
        	local url = item.URL.value
        	local numericId = url:match("Q(%d+)")
        	local urlRendered = "https://portal.mardi4nfdi.de/wiki/Academic_discipline:" .. numericId
        	local labelWithUrl = string.format('[%s %s]', tostring(url), tostring(label))
        	table.insert(describedBySources, "| " .. labelWithUrl)
    	end
	end

	-- Construct the Wikitext table
	local wikitextTable = "{| class='wikitable'\n" .. table.concat(describedBySources, "\n|-\n") .. "\n|}"
	return wikitextTable
end	

function p.getImageWithLegend(frame)
	-- Property ID for the image
    local pidImage  = "P356" 
    -- Property ID for the (qualifier) media legend
    local pidMediaLegend = "P401"   
    local defaultLegend = "No legend available."

   	
	local entityId = frame.args[1]
    
    -- Validate input parameter
    if not entityId or entityId == '' then
        return "Error: No entity ID provided"
    end
    
    -- Attempt to retrieve entity data
    local entity = mw.wikibase.getEntity(entityId)
    local imageClaims = entity.claims[pidImage]
    local imageStrings = {}
	if imageClaims and type(imageClaims) == "table" then
    	local numClaims = #imageClaims
    	-- Loop through the image claims
		-- for index = 1, numClaims  do
		local index = 1
		for _, claim in ipairs(imageClaims) do
			-- Extract the image filename
    		-- local imageFilename = imageClaims[index].mainsnak.datavalue.value
    		local imageFilename = claim.mainsnak.datavalue.value
    		-- Default legend (empty string)
        	local imageLegend = ""
    		-- Check if the media legend qualifier exists
        	if claim.qualifiers and claim.qualifiers[pidMediaLegend] 
        		and #claim.qualifiers[pidMediaLegend] > 0 
        		and claim.qualifiers[pidMediaLegend][1].datavalue
        		and claim.qualifiers[pidMediaLegend][1].datavalue.value
        		and claim.qualifiers[pidMediaLegend][1].datavalue.value.text then

            	imageLegend = claim.qualifiers[pidMediaLegend][1].datavalue.value.text
        	end
			-- local imageLegend = imageClaims[index].qualifiers[pidMediaLegend][1].datavalue.value.text
			-- Add this image line to the list
			-- table.insert(imageStrings, {filename = imageFilename, legend = imageLegend})
        	table.insert(imageStrings, string.format("[[File:%s|thumb|380px|%s]]", imageFilename, imageLegend))
        
        	if index < numClaims then
        		-- spacer column
        		table.insert(imageStrings, '&nbsp;')  
        	end
			index = index + 1
		end    
		-- Combine all image cells into one row of a wikitable
		local imageTable = '{| class="wikitable"\n| ' .. table.concat(imageStrings, ' || ') .. '\n|}'
		return imageTable .. "\n\n"
	else
    	return "" 
	end

end


function p.getVideoWithLegend(frame)
	-- Property ID for the video
    local pidVideo  = "P797" 
    -- Property ID for the (qualifier) media legend
    local pidMediaLegend = "P401"   
    local defaultLegend = "No legend available."

   	
	local entityId = frame.args[1]
    
    -- Validate input parameter
    if not entityId or entityId == '' then
        return "Error: No entity ID provided"
    end
    
    -- Attempt to retrieve entity data
    local entity = mw.wikibase.getEntity(entityId)
    local videoClaims = entity.claims[pidVideo]
    local videoStrings = {}
	if videoClaims and type(videoClaims) == "table" then
    	local numClaims = #videoClaims
    	-- Loop through the image claims
		for index = 1, numClaims  do
			-- Extract the image filename
    		local videoFilename = videoClaims[index].mainsnak.datavalue.value
			local videoLegend = videoClaims[index].qualifiers[pidMediaLegend][1].datavalue.value.text
			-- Add this image line to the list
        	 table.insert(videoStrings, string.format("[[File:%s|thumb|340px|%s]]", videoFilename, videoLegend))
        
        	if index < numClaims then
        		-- spacer column
        		table.insert(videoStrings, '&nbsp;')  
    end
		end    
		-- Combine all image cells into one row of a wikitable
		local videoTable = '{| class="wikitable"\n| ' .. table.concat(videoStrings, ' || ') .. '\n|}'
		return videoTable .. "\n\n"
	else
    	return " " 
	end

end

function p.getLocalImageWithLegend(frame)
	-- Property ID for the image
    local pidImage  = "P1640" 
    -- Property ID for the (qualifier) media legend
    local pidMediaLegend = "P401"   
    local defaultLegend = "No legend available."

   	
	local entityId = frame.args[1]
    
    -- Validate input parameter
    if not entityId or entityId == '' then
        return "Error: No entity ID provided"
    end
    
    -- Attempt to retrieve entity data
    local entity = mw.wikibase.getEntity(entityId)
    local imageClaims = entity.claims[pidImage]
    local imageStrings = {}
	if imageClaims and type(imageClaims) == "table" then
    	local numClaims = #imageClaims
    	-- Loop through the image claims
		for index = 1, numClaims  do
			-- Extract the image filename
    		local imageFilename = imageClaims[index].mainsnak.datavalue.value
    		-- Default legend (empty string)
        	local imageLegend = ""
    		-- Check if the media legend qualifier exists
        	if imageClaims[index].qualifiers and imageClaims[index].qualifiers[pidMediaLegend] 
        		and #imageClaims[index].qualifiers[pidMediaLegend] > 0 
        		and imageClaims[index].qualifiers[pidMediaLegend][1].datavalue
        		and imageClaims[index].qualifiers[pidMediaLegend][1].datavalue.value
        		and imageClaims[index].qualifiers[pidMediaLegend][1].datavalue.value.text then

            	imageLegend = imageClaims[index].qualifiers[pidMediaLegend][1].datavalue.value.text
        	end
			-- Add this image line to the list
        	 table.insert(imageStrings, string.format("[[File:%s|thumb|380px|%s]]", imageFilename, imageLegend))
        
        	if index < numClaims then
        		-- spacer column
        		table.insert(imageStrings, '&nbsp;')  
    end
		end    
		-- Combine all image cells into one row of a wikitable
		local imageTable = '{| class="wikitable"\n| ' .. table.concat(imageStrings, ' || ') .. '\n|}'
		return imageTable .. "\n\n"
	else
    	return " " 
	end

end


function p.getLocalVideoWithLegend(frame)
	-- Property ID for the video
    local pidVideo  = "P1675" 
    -- Property ID for the (qualifier) media legend
    local pidMediaLegend = "P401"   
    local defaultLegend = "No legend available."

   	
	local entityId = frame.args[1]
    
    -- Validate input parameter
    if not entityId or entityId == '' then
        return "Error: No entity ID provided"
    end
    
    -- Attempt to retrieve entity data
    local entity = mw.wikibase.getEntity(entityId)
    local videoClaims = entity.claims[pidVideo]
    local videoStrings = {}
	if videoClaims and type(videoClaims) == "table" then
    	local numClaims = #videoClaims
    	-- Loop through the image claims
		for index = 1, numClaims  do
			-- Extract the image filename
    		local videoFilename = videoClaims[index].mainsnak.datavalue.value
			local videoLegend = videoClaims[index].qualifiers[pidMediaLegend][1].datavalue.value.text
			-- Add this image line to the list
        	 table.insert(videoStrings, string.format("[[File:%s|thumb|340px|%s]]", videoFilename, videoLegend))
        
        	if index < numClaims then
        		-- spacer column
        		table.insert(videoStrings, '&nbsp;')  
    end
		end    
		-- Combine all image cells into one row of a wikitable
		local videoTable = '{| class="wikitable"\n| ' .. table.concat(videoStrings, ' || ') .. '\n|}'
		return videoTable .. "\n\n"
	else
    	return " " 
	end

end

-- Function to get list with qualifier values only
function p.getListWithQualifierValues(frame)
	local entityId = frame.args[1]
    local propertyId = frame.args[2]
    
    -- Validate input parameter
    if not entityId or entityId == '' then
        return " "
    end
   
    -- Constructing the SPARQL query with dynamic entity entityId
    local sparqlQuery = [[
	PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
	SELECT ?URL ?Label ?qualPropEntity ?qualPropLabel ?qualValue ?qualValueLabel
	WHERE {
		entityId: p:]] .. propertyId .. [[  ?statement .
		?statement ps:]] .. propertyId .. [[ ?URL .
		?URL rdfs:label ?Label
		FILTER(LANG(?Label) = "en")

		OPTIONAL {
    		?statement ?qualProp ?qualValue .
    		FILTER(STRSTARTS(STR(?qualProp), STR(pq:)))   # only qualifiers

	    	# Map qualifier property to its property entity
    		BIND(IRI(REPLACE(STR(?qualProp), "prop/qualifier", "entity")) AS ?qualPropEntity)

	    	OPTIONAL {
    			?qualPropEntity rdfs:label ?qualPropLabel .
    			FILTER(LANG(?qualPropLabel) = "en")
    		}

    		OPTIONAL {
    			?qualValue rdfs:label ?qualValueLabel .
    			FILTER(LANG(?qualValueLabel) = "en")
    		}
		}
	}
	ORDER BY ?Label
	]]

	-- Executing the SPARQL query and retrieving results in JSON format
	local jsonResults = sparql.runQuery(sparqlQuery)
	-- Validate results
	if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
       	return "No specialized research fields found"
    end
	
	local listItems = {}
    -- Get the number of specialized research fields
	local totallistItems = #jsonResults.results.bindings
	-- Loop through the bindings
	for index = 0, totallistItems do
    	local item = jsonResults.results.bindings[index]
    	if not item.Label.value then
        	return "Error: Missing item.Label.value"
    	elseif not item.URL.value then
        	return "Error: Missing item.URL.value"
    	else
    		local label = item.Label.value
        	local url = item.URL.value
        	local numericId = url:match("Q(%d+)")
        	local urlRendered = "https://portal.mardi4nfdi.de/wiki/Model:" .. numericId
        	local qualValue = item.qualValueLabel or item.qualValue or ""
	        local labelWithUrl = string.format('[%s %s]', tostring(url), tostring(label))
	        if qualValue ~= "" then
	       		local qualValueWithUrl = string.format('[%s %s]', tostring(item.qualValue.value), tostring(item.qualValueLabel.value))
	        	local row = "| " .. labelWithUrl ..  " || (" ..  qualValueWithUrl .. ")"
    			table.insert(listItems, row)
	        else
        		table.insert(listItems, "| " .. labelWithUrl)
        	end
    	end
	end

	-- Construct the Wikitext table
	local wikitextTable = "{| class='wikitable'\n" .. table.concat(listItems, "\n|-\n") .. "\n|}"
	return wikitextTable
end


-- Function to get list with qualifier values and qualifier labels
function p.getListWithQualifierValuesLabels(frame)
	local entityId = frame.args[1]
    local propertyId = frame.args[2]
    
    -- Validate input parameter
    if not entityId or entityId == '' then
        return " "
    end
   
    -- Constructing the SPARQL query with dynamic entity entityId
    local sparqlQuery = [[
	PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
	SELECT ?URL ?Label ?qualPropEntity ?qualPropLabel ?qualValue ?qualValueLabel
	WHERE {
		entityId: p:]] .. propertyId .. [[  ?statement .
		?statement ps:]] .. propertyId .. [[ ?URL .
		?URL rdfs:label ?Label
		FILTER(LANG(?Label) = "en")

		OPTIONAL {
    		?statement ?qualProp ?qualValue .
    		FILTER(STRSTARTS(STR(?qualProp), STR(pq:)))   # only qualifiers

	    	# Map qualifier property to its property entity
    		BIND(IRI(REPLACE(STR(?qualProp), "prop/qualifier", "entity")) AS ?qualPropEntity)

	    	OPTIONAL {
    			?qualPropEntity rdfs:label ?qualPropLabel .
    			FILTER(LANG(?qualPropLabel) = "en")
    		}

    		OPTIONAL {
    			?qualValue rdfs:label ?qualValueLabel .
    			FILTER(LANG(?qualValueLabel) = "en")
    		}
		}
	}
	ORDER BY ?Label
	]]

	-- Executing the SPARQL query and retrieving results in JSON format
	local jsonResults = sparql.runQuery(sparqlQuery)
	-- Validate results
	if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
       	return "No specialized research fields found"
    end
	
	local listItems = {}
    -- Get the number of specialized research fields
	local totallistItems = #jsonResults.results.bindings
	-- Loop through the bindings
	for index = 0, totallistItems do
    	local item = jsonResults.results.bindings[index]
    	if not item.Label.value then
        	return "Error: Missing item.Label.value"
    	elseif not item.URL.value then
        	return "Error: Missing item.URL.value"
    	else
    		local label = item.Label.value
        	local url = item.URL.value
        	local numericId = url:match("Q(%d+)")
        	local urlRendered = "https://portal.mardi4nfdi.de/wiki/Model:" .. numericId
        	local qualValue = item.qualValueLabel or item.qualValue or ""
        	local qualPropLabel = item.qualPropLabel or "" 
	        local labelWithUrl = string.format('[%s %s]', tostring(url), tostring(label))
	        if qualValue ~= "" then
	       		local qualValueWithUrl = string.format('[%s %s]', tostring(item.qualValue.value), tostring(item.qualValueLabel.value))
	        	local row = "| " .. labelWithUrl ..  " || " ..  qualPropLabel.value .. " || " .. qualValueWithUrl 
    			table.insert(listItems, row)
	        else
        		table.insert(listItems, "| " .. labelWithUrl)
        	end
    	end
	end

	-- Construct the Wikitext table
	local wikitextTable = "{| class='wikitable'\n" .. table.concat(listItems, "\n|-\n") .. "\n|}"
	return wikitextTable
end


-- Function to get instance of types
function p.getInstanceOfTypes(frame)
	local entityId = frame.args[1]
    
    -- Validate input parameter
    if not entityId or entityId == '' then
        return "Error: No entity ID provided"
    end
    
    -- Constructing the SPARQL query with dynamic entity entityId
    -- P31: instance of property id
    local sparqlQuery = [[
PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
SELECT  ?InstanceOfTypeLabel WHERE {
  entityId: p:P31 ?statement .
  ?statement ps:P31 ?InstanceOfType .
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
ORDER BY ?InstanceOfTypeLabel
	]]


	-- Executing the SPARQL query and retrieving results in JSON format
	local jsonResults = sparql.runQuery(sparqlQuery)
	-- Validate results
	if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
    end
	
	local InstanceOfTypes = {}
    -- Get the number of model types
	local totalInstanceOfTypes = #jsonResults.results.bindings
	-- Loop through the bindings
	for index = 0, totalInstanceOfTypes  do
    	local item = jsonResults.results.bindings[index]
    	if item and item.InstanceOfTypeLabel and item.InstanceOfTypeLabel.value then
        	local label = item.InstanceOfTypeLabel.value
        	table.insert(InstanceOfTypes, label)
    	end
	end

	-- Construct the Wikitext table
	local wikitextTable = "{| class='wikitable'\n|-\n| " .. table.concat(InstanceOfTypes, " || ") .. "\n|}"
	return wikitextTable

end

-- Function to get instance of types
function p.getListNamedAfter(frame)
	local entityId = frame.args[1]
    
    -- Validate input parameter
    if not entityId or entityId == '' then
        return "Error: No entity ID provided"
    end
    
    -- Constructing the SPARQL query with dynamic entity entityId
    -- P31: instance of property id
    local sparqlQuery = [[
PREFIX entityId: <https://portal.mardi4nfdi.de/entity/]] .. entityId .. [[>
SELECT ?namedAfterLabel ?namedAfter
WHERE {
  entityId: p:P558 ?statement .
  ?statement ps:P558 ?namedAfter .
  SERVICE wikibase:label { bd:serviceParam wikibase:language "en". }
}
ORDER BY ?namedAfterLabel
	]]


	-- Executing the SPARQL query and retrieving results in JSON format
	local jsonResults = sparql.runQuery(sparqlQuery)
	-- Validate results
	if not jsonResults or not jsonResults.results or not jsonResults.results.bindings then
	end

	local ListNamedAfter = {}
    -- Get the number of persons named after
	local totalPersons = #jsonResults.results.bindings
	-- Loop through the bindings
	for index = 0, totalPersons  do
    	local item = jsonResults.results.bindings[index]
    	if item and item.namedAfterLabel and item.namedAfterLabel.value then
        	local label = item.namedAfterLabel.value
        	local url = item.namedAfter.value
        	local numericId = url:match("Q(%d+)")
    		local urlRendered = "https://portal.mardi4nfdi.de/wiki/Person:" .. numericId
        	local labelWithUrl = string.format('[%s %s]', tostring(urlRendered), tostring(label))
        	table.insert(ListNamedAfter,  labelWithUrl)
    	end
	end
	
	return table.concat(ListNamedAfter, ', ')
    
-- end of function getListNamedAfter
end
    


return p