Hoppa till innehållet

Modul:Wikidata

Från Wikipedia

Dokumentation [visa] [redigera] [historik] [rensa sidcachen]


Se även Modul:Wikidataen för viss skild funktionalitet

Modulen används för att hämta formatterad data från Wikidata.

anrop:

{{#invoke:Wikidata|formatStatements|property=p17}}

Parametrar

  • property = Obligatorisk parameter som beskriver vilken egenskap som ska hämtas.
  • entityId = Det id-nummer den artikel har som du vill hämta egenskap från.
  • enbarten = När bara ett värde ska hämtas. Tex för att hämta bild på heraldiskt vapen, och då inte få tillbaka alla objekt.
  • separator = När något annat än "," ska separera en lista på objekt. Tex separator=<br/> Se även conjunction
  • conjunction = Som ovan, men påverkar bara den sista separatorn i en lista av objekt. Default är och.
  • label = När man själv vill välja hur länken ska formateras. Tex [[Blekinge läns vapen|vapen]] fås av att ange label=vapen Den här parametern påverkar även enheter
  • pattern = När man vill hämta en sträng och passa in den i ett mönster, exempelvis för att lägga in en kod av något slag istället för $1 i https://viaf.org/viaf/$1/.
    • pattern = auktoritetsdata är ett specialfall av ovanstående. Det "pattern" som används, är då det som är angivet i P1630 (format för URL) för den berörda egenskapen.
    • pattern = auktoritetsdata2 kompletterar ovanstående och skapar en länk av typen [https://viaf.org/viaf/$1/ $1]
  • rank = Bestämmer vilken typ av påståenden som ska släppas igenom.
    • rank = all släpper igenom alla påståenden
    • rank = valid släpper igenom "preferred" och "normal", men inte "deprecated"
    • rank = best (default) släpper igenom "preferred", men om det inte finns släpps "normal" igenom
    • rank = preferred/normal/deprecated släpper igenom angiven rank, men ingen annan
  • avoidqualifier = Sorterar bort värden som är associerade med en viss egenskap i sin bestämning. Exempelvis avoidqualifier=P518 (berörd del) om man vill ha folkmängden för hela orten, inte bara de som är kvinnor eller den andel som bor i Haninge kommun.
  • nolink = Något värde tar bort länkar, även länkar till enheter görs olänkade.
    • nounitlink = samma som ovan, men påverkar bara enheter.
  • noshortunit = enheter förkortas inte med ett värde i denna parameter, d.v.s kilometer förkortas inte till km, vilket annars är standard.
  • sortbytime = sorterar påståenden efter datum i bestämningar, detta system används med fördel tillsammans med parameter enbarten ovan
    • sortbytime = chronological sorterar påståenden i kronologisk ordning i bestämningar
    • sortbytime = inverted sorterar påståenden i omvänd kronologisk ordning i bestämningar
  • sortingproperty = Ange vilken egenskap som ska stödas. Det går att lägga in en tabell i denna parameter, men då bara från en annan modul. Default är: 'P585','P571','P580','P569','P582','P570' i given ordning. Hittills stöds bara properties med datatype = time
  • sortbyarbitrary = sorterar påståenden efter datum de objekt som länkas i de olika uttalandena, exempelvis födelsedag för en rad av "barn". Tillåtna värden är 'chronological' eller 'inverted'. Vilken egenskap som ska sökas anges med parameter 'sortingproperty ovan'.


  • langpref = I denna modul finns det ett filter som prioriterar påståenden som har bestämningen "språk = svenska". Ett värde på parameter langpref inaktiverar detta filter
  • noref = Ange ett värde i denna parameter om du inte är intresserad av att ta med själva källhänvisningen, utan bara datan.
  • versalisering = För att ange vilken versalisering utdatan ska ha. Tillåtna värden är: lc/uc/lcfirst/ucfirst
    • firstversalisering = Samma som ovan, men påverkar bara det första i raden av värden
  • modifytime = fixar med datumformat
    • modifytime = longdate skriver datum på formatet "11 november 2024", dvs ner till datumnivå när så tillåts
    • modifytime = Y skriver datum på formatet "2024", dvs endast årtal.
  • modifyqualifiertime = Som ovan, men påverkar bara bestämningar
  • getsimpleproperty = För att hämta information från det länkade objektet. Denna funktion tillåter ingen iteration, utan går bara en nivå.
    • getproperty = Här anger du vilken egenskap du ska hämta med getsimpleproperty
    • getenbarten = Här anger du om en eller alla uttalanden ska hämtas med getsimpleproperty
    • getmodifytime = Här anger du vilket tidsformat getsimpleproperty ska hämta
    • getraw = Som "raw" nedan
  • raw = är en parameter som kan användas från andra moduler. Den resulterar i att utdatan kommer i en tabell.
  • novalue = En parameter som styr hur "novalue" på Wikidata ska presenteras här. Tomt värde ger 'nil' som resultat
  • somevalue = Som "novalue" ovan
  • relevans = Objekt som saknar en webbplatslänk till svwiki inte kommer att inkluderas.
  • prefix = Text läggs in före svaret
  • suffix = Text läggs in efter svaret
-- Den ordning fallback language hämtas, om svensk label saknas. Engelska först, därefter bokmål, danska, etc...
local fallback = {'en', 'nb', 'da', 'nn', 'de', 'fr', 'es', 'it', 'pt'}
local i18n = {
    ["errors"] = {
        ["property-param-not-provided"] = "Property parameter not provided.",
        ["entity-not-found"] = "Entity not found.",
        ["unknown-claim-type"] = "Unknown claim type.",
        ["unknown-snak-type"] = "Unknown snak type.",
        ["unknown-datatype"] = "Unknown datatype.",
        ["unknown-entity-type"] = "Unknown entity type.",
        ["unknown-value-module"] = "You must set both value-module and value-function parameters.",
        ["value-module-not-found"] = "The module pointed by value-module not found.",
        ["value-function-not-found"] = "The function pointed by value-function not found."
    },
    ["somevalue"] = "''unknown value''",
    ["novalue"] = "''no value''"
}
local sortingproperties = {'P585','P571','P580','P569','P582','P570'}

function getqualifierbysortingproperty(claim, sortingproperty)
	for k, v in pairs(sortingproperty) do
		if claim.qualifiers and claim.qualifiers[v] and claim.qualifiers[v][1].snaktype == 'value' then
			return claim.qualifiers[v][1].datavalue.value.time 
		end
	end
	return nil
end

function getDate(claim, options)
	local sortingproperty = sortingproperties
	if type(options.sortingproperty) == 'table' then
		sortingproperty = options.sortingproperty
	elseif type(options.sortingproperty) == 'string' then
		sortingproperty = {options.sortingproperty}
	end
	return getqualifierbysortingproperty(claim, sortingproperty) 
end

function comparedates(a, b) 
	if a and b then
		return a > b
	elseif a then
		return true
	end
end

function sortbyqualifier(claims, options)
	
	table.sort(claims, function(a,b)
		local timeA = getDate(a, options)
		local timeB = getDate(b, options)
		if options.sortbytime == 'inverted' then
			return comparedates(timeB, timeA)
		else
			return comparedates(timeA, timeB)
		end
	end
	)
	return claims
end

function getLabelFromFallBack( id ) 
	local entity = getEntityFromId( id )
 	for k, v in pairs(fallback) do
		if entity.labels[v] then
			return {value = entity.labels[v].value, language = entity.labels[v].language}
		end
	end
	-- Om inget fallback-språk finns av de i variabeln ovan, så används det först definierade i objektet
	if entity.labels then 
		for v, k in pairs(entity.labels) do
			return {value = k.value, language = k.language}
		end
	end
	return {value = '-', language = ''}
end

function getEntityFromId( id )
	if id then 
		return mw.wikibase.getEntityObject( id )
	else
		return mw.wikibase.getEntityObject() 
	end
end
 
function getEntityIdFromValue( value )
    if value['entity-type'] == 'item' then
        return 'Q' .. value['numeric-id']
    elseif value['entity-type'] == 'property' then
        return 'P' .. value['numeric-id']
    else
        return formatError( 'unknown-entity-type' )
    end
end
 
function formatError( key )
    return '<span class="error">' .. i18n.errors[key] .. '</span>'
end
 
 
function formatStatements( options, ref )
   	local formattedStatements = {}
   	local claims = {}
   	if not options.property then
       	return formatError( 'property-param-not-provided' )
   	end

    if type(ref) == 'table' then -- för de fall där funktionen anropas och alla claims redan finns i en tabell
		claims = ref[options.property]
	else
 
    	--Get entity
    	local entity = nil
    	if options.entity and type( options.entity ) == "table" then
        	entity = options.entity
    	else
        	entity = getEntityFromId( options.entityId )
    	end
 
    	if not entity then
        	return '' --TODO error?
    	end
 
    	if not entity.claims or not entity.claims[options.property:upper()] then
        	return '' --TODO error?
    	end
 
    	--Format statement and concat them cleanly
		if options.rank == 'best' or not options.rank then 
			claims = entity:getBestStatements( options.property:upper() )
		elseif options.rank == 'valid' then
			for i, statement in pairs( entity.claims[options.property:upper()] ) do
	    		if statement.rank == 'preferred' or statement.rank == 'normal' then
    				table.insert( claims, statement )
    			end
			end
		elseif options.rank == 'all' then
			for i, statement in pairs( entity.claims[options.property:upper()] ) do
				table.insert( claims, statement )
			end
		else
			for i, statement in pairs( entity.claims[options.property:upper()] ) do
				if statement.rank == options.rank then
					table.insert( claims, statement )
				end
			end
		end
		if options.avoidqualifier then
			local claims2 = {}
			for i, statement in pairs( claims ) do	
				if not statement.qualifiers or not statement.qualifiers[options.avoidqualifier:upper()] then
					table.insert( claims2, statement)
				end
			end
			claims = claims2
		end
		--om det finns vissa statements som har en qualifier som säger "språk = svenska", ta bara med dessa
		if not options.langpref or options.langpref == '' then
			local claims2 = {}
			for i, statement in pairs( claims ) do
				if statement.qualifiers and statement.qualifiers.P407 then
					for k, v in pairs( statement.qualifiers.P407 ) do
						if v.snaktype == 'value' and v.datavalue.value['numeric-id'] == 9027 then -- Q9027 = 'svenska'
							table.insert( claims2, statement )
						end
					end
				end
			end
			if #claims2 > 0 then
				claims = claims2
			end
		end
		if options.sortbytime == 'chronological' or options.sortbytime == 'inverted' then
			claims = sortbyqualifier(claims, options)
		end
	end
	if options.enbarten and options.enbarten ~= '' and #claims > 1 then
		claims = {claims[1]}
	end
	if claims then
		for i, statement in pairs( claims ) do	
			local s = formatStatement( statement, options ) 
			if s == '' then s = nil end
			if type(ref) == 'table' or (options.noref and options.noref ~='') then --Inte leta efter referenser om själva anropet görs från en referens
				table.insert( formattedStatements, s )
			else
				local t = ''--formatReferences( statement, options )
				table.insert( formattedStatements, s .. t )	
			end
		end
	end
	return mw.text.listToText( formattedStatements, options.separator, options.conjunction )
end
function formatReferences( statement, options )
	local reference = {}
	if statement.references then
		local cite = require('Modul:Cite')
		for i, ref in pairs(statement.references) do
			local items, s = {}, nil
			if ref.snaks then
				if ref.snaks.P248 then
					for j, prop in pairs(ref.snaks.P248) do
						table.insert(items, 'Q' .. prop.datavalue.value['numeric-id'])
					end
				end
				s = cite.citeitem( items, ref.snaks, options ) 
				if s == '' or not s then
					s = 'Källangivelsen på Wikidata använder propertys som inte känns igen av Modul:Cite'
				end
			end
			table.insert(reference, mw.getCurrentFrame():extensionTag( 'ref', s, {name = ref.hash} ) )
		end
	end
	return table.concat(reference)
end
function formatStatement( statement, options )
    if statement.type == 'statement' then
		return formatSnak( statement.mainsnak, options ).value 
	elseif not statement.type then
		return formatSnak( statement, options ).value --reference and qualifier
    end
	return formatError( 'unknown-claim-type' )
end
 
function formatSnak( snak, options )
    if snak.snaktype == 'somevalue' then
        return {value =  i18n['somevalue']}
    elseif snak.snaktype == 'novalue' then
        return {value = i18n['novalue']}
    elseif snak.snaktype == 'value' then
        return {value = formatDatavalue( snak.datavalue, options, snak.datatype ).value}
    else
        return {value = formatError( 'unknown-snak-type' )}
    end
end
 
function formatDatavalue( datavalue, options, datatype )
    --Use the customize handler if provided
    if options['value-module'] or options['value-function'] then
        if not options['value-module'] or not options['value-function'] then
            return {value = formatError( 'unknown-value-module' )}
        end
        local formatter = require ('Module:' .. options['value-module'])
        if not formatter then
            return {value = formatError( 'value-module-not-found' )}
        end
        local fun = formatter[options['value-function']]
        if not fun then
            return {value = formatError( 'value-function-not-found' )}
        end
        return {value = fun( datavalue.value, options )}
    end
 
    --Default formatters
    if datatype == 'wikibase-item' then
        return {value = formatEntityId( getEntityIdFromValue( datavalue.value ), options ).value}
        
    elseif datatype == 'string' or datatype == 'commonsMedia' then
        if options.pattern and options.pattern ~= '' then
        	if options.pattern == "auktoritetsdata" then
        		local patter = formatStatements( {property = "P1630", entityId = options.property, enbarten = 'true', noref = 'true' })
        		return {value = formatFromPattern( datavalue.value, {pattern = patter} )}
        	elseif options.pattern == "auktoritetsdata2" or options.pattern == 'auktoritetsdata3' then
        		local patter = formatStatements( {property = "P1630", entityId = options.property, enbarten = 'true', noref = 'true' })
        		return {value = '[' .. formatFromPattern( datavalue.value, {pattern = patter} ) .. ' ' .. datavalue.value .. ']' } 
        	else
            	return {value = formatFromPattern( datavalue.value, options )}
            end
        else
            return {value = datavalue.value}
        end
        
    elseif datatype == 'time' then
        local Time = require 'Module:Time'
        return {value = Time.newFromWikidataValue( datavalue.value ):toHtml()}
        
    elseif datatype == 'globe-coordinate' then
        local GlobeCoordinate = require 'Module:GlobeCoordinate'
        return {value = GlobeCoordinate.newFromWikidataValue( datavalue.value ):toHtml()}
    
	elseif datatype == 'quantity' then 
		local amount, unit, cat = datavalue.value.amount, datavalue.value.unit, nil
		if unit then
			unit = unit:match('Q%d+')
		end
		local formatera = require('Modul:Math')
		local number = formatera.newFromWikidataValue(datavalue.value)

		local unitraw = unit
		if unit then
			-- Kontrollerar om det finns någon förkortning för denna 'unit'
			local lab = options.label or formatStatements({property = 'P558', entityId = unit, enbarten = 'true', langpref = options.langpref, noref = 'true'})
			if lab and ( not options.nounitshort or options.nounitshort == '' )  then
				local s = formatEntityId( unit, {label = lab, nolink = (options.nounitlink or options.nolink) })
				unit = s.value
				cat = s.cat
			else -- om det inte finns en förkortning
				local s = formatEntityId( unit, {nolink = options.nounitlink})
				unit = s.value
				cat = s.cat
			end
		end
		return {value = number .. ' ' .. (unit or ''), amount = amount, unit = unit, unitraw = unitraw, cat = cat}
		
	elseif datatype == 'url' then
		if options.label and options.label ~= '' then
			return {value = '[' .. datavalue.value .. ' ' .. options.label .. ']'}
		else
			return {value = datavalue.value}
		end
		
	elseif datavalue.type == 'monolingualtext' then
		return {value = mw.text.tag('span', {title = mw.language.fetchLanguageName(datavalue.value.language, 'sv')}, datavalue.value.text)}
		
    else
        return {value = formatError( 'unknown-datatype' )}
    end
end
 
function formatEntityId( entityId, options )
	local label = options.label or mw.wikibase.label( entityId )
	if label == '' then
		label = mw.wikibase.label( entityId ) or nil
	end

    local link = mw.wikibase.sitelink( entityId )
    if link and (not options.nolink or options.nolink == '') then
        if label and label ~= '' then
            return {value = '[[:' .. link .. '|' .. label .. ']]' }
        else
            return {value = '[[:' .. link .. ']]' }
        end
    else
    	if label then
    		return {value = label}
    	else
    		local s = getLabelFromFallBack( entityId )
    		local l = mw.language.fetchLanguageName(s.language, 'sv')
    		if not l or l == '' then
    			l = 'okänt språk'
    		end
    		if s then
    			return {value = mw.text.tag('span', {title = l}, s.value), cat = 'med labels på ' .. l }
    		end
    	end
    	return {value = entityId, cat = 'som har labels med Qid'}
    end
end
 
function formatFromPattern( str, options )
    return mw.ustring.gsub( options.pattern, '$1', str ) .. '' --Hack to get only the first result of the function
end
 
local p = {}
 
function p.formatStatements( frame, key )
    local args = frame.args
 
    --If a value if already set, use it
    if args.value and args.value ~= '' then
        return args.value
    end
    return formatStatements( frame.args, key )
end
 
function p.formatStatementsFromLua( options, key )
    --If a value if already set, use it
    if options.value and options.value ~= '' then
        return options.value
    end
    local s = formatStatements( options, key )
    if s == '' then
    	s = nil
    end
    return s
end
 
-- Return the site link (for the current site) for a given data item.
function p.getSiteLink( frame )
    if frame.args[1] == nil then
        entity = mw.wikibase.getEntityObject()
        if not entity then
        	entity = mw.wikibase.getEntityObject(frame.args[1])
        end
        id = entity.id
    else
        id = frame.args[1]
    end
 
    return mw.wikibase.sitelink( id )
end

-- look into entity object
function p.ViewSomething(frame)
	local f = (frame.args[1] or frame.args.id) and frame or frame:getParent()
	local id = f.args.id
	if id and (#id == 0) then
		id = nil
	end
	local data = mw.wikibase.getEntityObject(id)
	if not data then
		return nil
	end

	local i = 1
	while true do
		local index = f.args[i]
		if not index then
			if type(data) == "table" then
				return mw.text.jsonEncode(data, mw.text.JSON_PRESERVE_KEYS + mw.text.JSON_PRETTY)
			else
				return tostring(data)
			end
		end
		
		data = data[index] or data[tonumber(index)]
		if not data then
			return
		end
		
		i = i + 1
	end
end

-- This is used to get the TA98 (Terminologia Anatomica first edition 1998) values like 'A01.1.00.005' (property P1323)
-- which are then linked to http://www.unifr.ch/ifaa/Public/EntryPage/TA98%20Tree/Entity%20TA98%20EN/01.1.00.005%20Entity%20TA98%20EN.htm
-- uses the newer mw.wikibase calls instead of directly using the snaks
-- formatPropertyValues returns a table with the P1323 values concatenated with ", " so we have to split them out into a table in order to construct the return string
p.getTAValue = function(frame)
	local ent = mw.wikibase.getEntityObject()
	local props = ent:formatPropertyValues('P1323')
	local out = {}
	local t = {}
	for k, v in pairs(props) do
		if k == 'value' then
			t = mw.text.split( v, ", ")
			for k2, v2 in pairs(t) do
				out[#out + 1] = "[http://www.unifr.ch/ifaa/Public/EntryPage/TA98%20Tree/Entity%20TA98%20EN/" .. string.sub(v2, 2) .. "%20Entity%20TA98%20EN.htm " .. v2 .. "]"
			end
		end
	end
	ret = table.concat(out, "<br> ")
	if #ret == 0 then
		ret = "Invalid TA"
	end
	return ret
end

return p