Module:Settlement Wikidata

require('strict')

local p = {}

-- Is the string a valid QID?
local function validQid(qid)
    return qid and mw.ustring.find(qid,"^[Qq]%d+$")
end

-- lookup nestedIndex in outer table
-- Example:  fetchNested(foo,{'bar','baz','quux'}) will return
--     foo.bar and foo.bar.baz and foo.bar.baz.quux
local function fetchNested(outer,nestedIndex)
    if not outer or type(outer) ~= 'table' or not nestedIndex or type(nestedIndex) ~= 'table' then
        return nil
    end
    local current = outer
    for _, indx in ipairs(nestedIndex) do
        current = current[indx]
        if not current then
            return current
        end
    end
    return current
end

-- Mapping from wikidata properties (of a reference or "stated in" entity) to citation parameters
local pid2param = {
    P50 = "author",
    P123 = "publisher",
    P407 = "language",
    P577 = "date",
	P585 = "date",
    P813 = "access-date",
    P854 = "url",
    P856 = "url",
    P953 = "url",
    P1476 = "title",
    P2699 = "url",
}

-- scan through snaks, loading citation args with correct values
local function scanSnaks(args, snaks)
    for pid, data in pairs(snaks) do
        data = fetchNested(data,{1,'mainsnak'}) or data[1] -- handle the case where the snak is buried in the claims
        local param = pid2param[pid]
        if pid == "P248" then  --- "stated in": must look up different entity for data
            local statedId = fetchNested(data,{'datavalue','value','id'})
            local statedEntity = statedId and mw.wikibase.getEntity(statedId)
            local statedClaims = statedEntity and statedEntity.claims
            if statedClaims then
                scanSnaks(args, statedClaims)
            end
            local statedLabel = fetchNested(statedEntity,{'labels','en','value'})
            args.title = args.title or statedLabel
        elseif param then
            local renderedData = data and mw.wikibase.renderSnak(data)
            if param == "title" then
                -- set language from title if not otherwise specified
                args.language = args.language or fetchNested(data,{'datavalue','value','language'})
            end
            if pid == "P856" then --- use official URL only if URL is missing
                args[param] = args[param] or renderedData
            else
                args[param] = renderedData
            end
        end
    end
end

-- In some situations (e.g., France census) we want to link to a specific data page instead of
-- a generic census landing page. urlMap is a list of tuples:
-- (url to substitute, property to use in the substitution, url to use in the substitution)
-- the url to use in the substitution has ***** where it wants to swap in the property
local urlMap = {
{'https://www.insee.fr/fr/statistiques/8681011','P374','https://www.insee.fr/fr/statistiques/8643952?geo=COM-*****'},
{'https://www.insee.fr/fr/statistiques/8290669','P374','https://www.insee.fr/fr/statistiques/8288323?geo=COM-*****'}
}

local function mapURL(qid,origURL)
    if not qid or not origURL then
        return origURL
    end
    for _, mapper in ipairs(urlMap) do
        if origURL == mapper[1] then
            local statements = mw.wikibase.getBestStatements(qid,mapper[2])
            for _, statement in ipairs(statements) do
                local prop = fetchNested(statement,{'mainsnak','datavalue','value'})
                if prop then
                    return mw.ustring.gsub(mapper[3],'*****',prop)
                end
            end
        end
    end
    return origURL
end

-- function to assemble wikicode to create citation, given reference property
local function citeSource(qid,snaks)
    local args = {}
    args.mode = "cs1"
    scanSnaks(args, snaks)
    args.url = mapURL(qid,args.url)
    -- citation templates are unhappy without a title, so return a wikilink
    if not args.title then  
        return args.url and "["..args.url.."]"
    end
    if not args.url then
        args["access-date"] = nil  -- don't allow access date without url
    end
    local result = '{{'..(args.url and 'cite web' or 'citation')
    for k,v in pairs(args) do
        result = result..'|'..k..'='..v
    end
    result = result..'}}'
    return result
end

local rankToNumeric = {truth = 3, preferred = 2, normal = 1, deprecated = -1}

local function numericRank(rank)
   if not rank then
       return 0
   end
   return rankToNumeric[rank] or 0
end

local function compareRanks(rank1,rank2)
   local numeric1 = numericRank(rank1)
   local numeric2 = numericRank(rank2)
   if numeric1 > numeric2 then
       return 1
   elseif numeric1 < numeric2 then
       return -1
   else
       return 0
   end
end

-- Core function that looks up value, reference, and data for property
-- Arguments:
--   qid = entity id in Wikidata
--   pid = property id on that entity
--   unit = if non-nil, desired unit for value (expressed as a qid for that unit)
-- Returns table only if Wikidata property is source externally
--   amount = value that is looked up (or nil)
--   source = wiki markup for reference
--   asOf = date that value is valid (if given)
function p._getValueAndRef(qid,pid,unit)
    local results = nil
    local storedDate = nil
    local storedRank = nil
    local statements = mw.wikibase.getAllStatements(qid, pid) 
    for _, statement in pairs(statements) do
        local amount
        local value = fetchNested(statement,{'mainsnak','datavalue','value'})
        if value then
            amount = value.amount
        end
        -- check if unit is correct, if given
        if unit then
            local storedUnit = value.unit
            if not storedUnit or not mw.ustring.find(value.unit or '',unit,1,true) then
                amount = nil
            end
        end
        local storedAsOf = fetchNested(statement,{'qualifiers','P585',1,'datavalue','value','time'})
        local date
        if storedAsOf then
            date = mw.ustring.match(storedAsOf,'^%+(%d+%-%d+%-%d+)')
            local justYear = mw.ustring.match(date,'^(%d+)%-0+%-0+$')
            date = justYear or date
        end
        local rank = fetchNested(statement,{'rank'})
        -- check to see if this statement is adequately sourced (filter out "imported from" refs)
        local source
        local refs = statement['references']
        if refs then
            for _, ref in ipairs(refs) do
                local renderedRef = ref.snaks and mw.wikibase.renderSnaks(ref.snaks)
                if renderedRef and not mw.ustring.find(renderedRef,'Wiki') then
					local citation = citeSource(qid,ref.snaks)
					if citation then
				        source = (source or '')..'<ref>'..citation..'</ref>'
					end
                end
            end
        end
        if amount and source then -- yes, it is adequately sourced,
            local theseResults = {}
            theseResults.amount = tonumber(amount)
            theseResults.source = source
            theseResults.asOf = date
			local betterRank = compareRanks(rank,storedRank)
			-- ranking logic:
			-- 1. Higher ranked statements are better than lower ranked
			-- 2. At the same rank, dated statements are better than undated
			-- 3. Between dated statements at the same rank, choose the latest one
			-- 4. All else being equal, choose the first statement
			-- 5. Ignore deprecated statements
		    if betterRank > 0 or (betterRank == 0 and date and (not storedDate or date > storedDate)) then
                results = theseResults
                storedDate = date
                storedRank = rank
			end
        end
    end
    return results
end

-- for a qid, find the entity's population
-- if asOf is specified, prefer that population value
function p._population(qid)
    return p._getValueAndRef(qid,"P1082",nil)
end

-- for a qid, find the area of the entity in square kilometers
function p._area(qid)
    return p._getValueAndRef(qid,"P2046","Q712226") -- look for square kilometers only
end

-- main entry point
-- Arguments:
--   args[1] = name of infobox parameter to lookup in Wikidata (e.g., "area_total_km2" or "population_footnotes")
--   args[2] = date format for returned date
--   country = name of country which contains entity
--   qid = qid for entity (for testing, by default, use qid of current page)
-- Returns (depending on args[1]):
--   the value of the population or area, or
--   a reference for the value, or
--   the date the value is valid
function p._main(args)
    local country = args.country
    local param = args[1]
    local qid = validQid(args.qid) and args.qid or mw.wikibase.getEntityIdForCurrentPage()
    if not param or not qid then
        return nil
    end
    qid = qid:upper()
    country = country and string.lower(country)
    param = string.lower(param)
    --- France infobox is narrow, so display only year (unless otherwise specified)
    args[2] = args[2] or country == "france" and 'y'
    local results
    -- currently supports area and population: check for substring in parameter
    local wantArea = mw.ustring.find(param,"area",1,true)
    local wantPop = mw.ustring.find(param,"population",1,true)
    if wantArea then
        results = p._area(qid)
    elseif wantPop then
        results = p._population(qid)
    end
    if not results then
        return nil
    elseif mw.ustring.find(param,"as_of",1,true) then
        -- return date of validity
        if not results.asOf then
            return nil
        end
        --- if asOf has only year, return it
        if mw.ustring.find(results.asOf,'^%d+$') then
            return results.asOf
        end
        local lang = mw.getContentLanguage()
        if args[2] == "ymd" then
            return lang:formatDate("Y-m-d",results.asOf)
        elseif args[2] == "dmy" then
            return lang:formatDate("j F Y",results.asOf)
        elseif args[2] == "mdy" then
            return lang:formatDate("F j, Y",results.asOf)
        elseif args[2] == "y" then
            return lang:formatDate("Y",results.asOf)
        else
            return results.asOf
        end
    elseif mw.ustring.find(param,"footnotes",1,true) then
        if not results.source then
            return nil
        end
        -- run the pre-processor exactly once if returning a reference, because otherwise you get multiple (unused) reference
        local frame = mw.getCurrentFrame()
        return frame:preprocess(results.source)
    elseif wantArea and mw.ustring.find(param,"km2",1,true) then
        -- if parameter is for area in km2, return value
        return results.amount
    elseif wantPop then
        return results.amount
    end
    -- either parameter unrecognized or something bad happened
    return nil
end

-- template-facing entry point: do the usual argument processing
function p.main(frame)
    local getArgs = require('Module:Arguments').getArgs
    local args = getArgs(frame)
    return p._main(args) or ""
end

return p

Content Disclaimer

Informasi ini disarikan dari Wikipedia dan disajikan kembali untuk tujuan edukasi. Konten tersedia di bawah lisensi CC BY-SA 3.0. Kami tidak bertanggung jawab atas ketidakakuratan data yang bersumber dari kontribusi publik tersebut.

  1. The information displayed on this website is sourced in part or in whole from Wikipedia and has been adapted for the purpose of restating it. We strive to provide accurate and relevant information, however:
  2. There is no guarantee of absolute accuracy. Wikipedia is an open, collaborative project that can be edited by anyone, so information is subject to change.
  3. It is not intended to constitute professional advice. The content displayed is for informational and educational purposes only. For important decisions (e.g., medical, legal, or financial), please consult a professional.
  4. Content copyright. Wikipedia is licensed under the Creative Commons Attribution-ShareAlike License (CC BY-SA). This means that content may be reused with appropriate attribution and shared under a similar license.
  5. Responsible use. Any risk arising from the use of information from this website is entirely the responsibility of the user.