Module:PublicationAuthorList

From MaRDI portal

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

-- Required module containing helper methods
local helper = require('Module:HelperMethods')

-- Required modules for SPARQL queries and HTML table generation
local sparql = require('SPARQL')
local mwHtml = require('mw.html')

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

-- Function to convert JSON results into a comma-separated string
function p.convertJsonToCommaSeparatedList(jsonResults)
	local resultsString = ""
	
	if jsonResults and jsonResults.results and jsonResults.results.bindings then
        local bindings = jsonResults.results.bindings
        for i = 0, #bindings do
            local binding = bindings[i]
            if binding.valueLabel and binding.valueLabel.value then
                if resultsString ~= "" then
                    resultsString = resultsString .. ", "
                end
                
                local name = binding.valueLabel.value
                if string.find(name, "https://") then
                	name = helper.titleNotAvailableStr("Author name")
                end
                
                local link = binding.value.value
                
                if binding.isHuman and binding.isHuman.value == "Y" then
                	link = link:gsub("entity/Q", "wiki/Person:")
                end

                resultsString = resultsString .. helper.makeWikiLink(link, name)
            end
        end
    end

    return resultsString
end


function p.convertJsonToCommaSeparatedListTextOnly(jsonResults)
    local resultsString = ""

    if jsonResults and jsonResults.results and jsonResults.results.bindings then
        local bindings = jsonResults.results.bindings
        for i = 0, #bindings do
            local binding = bindings[i]
            if binding.value and binding.value.value then
                local name = binding.value.value

                if resultsString ~= "" then
                    resultsString = resultsString .. ", "
                end

                resultsString = resultsString .. name  
            end
        end
    end

    return resultsString
end


-- Function to build the list
function p.buildAuthorList(frame)
	
    -- Retrieve target1 from frame arguments or return error message if not set
	local target1 = frame.args[1]
    if not target1 or target1 == '' then
        return "No ID given"
    end    
    
    -- ── Query P16: linked author entities with ordinal ──
    local sparqlQueryP16 = [[
PREFIX target1: <https://portal.mardi4nfdi.de/entity/]] .. target1 .. [[>
PREFIX wdt: <https://portal.mardi4nfdi.de/prop/direct/>
PREFIX wd: <https://portal.mardi4nfdi.de/entity/>
PREFIX p: <https://portal.mardi4nfdi.de/prop/>
PREFIX ps: <https://portal.mardi4nfdi.de/prop/statement/>
PREFIX pq: <https://portal.mardi4nfdi.de/prop/qualifier/>
PREFIX wikibase: <http://wikiba.se/ontology#>
PREFIX bd: <http://www.bigdata.com/rdf#>

SELECT DISTINCT ?value ?valueLabel ?property ?propertyLabel ?isHuman ?seriesOrdinal
WHERE {
  {
    SELECT ?value ?seriesOrdinal ?isHuman WHERE {
      target1: p:P16 ?authorstatement .
      ?authorstatement ps:P16 ?value .
      BIND(IF(EXISTS { ?value wdt:P31 wd:Q57162 }, "Y", "N") AS ?isHuman)
      OPTIONAL { ?authorstatement pq:P146 ?seriesOrdinal. }
    }
  }
  BIND(wdt:P16 AS ?property)
  SERVICE wikibase:label { bd:serviceParam wikibase:language "[AUTO_LANGUAGE],en". }
}
ORDER BY xsd:integer(?seriesOrdinal)
    ]]

    -- ── Query P43: author name strings with ordinal ──
    local sparqlQueryP43 = [[
PREFIX target1: <https://portal.mardi4nfdi.de/entity/]] .. target1 .. [[>
PREFIX wdt: <https://portal.mardi4nfdi.de/prop/direct/>
PREFIX wd: <https://portal.mardi4nfdi.de/entity/>
PREFIX p: <https://portal.mardi4nfdi.de/prop/>
PREFIX ps: <https://portal.mardi4nfdi.de/prop/statement/>
PREFIX pq: <https://portal.mardi4nfdi.de/prop/qualifier/>
PREFIX wikibase: <http://wikiba.se/ontology#>
PREFIX bd: <http://www.bigdata.com/rdf#>

SELECT DISTINCT ?value ?seriesOrdinal
WHERE {
  target1: p:P43 ?authorstatement .
  ?authorstatement ps:P43 ?value .
  OPTIONAL { ?authorstatement pq:P146 ?seriesOrdinal. }
}
ORDER BY xsd:integer(?seriesOrdinal)
    ]]

    local jsonP16 = sparql.runQuery(sparqlQueryP16)
    local jsonP43 = sparql.runQuery(sparqlQueryP43)

    local countP16 = 0
    local countP43 = 0

    if jsonP16 and not jsonP16.error then
        countP16 = helper.countElementsInBindings(jsonP16.results.bindings)
    end
    if jsonP43 and not jsonP43.error then
        countP43 = helper.countElementsInBindings(jsonP43.results.bindings)
    end

    -- ── Only P16 ──
    if countP16 > 0 and countP43 == 0 then
        return p.convertJsonToCommaSeparatedList(jsonP16)
    end

    -- ── Only P43 ──
    if countP43 > 0 and countP16 == 0 then
        return p.convertJsonToCommaSeparatedListTextOnly(jsonP43)
    end

    -- ── Both P16 and P43: merge by ordinal ──
    if countP16 > 0 and countP43 > 0 then
        -- Build a combined list keyed by ordinal
        local authors = {}  -- {ordinal, text}

        local bindings16 = jsonP16.results.bindings
        for i = 0, #bindings16 do
            local b = bindings16[i]
            if b and b.valueLabel and b.valueLabel.value then
                local name = b.valueLabel.value
                if string.find(name, "https://") then
                    name = helper.titleNotAvailableStr("Author name")
                end
                local link = b.value.value
                if b.isHuman and b.isHuman.value == "Y" then
                    link = link:gsub("entity/Q", "wiki/Person:")
                end
                local ordinal = b.seriesOrdinal and tonumber(b.seriesOrdinal.value) or nil
                table.insert(authors, {ordinal = ordinal, text = helper.makeWikiLink(link, name)})
            end
        end

        local bindings43 = jsonP43.results.bindings
        for i = 0, #bindings43 do
            local b = bindings43[i]
            if b and b.value and b.value.value then
                local ordinal = b.seriesOrdinal and tonumber(b.seriesOrdinal.value) or nil
                table.insert(authors, {ordinal = ordinal, text = b.value.value})
            end
        end

        -- Sort by ordinal (nil ordinals go to end)
        table.sort(authors, function(a, b)
            if a.ordinal and b.ordinal then return a.ordinal < b.ordinal end
            if a.ordinal then return true end
            return false
        end)

        local parts = {}
        for _, entry in ipairs(authors) do
            table.insert(parts, entry.text)
        end
        return table.concat(parts, ", ")
    end

    -- ── Fallback: nothing found ──
    return nil
end

-- Return the created html table
return p