Ir al contenido

Módulo:Wikidata

De Wikisource, la biblioteca libre.
Documentación del módulo


Uso

Este módulo devuelve el valor o valores con o sin formato específico a una propiedad de Wikidata.

Funciones

  • claim: Devuelve el valor (o los valores) de una declaración o de un calificador con un formato por defecto según el tipo de dato.
  • badge: Devuelve el valor de la insígnia (badge) de una obra enlazada en Wikidata.

Función claim

Devuelve el valor (o los valores) de una declaración o de un calificador con un formato por defecto según el tipo de dato. Por defecto está referido al ítem de Wikidata (Qid) asociado a la página actual.

Sintaxis completa:

{{#invoke:Wikidata|claim|item= |lang= |property= |qualifier= |list= |formatting= }}

Parámetros generales

  • item= (opcional) Permite indicar un ítem (Qid) diferente al ítem asociado a la página actual. Ha de usarse con moderación por su alto consumo de recursos.
  • lang= (opcional) Permite indicar el código de un idioma determinado.
  • property= (obligatorio) Identificador de la propiedad de la declaración (Pid). Por ejemplo "P50".
  • qualifier= (opcional) Calificador (Pid) del valor de la propiedad.
  • list= (opcional):
    • list=true (por defecto): Muestra una lista de todos los valores, separados con un "separador" por defecto y una "conjunción" predefinida.
    • list=false: sólo recuperará un valor, generalmente el de mayor rango o el más antiguo.
  • formatting= (opcional): tipo de formato. Depende del valor de la entidad (ver código fuente). Ejemplos habituales: "raw", "label", "sitelink"...

Ejemplos

  • Wikidata.claim{item=Q107297266, property="P50", lang="es", list=true} devuelve los autores (propiedad P50) del ítem Q107297266 (edición de 1864 de El Robinson suizo).


Función badge

Devuelve la insignia (badge) de una obra enlazada en Wikidata a partir de su identificador o del valor correspondiente en el índice. Valores devueltos posibles: no corregido (no corregido), corregida (corregida), validada (validada), o problemática (problemática). Ha de existir la página y la insignia debe corresponder a uno de estas cuatro (si no, el valor devuelto es nulo).

{{#invoke:Wikidata|badge|qid=|indicator=|ws=}}

  • qid= es el identificador de la obra en Wikidata.
  • indicator= si tiene cualquier valor, envuelve la insignia en la etiqueta <indicator> y la muestra en la parte superior de la página (no funciona en móviles, solo escritorio).
  • ws= devuelve la insignia correspondiente según el valor del parámetro "progreso" en los índices. C = no corregido, V = corregido, T = validado, E = problemática.
Por ejemplo, {{#invoke:Wikidata|badge|qid=Q30097675}} = corregida («Q30097675» corresponde al identificador de Lecciones Matemáticas).
Esta documentación está transcluida desde Módulo:Wikidata/doc.
Los editores pueden experimentar en la zona de pruebas de este módulo.
Por favor, añade las categorías e interwikis a la subpágina de documentación. Subpáginas de este módulo.

--[[*********************************************************************************
	* Nombre: Módulo:Wikidata
	*
	* Descripción: Este módulo devuelve el valor o valores con o sin formato
	* específico a una propiedad de Wikidata.
	*
	* Fecha última revisión: 2 de mayo de 2019.
	*
	* Estado: En uso.
	*
	*********************************************************************************`-- ]]

local p = {}
local datequalifiers = {'P585', 'P571', 'P580', 'P582'}
local es = mw.language.new('es')
local primera = true
--local marco Ojo. marco no debe definirse como local pues si se hace así puede fallar.
 --[[ =========================================================================
			Mensajes de error
	  ========================================================================= `-- ]]

local avisos = {
	["errores"] = {
		["property-param-not-provided"] = "Parámetro de la propiedad no proporcionado.",
		["entity-not-found"] = "Entrada no encontrada.",
		["unknown-claim-type"] = "Tipo de notificación desconocida.",
		["unknown-snak-type"] = "Tipo de dato desconocido.",
		["unknown-datavalue-type"] = "Formato de dato desconocido.",
		["unknown-entity-type"] = "Tipo de entrada desconocido.",
		["unknown-value-module"] = "Debe ajustar ambos parámetros de valor y el valor del módulo de funciones.",
		["value-module-not-found"] = "No se ha encontrado el módulo apuntado por valor-módulo.",
		["value-function-not-found"] = "No se ha encontrado la función apuntada por valor-función.",
		["qualifier-not-found"] = "Qualifier not found.",
		["other entity"] = "Enlaces a elementos diferentes desactivado."
	},
	["somevalue"] = "''valor desconocido''",
	["novalue"] = ""
}

-- Módulos y funciones utilizadas
local elementoTabla = require('Módulo:Tablas').elemento
--
-- Módulos en los que están definidos los tipos de datos más habituales si son
-- diferentes de Wikidata/Formatos
--
local modulosTipos	=  {
	['altura']		= 'Módulo:Wikidata/Formato magnitud',
	['área']		= 'Módulo:Wikidata/Formato magnitud',
	['educado en']	= 'Módulo:Wikidata/Formatos educación',
	['imagen']		= 'Módulo:Wikidata/Formato imagen',
	['lugar']		= 'Módulo:Wikidata/Formato lugar',
	['formatoLugar']= 'Módulo:Wikidata/Formato lugar',
	['magnitud']	= 'Módulo:Wikidata/Formato magnitud',
	['movimiento']	= 'Módulo:Wikidata/Formato movimiento',	
	['periodicidad']= 'Módulo:Wikidata/Formato magnitud',
	['premio']		= 'Módulo:Wikidata/Formato premio',
}

 --[[ =========================================================================
	  Función para pasar el frame cuando se usa en otros módulos.	 
	 ========================================================================= `-- ]]
function p:setFrame(frame)
	marco = frame
end
 --[[ =========================================================================
	  Función para identificar el ítem correspondiente a la página o otro dado.
			  Esto último aún no funciona.	 
	 ========================================================================= `-- ]]

function SelecionEntidadPorId( id )

		if id and id ~= ''  then
			return mw.wikibase.getEntityObject( id )
		else
			return mw.wikibase.getEntityObject()
		end

end

 --[[ =========================================================================
	  Función que identifica si el valor devuelto es un ítem o una propiedad
	  y en función de eso añade el prefijo correspondiente	
	 ========================================================================= `-- ]]

function SelecionEntidadPorValor( valor )
	local prefijo = ''
	if valor['entity-type'] == 'item' then
		prefijo = 'q' -- Prefijo de ítem
	elseif valor['entity-type'] == 'property' then
		prefijo = 'p' -- Prefijo de propiedad
	else
		return formatoError( 'unknown-entity-type' )
	end
	return prefijo .. valor['numeric-id'] -- Se concatena el prefijo y el código numérico
end

 --[[ =========================================================================
	  Función auxiliar para dar formato a los mensajes de error	 
	 ========================================================================= `-- ]]

function formatoError( clave )
	return '<span class="error">' .. avisos.errores[clave] .. '</span>'
end
 --[[ =========================================================================
	  Función para determinar el rango	
	 ========================================================================= `-- ]]
function getRango(tablaDeclaraciones)

	local rank = 'deprecated'

	for indice, declaracion in pairs(tablaDeclaraciones) do
		if declaracion.rank == 'preferred' then
			return 'preferred'
		elseif declaracion.rank == 'normal' then
			rank = 'normal'
		end
	end

	return rank
end

 --[[ =========================================================================
	  Función para determinar la declaracion o declaraciones de mayor rango	
	 ========================================================================= `-- ]]
function filtrarDeclaracionPorRango(tablaDeclaraciones)
	local rango = getRango(tablaDeclaraciones)
	local tablaAuxiliar = tablaDeclaraciones
	tablaDeclaraciones = {}

	for indice, declaracion in pairs(tablaAuxiliar) do
		if declaracion.rank == rango then
			table.insert(tablaDeclaraciones, declaracion)
		end
	end
	return tablaDeclaraciones
end

 --[[ =========================================================================
	  Función para seleccionar el tipo de declaración: Referencia, valor principal
	  o calificador	 
	 ========================================================================= `-- ]]

function seleccionDeclaracion(declaracion, opciones)
	local fuente = {}
	local propiedadFuente = {}
	local calificador = opciones.formatoCalificador ~= '()' and opciones.calificador

	if calificador ~= '' and calificador  and declaracion['qualifiers'] then
		if declaracion['qualifiers'][mw.ustring.upper(calificador)] then
			return declaracion.qualifiers[mw.ustring.upper(calificador)][1] -- devuelve el calificador (solo devolverá el primer valor)
		else
			return "" --Para que no lance excepción si no existe el calificador
		end
	elseif opciones.dato == 'fuente' and declaracion['references'] then
		fuente = declaracion.references[1]['snaks']
		for k,v in pairs(fuente) do
			propiedadFuente = k
		end
		return declaracion.references[1]['snaks'][propiedadFuente][1]  -- devuelve la fuente (queda que se itinere la tabla)
	elseif (calificador == '' or not calificador) and (opciones.dato ~= 'fuente') then
		return declaracion.mainsnak -- devuelve el valor principal
	else
		return ''	
	end
end

 --[[ =========================================================================
	  Función para recopilar las declaraciones	 
	 ========================================================================= `-- ]]

function p.getDeclaraciones(entityId)


	-- == Comprobamos que existe un ítem enlazado a la página en Wikidata ==
	if not pcall (SelecionEntidadPorId, entityId ) then
		return false
	end
	local entidad  = SelecionEntidadPorId(entityId)

	if not entidad then
		return  '' -- Si la página no está enlazada a un ítem no devuelve nada
	end

	-- == Comprobamos que el ítem tiene declaraciones (claims) ==

	if not entidad.claims then
		return '' -- Si el ítem no tiene declaraciones no devuelve nada
	end
	-- == Declaración de formato y concatenado limpio ==

	return entidad.claims
end

 --[[ =========================================================================
	  Función para  crear la cadena que devolverá la declaración	
	 ========================================================================= `-- ]]
	
local function valinQualif(claim, qualifs)
	local claimqualifs = claim.qualifiers
	local i,qualif
	local vals, vals1, datavalue, value
	
	if not claimqualifs then
		return nil
	end
	for i, qualif in pairs(qualifs) do
		vals = claimqualifs[qualif]
		if vals then
			vals1 = vals[1]
			if vals1 then
				datavalue=vals1.datavalue
				
				if datavalue then
					value = datavalue.value
					
					if value then
						return value.time
					end
				end
			end
		end
	end
end	

function p.getPropiedad(opciones, declaracion)
	local propiedad	 = {}
	local tablaOrdenada = {}

	if opciones.propiedad == 'precisión' or opciones.propiedad == 'latitud' or opciones.propiedad == 'longitud'  then
		propiedad = 'P625' -- Si damos el valor latitud, longitud o precisión equivaldrá a dar p625
	else
		propiedad = opciones.propiedad -- En el resto de casos se lee lo dado
	end

	if not propiedad then -- Comprobamos si existe la propiedad dada y en caso contrario se devuelve un error
		return formatoError( 'property-param-not-provided' )
	end

	if declaracion then
		tablaOrdenada = declaracion
	elseif not p.getDeclaraciones(opciones.entityId) then
		return formatoError( 'other entity' )
	elseif p.getDeclaraciones(opciones.entityId)[mw.ustring.upper(propiedad)] then
		tablaOrdenada = p.getDeclaraciones(opciones.entityId)[mw.ustring.upper(propiedad)]
	else
		return ''
	end

	-- Evitar que pete cuando se haga el find en opciones['formatoTexto'] si vale nil
	if not opciones['formatoTexto'] then
		opciones['formatoTexto'] = ''
	end

	--Dejar en su caso los valores de mayor rango
	if (opciones.rangoMayor == 'sí') then
		tablaOrdenada = filtrarDeclaracionPorRango(tablaOrdenada)
	end

	--Ordenar en su caso por fecha. Ver la función chronosort de :fr:Module:Wikidata/Récup
	if opciones.ordenar == 'por fecha' then
		require('Módulo:Tablas').ordenar(tablaOrdenada,
			function(elemento1,elemento2)
				local fecha1 = valinQualif(elemento1, datequalifiers) or '' -- elemento1.qualifiers.P580[1].datavalue.value.time or ''
				local fecha2 = valinQualif(elemento2, datequalifiers) or '' -- elemento2.qualifiers.P580[1].datavalue.value.time or ''
				
				return fecha1 < fecha2
			end
		 )
	end
	
	if not tablaOrdenada[1] then
		return
	end

	-- == Si solo se desea que devuelva un valor ==
	-- Pendiente eliminar el parámetro y sustituirlo por un nuevo valor del parámetro lista=no que haría lo mismo que opciones.uno = sí
	if opciones.uno == 'sí' then -- Para que devuelva el valor de índice 1
		tablaOrdenada = {tablaOrdenada[1]}
	elseif opciones.uno == 'último' then -- Para que devuelva la última entrada de la tabla
		tablaOrdenada = {tablaOrdenada[#tablaOrdenada]}
	end

-- == Creamos una tabla con los valores que devolverá ==

	local formatoDeclaraciones = {}
	local hayDeclaraciones
	
	for indice, declaracion in pairs(tablaOrdenada) do
   		declaracionFormateada = p.formatoDeclaracion(declaracion, opciones)
   		if declaracionFormateada and declaracionFormateada ~= '' then
		   	table.insert(formatoDeclaraciones, declaracionFormateada)
		   	hayDeclaraciones = true
	   	end	
   	end
   	
	primera = true
	
	if not hayDeclaraciones then
		return
	end

	-- Aplicar el formato a la lista de valores según el tipo de lista de las
	-- opciones
	local listaDeclaraciones = mw.text.listToText( formatoDeclaraciones, '</li><li>', '</li><li>' )
	-- Añadir en su caso un lápiz
	if opciones.linkback == 'sí' then
		listaDeclaraciones = p.addLinkback( listaDeclaraciones, opciones.entityId, opciones.propiedad )
	end
	if opciones['lista'] == 'no ordenada' then
		return '<ul><li>' .. listaDeclaraciones .. '</li></ul>'
	elseif opciones['lista'] == 'ordenada' then
		return '<ol><li>' .. listaDeclaraciones .. '</li></ol>'			
	elseif opciones['lista'] == 'nobullet' then
		return '<ul style="list-style-type:none;list-style-image:none;margin-left:0;"><li>' .. listaDeclaraciones .. '</li></ul>'						
	else
	 	-- valores separados por coma o por el separador y la
	  	-- conjunción de las opciones
	   	local separador, conjuncion
			
		if opciones['conjunción'] == 'null' then
			conjuncion = nil
		else
			conjuncion = opciones['conjunción']
		end
	
		if opciones['separador'] == 'null' then
			separador	= nil
		else
			separador = opciones['separador']
		end
		
		if table.getn(formatoDeclaraciones) > 1 then
			if not conjuncion then
				conjuncion = 'y'
			end
			if marco and conjuncion == 'y' then
				conjuncion = ' ' .. string.sub(marco:preprocess('{{y-e|{{Desvincular|' .. formatoDeclaraciones[#formatoDeclaraciones] .. '}}}}'), 1, 1) .. ' '
			elseif conjuncion == 'y' or conjuncion == 'o' then
				conjuncion = ' ' .. conjuncion .. ' '
			end
		end
		
		-- Añadir en su caso un lápiz
		if opciones.linkback == 'sí' then
			return p.addLinkback(mw.text.listToText( formatoDeclaraciones, separador,conjuncion ), opciones.entityId, opciones.propiedad)  		
		else
			return mw.text.listToText( formatoDeclaraciones, separador, conjuncion )
		end
	end
end

-- Función que sirve para comprobar si una entidad tiene una propiedad con un
-- valor específico
-- Parámetros:
--   · entidad: tabla de la entidad de Wikidata
--   · propiedad: identificador de Wikidata para la propiedad
--   · valor: valor de la propiedad en Wikidata
function p.tieneValorPropiedad(entidad, propiedad, valor)
	
	if entidad and entidad.claims and entidad.claims[propiedad] then
		
		local mainsnak
		
		for key,value in ipairs(entidad.claims[propiedad]) do
			if value and value.mainsnak then
				mainsnak = value.mainsnak
				if mainsnak.datatype == 'wikibase-item' and
						mainsnak.snaktype == 'value' and
						mainsnak.datavalue.value.id == valor then
					return true
				end
			end
		end
	end
	
	return false
end

-- Función que sirve para devolver la leyenda (P2096) de una imagen (P18) en Wikidata en un determinado idioma
-- La función se llama así: {{#invoke:Wikidata |getLeyendaImagen | <PARÁMETRO> | lang=<ISO-639code> |id=<QID>}}
-- Devuelve PARÁMETRO, a menos que sea igual a "FETCH_WIKIDATA", del objeto QID (llamada que consume recursos)
-- Si se omite QID o está vacio, se utiliza el artículo actual (llamada que NO consume recursos)
-- Si se omite lang se utiliza por defecto el idioma local de la wiki, en caso contrario el idioma del código ISO-639
-- ISO-639 está documentado aquí: https://docs.oracle.com/cd/E13214_01/wli/docs92/xref/xqisocodes.html#wp1252447
-- El ranking es: 'preferred' > 'normal' y devuelve la etiqueta de la primera imágen con ranking 'preferred'
-- O la etiqueta de la primera imagen with ranking 'normal' si no hay ningún 'preferred'
-- Ranks: https://www.mediawiki.org/wiki/Extension:Wikibase_Client/Lua

p.getLeyendaImagen = function(frame)
	-- busca un un elemento concreto en Wikidata (QID), en caso contrario que sea nil
	local id = frame.args.id
	if id and (#id == 0) then
		id = nil
	end

	-- busca el parámetro del idioma que debería contender un código ISO-639 de dos dígitos
	-- si no se declara, toma por defecto el idioma local de la wiki (es)
	local lang = frame.args.lang
	if (not lang) or (#lang < 2) then
		lang = mw.language.getContentLanguage().code
	end

	-- el primer parámetro sin nombrar es el parámetro local, si se declara
	local input_parm = mw.text.trim(frame.args[1] or "")
	if input_parm == "FETCH_WIKIDATA" or input_parm == "" or input_parm == nil then
		local ent = mw.wikibase.getEntityObject(id)
		local imgs
		if ent and ent.claims then
			imgs = ent.claims.P18
		end
		local imglbl
		if imgs then
			-- busca una imagen con ranking 'preferred'
			for k1, v1 in pairs(imgs) do
				if v1.rank == "preferred" and v1.qualifiers and v1.qualifiers.P2096 then
					local imglbls = v1.qualifiers.P2096
					for k2, v2 in pairs(imglbls) do
						if v2.datavalue.value.language == lang then
							imglbl = v2.datavalue.value.text
							break
						end
					end
				end
			end
			-- si no hay ninguna, busca una con ranking 'normal'
			if (not imglbl) then
				for k1, v1 in pairs(imgs) do
					if v1.rank == "normal" and v1.qualifiers and v1.qualifiers.P2096 then
						local imglbls = v1.qualifiers.P2096
						for k2, v2 in pairs(imglbls) do
							if v2.datavalue.value.language == lang then
								imglbl = v2.datavalue.value.text
								break
							end
						end
					end
				end
			end
		end
		return imglbl
	else
		return input_parm
	end
end

-- devuelve el ID de la página en Wikidata (Q...), o nada si la página no está conectada a Wikidata
function p.pageId(frame)
	local entity = mw.wikibase.getEntityObject()
	if not entity then return nil else return entity.id end
end

function p.categorizar(opciones, declaracion)
	-- Evitar que pete cuando se haga el find en opciones['formatoTexto'] si vale nil
	if not opciones['formatoTexto'] then
		opciones['formatoTexto'] = ''
	end	
	
	local categoriaOpciones=opciones['categoría']	
	
	if not categoriaOpciones then
		return ''
	end

	opciones['enlace'] = 'no'

	-- Crear una tabla con los valores de la propiedad.	
	local valoresDeclaracion = {}

	if declaracion then
		valoresDeclaracion = declaracion
	elseif opciones.propiedad then
		local propiedad = {}
		if opciones.propiedad == 'precisión' or opciones.propiedad == 'latitud' or opciones.propiedad == 'longitud'  then
			propiedad = 'P625' -- Si damos el valor latitud, longitud o precisión equivaldrá a dar p625
		else
			propiedad = opciones.propiedad -- En el resto de casos se lee lo dado
		end
		
		if not p.getDeclaraciones(opciones.entityId) then
			return formatoError( 'other entity' )
		elseif p.getDeclaraciones(opciones.entityId)[mw.ustring.upper(propiedad)] then
			valoresDeclaracion = p.getDeclaraciones(opciones.entityId)[mw.ustring.upper(propiedad)]
		else
			return ''
		end		
	else
		return ''
	end

--  Creamos una tabla con cada categoría a partir de cada valor de la declaración
	local categorias	= {}
	local hayCategorias
	
	if type(categoriaOpciones) == 'string' then
		local ModuloPaginas = require('Módulo:Páginas')
	 
		for indice, valor in pairs(valoresDeclaracion) do
			valorFormateado = p.formatoDeclaracion(valor, opciones)
			if valorFormateado ~= '' then
				categoria = ModuloPaginas.existeCategoria(categoriaOpciones:gsub('$1',valorFormateado))
			
				if categoria then
					table.insert(categorias, categoria)
					hayCategorias = true
				end
			end	
		end
	elseif type(categoriaOpciones) == 'table' then
		for indice, valor in pairs(valoresDeclaracion) do
			categoria = categoriaOpciones[elementoTabla(valor, 'mainsnak', 'datavalue', 'value', 'numeric-id')]
			
			if categoria then
				table.insert(categorias, 'Categoría:' .. categoria)
				hayCategorias = true
			end
		end
	end
	
	if hayCategorias then
		return '[[' .. mw.text.listToText( categorias, ']][[',']][[') .. ']]'
	end
	
	return ''
end

 --[[ =========================================================================
		Función que comprueba si la página está enlazada a  Wikidata
		en caso de estarlo pasa el valor como a argumento a la función formatSnak()  
	 ========================================================================= `-- ]]

function p.formatoDeclaracion( declaracion, opciones)
	if not declaracion.type or declaracion.type ~= 'statement' then -- Se comprueba que tiene valor de tipo y que este sea statement (declaración) lo cual pasa siempre que existe la propiedad
		return formatoError( 'unknown-claim-type' ) -- Si no se cumple devuelve error
	end
	
	-- En el caso de que haya calificador se devuelve a la derecha del valor de la
	-- declaración entre paréntesis.
	
	local calificativo = opciones.calificativo or opciones.calificador

	if calificativo and declaracion.qualifiers then
		-- De momento los calificativos, normalmente años, no se enlazan
	   local opcionesCalificativo = {['formatoTexto']='', enlace='no', ['formatoFecha']='año'} -- Pendiente
	  
	   local wValorCalificativo
	   local wValorCalificativoFormateado
	  
	   local funcionCalificativo, mensajeError = obtenerFuncion(calificativo, opciones['módulo calificativo'])
	  
		if mensajeError then
			return mensajeError
		elseif funcionCalificativo then
	   	  -- Utilizar la función recibida sobre todos los calificativos
	   	  wValorCalificativo		   = declaracion.qualifiers
		  wValorCalificativoFormateado = funcionCalificativo(wValorCalificativo, opcionesCalificativo)
	   	elseif opciones.formatoCalificador and opciones.formatoCalificador == '()' then
			wValorCalificativo = declaracion.qualifiers[mw.ustring.upper(calificativo)]
			if wValorCalificativo and wValorCalificativo[1] then
				wValorCalificativoFormateado = p.formatoDato(wValorCalificativo[1], opcionesCalificativo)
			end
		elseif opciones.formatoCalificador and table.getn(mw.text.split(opciones.formatoCalificador, '%.')) == 2 then
			moduloFormatoCalificador = mw.text.split(opciones.formatoCalificador, '%.')
			formateado = require ('Módulo:' .. moduloFormatoCalificador[1])
			if not formateado then
				return formatoError( 'value-module-not-found' )
			end
			fun = formateado[moduloFormatoCalificador[2]]
			if not fun then
				return formatoError( 'value-function-not-found' )
			end
			
			if mw.ustring.find(opciones['formatoTexto'],'mayúscula', plain ) and
			   (primera or (opciones['separador'] and opciones['separador'] ~= 'null') or
			   	(opciones['lista'] and opciones['lista'] ~= '')) then
			  opciones['mayúscula'] = 'sí'
				  primera = false
			end
			
			if mw.ustring.find(opciones['formatoTexto'],'cursivas', plain ) then
				opcionesEntidad.cursivas = 'sí'
			end
			
			wValorCalificativoFormateado = fun( declaracion.qualifiers, opciones, marco)
			--return require('Módulo:Tablas').tostring(declaracion)
		else
	   	  -- Utilizar el primer valor del calificativo de la propiedad recibida
	   	  wValorCalificativo = declaracion.qualifiers[mw.ustring.upper(calificativo)]
	   	 
	   	  if wValorCalificativo and wValorCalificativo[1] then
			wValorCalificativoFormateado = p.formatoDato(wValorCalificativo[1], opcionesCalificativo)
		  end
		end
		if opciones.separadorcalificador then separador = opciones.separadorcalificador else separador = ' ' end
		if wValorCalificativoFormateado then
			datoFormateado = p.formatoDato(declaracion.mainsnak, opciones)
			return (datoFormateado and datoFormateado .. '&nbsp;<small>(' .. wValorCalificativoFormateado .. ')</small>') or nil
		end		
	end

	-- Si no hay calificativo.
	return p.formatoDato(seleccionDeclaracion(declaracion, opciones), opciones, declaracion.qualifiers)
end

 --[[ =========================================================================
		Función que comprueba el tipo de dato (snaktype)
		si es value pasa el valor como argumento a la función formatoValorDato()	
	 ========================================================================= `-- ]]

function p.formatoDato( dato, opciones, calificativos)
	
	if not dato or dato == '' then
		return ''
	end
	if dato.snaktype == 'somevalue' then
		-- Fecha más temprana
		if calificativos then
			if calificativos['P1319'] and calificativos['P1319'][1] and
			   calificativos['P1319'][1].datavalue and
			   calificativos['P1319'][1].datavalue.type=='time' then
			   	
				local opcionesFecha={['formatoFecha']=opciones['formatoFecha'],enlace=opciones.enlace}
		
				return 'post. ' .. require('Módulo:Wikidata/Fecha').FormateaFechaHora(calificativos['P1319'][1].datavalue.value, opcionesFecha)
			end
		end
		
		-- Si no tiene un calificativo válido
		return avisos['somevalue'] -- Valor desconocido
	elseif dato.snaktype == 'novalue' then
		return avisos['novalue'] -- Sin valor
	elseif dato.snaktype == 'value' then
		return formatoValorDato( dato.datavalue, opciones, calificativos) -- Si tiene el tipo de dato se pasa el valor a la función formatDatavalue()
	else
		return formatoError( 'unknown-snak-type' ) -- Tipo de dato desconocido
	end
end

 --[[ =========================================================================
	   Función que establece el tipo de formato en función del tipo de valor
	   (valorDato.type) y en caso de solicitarse un formato complemetario asocia
	   el módulo donde se establece el formato y la función de este que lo establece	
	 ========================================================================= `-- ]]

function formatoValorDato( valorDato, opciones, calificativos)
	local funcion, mensajeError = obtenerFuncion(opciones['valor-función'] or opciones['value-function'] or opciones['funcion'], opciones['valor-módulo'] or opciones['modulo'])
	
	if mensajeError then
		return mensajeError
	elseif funcion then
		local opcionesEntidad = {}
		
		for k, v in pairs(opciones) do
			opcionesEntidad[k] = v
		end
		
		if mw.ustring.find(opciones['formatoTexto'],'mayúscula', plain ) and
		   (primera or (opciones['separador'] and opciones['separador'] ~= 'null') or
		   	(opciones['lista'] and opciones['lista'] ~= '')) then
		  opcionesEntidad['mayúscula'] = 'sí'
			  primera = false
		end	
		
		if mw.ustring.find(opciones['formatoTexto'],'cursivas', plain ) then
			opcionesEntidad.cursivas = 'sí'
		end
		
		return funcion(valorDato.value, opcionesEntidad, marco, calificativos)		
	end

	-- == Formatos por defecto en función del tipo de valor ==

--		  * Para tipo coordenadas cuando se da como valor de propiedad: latitud, longitud o precisión

	if opciones.propiedad == 'latitud' then
		return valorDato.value['latitude']
	elseif opciones.propiedad == 'longitud' then
		return valorDato.value['longitude']
	elseif opciones.propiedad == 'precisión' then
		return valorDato.value['precision']

--		   * Con el resto de valores en propiedad

	elseif valorDato.type == 'wikibase-entityid' then	-- Tipo: Número de entidad que puede ser un ítem o propiedad
		local opcionesEntidad = {}
		if mw.ustring.find(opciones['formatoTexto'],'mayúscula', plain ) and
		   (primera or (opciones['separador'] and opciones['separador'] ~= 'null') or
		   	(opciones['lista'] and opciones['lista'] ~= '')) then
		  opcionesEntidad['mayúscula'] = 'sí'
			  primera = false
		end
		opcionesEntidad.enlace		 = opciones.enlace
		opcionesEntidad.etiqueta	   = opciones.etiqueta
		opcionesEntidad['debeExistir'] = opciones['debeExistir']
		
		if mw.ustring.find(opciones['formatoTexto'],'cursivas', plain ) then
			opcionesEntidad.cursivas = 'sí'
		end
		return p.formatoIdEntidad( SelecionEntidadPorValor( valorDato.value ), opcionesEntidad)
	elseif valorDato.type == 'string' then			   -- Tipo: Cadena de texto (string)
		return valorDato.value
	elseif valorDato.type == 'url' then	 --Tipo URL (dirección web)
		return value.url
	elseif valorDato.type == 'time' then				 -- Tipo: Fecha/hora
		local opcionesFecha={['formatoFecha']=opciones['formatoFecha'],enlace=opciones.enlace}
	  
		if mw.ustring.find(opciones['formatoTexto'] or '','mayúscula', plain ) and primera then
			opcionesFecha['mayúscula']='sí'
		end
		
		return require('Módulo:Wikidata/Fecha').FormateaFechaHora(valorDato.value, opcionesFecha, calificativos)
	elseif valorDato.type == 'monolingualtext' then	   -- Tipo: monoligüe
		if valorDato.value then
			if opciones.idioma then
				for k, v in pairs(valorDato) do
					if v.language == opciones.idioma then
						return v.text
					end
				end
			else
				return valorDato.value.text
			end
		else
			return ''
		end
	elseif valorDato.type ==  'quantity' then			-- Tipo: Cantidad
		return require('Módulo:Wikidata/Formatos').formatoUnidad(valorDato, opciones)
	elseif  valorDato.value['latitude']  and valorDato.value['longitude'] then -- Tipo: Coordenadas
		local globo = require('Módulo:Wikidata/Globos')[valorDato.value.globe]

--Concatenamos los valores de latitud y longitud dentro de la plantilla Coord

		if globo ~= 'earth' then
			return  marco:preprocess('{{coord|' .. valorDato.value['latitude'] .. '|' ..
				   valorDato.value['longitude'] .. '|globe:' .. globo .. '_type:' .. opciones.tipo .. '|display=' ..
				   opciones.display ..'|formato=' .. opciones.formato..'}}')
		else
			return  marco:preprocess('{{coord|' .. valorDato.value['latitude'] .. '|' ..
				   valorDato.value['longitude'] .. '|type:' .. opciones.tipo .. '|display=' ..
				   opciones.display ..'|formato=' .. opciones.formato..'}}')
		end

	else
		return formatoError( 'unknown-datavalue-type' ) -- Si no es de ninguno de estos tipos devolverá error valor desconocido
	end
end

  --[[ =========================================================================
		  Damos formato a los enlaces internos	
	   ========================================================================= `-- ]]

-- Opciones:
--	 - enlace:		Valores posibles 'sí' o 'no'
--	 - mayúscula:		Valores posibles 'sí' o 'no'
--	 - cursivas:		Valores posibles 'sí' o 'no'

function p.formatoIdEntidad(idEntidad, opciones)
	local enlace   = mw.wikibase.sitelink(idEntidad)
	local etiqueta = mw.wikibase.label(idEntidad)
	return require('Módulo:Wikidata/Formatos').enlazar(enlace, etiqueta, idEntidad, opciones)
end

 --[[ =========================================================================
		Función principal	
	 ========================================================================= `-- ]]

function p.Wikidata( frame )
	marco = frame
	local args = frame.args
	
	if args.valor == 'no' then
		return
	end

	local parentArgs = frame:getParent().args
	
	-- Copiar los argumentos
	local argumentos = {}
	
	for k, v in pairs(args) do
		argumentos[k] = v
	end
	
	for k, v in pairs(parentArgs) do
		if not argumentos[k] then
			argumentos[k] = v
		end
	end
	
	--if true then return require('Módulo:Tablas').tostring(argumentos) end
	
	-- No generar el valor de Wikidata si se ha facilitado un valor local y
	-- el valor local es prioritario.
	local valorWikidata;
	if (args.prioridad ~= 'sí' or (args.importar and args.importar == 'no')) and args.valor and args.valor ~= '' then
		valorWikidata = '';
	else
		valorWikidata = p.getPropiedad(argumentos, nil);
	end
	
 	local categorias = '';
 	local namespace = frame:preprocess('{{NAMESPACENUMBER}}');
 	
 	if (namespace == '0' and (not args.categorias or args.categorias ~= 'no') and
 			args.propiedad and string.upper(args.propiedad) ~= 'P18' -- P18: imagen de Commons
 			and string.upper(args.propiedad) ~= 'P41' -- P41: imagen de la bandera
 			and string.upper(args.propiedad) ~= 'P94' -- P94: imagen del escudo de armas
 			and string.upper(args.propiedad) ~= 'P109' -- P109: firma de persona
 			and string.upper(args.propiedad) ~= 'P154') then -- P154: logotipo
	 	if valorWikidata ~= '' and args.valor and args.valor ~= '' then
	 		categorias = '[[Categoría:Wikipedia:Artículos con datos locales]]'
	 	elseif valorWikidata and valorWikidata == '' and args.valor and args.valor ~= '' and
	 		(not args.calificador or args.calificador == '') and
	 		(not args.dato or args.dato == '' or args.dato ~= 'fuente')then
	 		categorias = '[[Categoría:Wikipedia:Artículos con datos por trasladar a Wikidata]]'
	 	end
	end

	if args.prioridad == 'sí' and valorWikidata  ~= '' then -- Si se da el valor sí a prioridad tendrá preferencia el valor de Wikidata
		if args.importar and args.importar == 'no' and args.valor and args.valor ~= '' then
			return args.valor .. categorias
		elseif valorWikidata then
			return valorWikidata .. categorias -- valor que sustituye al valor de Wikidata parámetro 2
		else
			return categorias
		end
	elseif args.valor and args.valor ~= '' then
		 return args.valor .. categorias
	elseif args.importar and args.importar == 'no' then
		 return ''
	elseif valorWikidata then -- Si el valor es nil salta una excepcion al concatenar
		return valorWikidata .. categorias
	else
		return ''
  end 
end

function obtenerFuncion(funcion, nombreModulo)
	if not funcion then
		return
	elseif type(funcion) == 'function' then -- Uso desde LUA
		return funcion
	elseif funcion == '' or not nombreModulo or nombreModulo == '' then
		return
	else -- Uso desde una plantilla
		local modulo
		
		if not nombreModulo or nombreModulo == '' or nombreModulo == 'Wikidata/Formatos' then
			modulo = require(modulosTipos[funcion] or 'Módulo:Wikidata/Formatos')
		else
			modulo = require ('Módulo:' .. nombreModulo)
		end
		
	   	if not modulo then
		   	return nil, formatoError( 'value-module-not-found' )
		elseif not modulo[funcion] then
		   	return nil, formatoError( 'value-function-not-found' )
		else
		   	return modulo[funcion]
	   	end
	end
end

function p.addLinkback(valorPropiedad, idEntidad, idPropiedad)
	local lidEntidad
	
	if valorPropiedad and idPropiedad then
		lidEntidad= (idEntidad ~='' and idEntidad) or mw.wikibase.getEntityIdForCurrentPage()
	end

	if lidEntidad then
		return valorPropiedad .. '<span class=\"wikidata-link noprint\"> [[Archivo:Blue_pencil.svg|Ver y modificar los datos en Wikidata|10px|baseline|alt=Ver y modificar los datos en Wikidata|enlace=https://www.wikidata.org/wiki/' .. lidEntidad .. '?uselang=es#' .. idPropiedad ..
		 ']]</span>'
	else
		return valorPropiedad
	end
end
--------------------------------------------------------------------
-- A continuación, función p.claim y funciones locales necesarias --
-- Adaptado de https://ca.wikisource.org/wiki/Module:Wikidata     --
--------------------------------------------------------------------
local wiki = {
	langcode = mw.language.getContentLanguage().code
}
local _ -- variable for unused returned values, avoiding globals

-- Table of language codes: requested or default and its fallbacks
local function findLang(langcode)
	if mw.language.isKnownLanguageTag(langcode or '') == false then
		local cframe = mw.getCurrentFrame()
		local pframe = cframe:getParent()
		langcode = pframe and pframe.args.lang
		if mw.language.isKnownLanguageTag(langcode or '') == false then
			if not mw.title.getCurrentTitle().isContentPage then
				langcode = cframe:preprocess('{{int:lang}}')
			end
			if mw.language.isKnownLanguageTag(langcode or '') == false then
				langcode = wiki.langcode
			end
		end
	end
	
	local languages = mw.language.getFallbacksFor(langcode)
	table.insert(languages, 1, langcode)
	if langcode == wiki.langcode then
		for _, l in ipairs({}) do
			table.insert(languages, l)
		end
	end
	
	return languages
end

-- Argument is 'set' when it exists (not nil) or when it is not an empty string.
local function isSet(var)
	return not (var == nil or (type(var) == 'string' and mw.text.trim(var) == ''))
end

-- get safely a serialized snak
local function getSnak(statement, snaks)
	local ret = statement
	for i, v in ipairs(snaks) do
		if not ret then return end
		ret = ret[v]
	end
	return ret
end

-- mw.wikibase.getLabelWithLang or getLabelByLang with a table of languages
local function getLabelByLangs(id, languages)
	local label
	local lang
	for _, l in ipairs(languages) do
		if l == wiki.langcode then
			-- using getLabelWithLang when possible instead of getLabelByLang
			label, l = mw.wikibase.getLabelWithLang(id)
		else
			label = mw.wikibase.getLabelByLang(id, l)
		end
		if label then
			lang = l
			break
		end
	end
	return label, lang
end

-- format data value wikibase-entityid: types wikibase-item, wikibase-property
local function printDatatypeEntity(data, parameters)
	local entity_id = data['id']
	if parameters.formatting == 'raw' then
		return entity_id, entity_id
	end
	local label, lang = getLabelByLangs(entity_id, parameters.lang)
	local sitelink = mw.wikibase.getSitelink(entity_id)
	local labelcase = label or sitelink
	local entity_page = 'Special:EntityPage/' .. entity_id
	
	local ret1
	if parameters.formatting == 'label' then
		ret1 = labelcase or entity_id
	else
		if sitelink then
			ret1 = '[[' .. sitelink .. '|' .. labelcase .. ']]'
		elseif label and string.match(parameter or '', 'internallink$') and not mw.wikibase.getEntityIdForTitle(label) then
			ret1 = '[[' .. label .. '|' .. labelcase .. ']]'
		else	--si no existe la pág. en WS, crea enlace a WD
			ret1 = '[[d:' .. entity_page .. '|<span style="color:#5f9cbb;">' .. (labelcase or entity_id) .. '</span>]]'
		end
	end
	
	return ret1
end

local function getSnakValue(snak, parameters)
	if snak.snaktype == 'value' then
		-- see Special:ListDatatypes
		if snak.datatype == 'wikibase-item' or snak.datatype == 'wikibase-property' then
			return printDatatypeEntity(snak.datavalue.value, parameters)
		end
	end
	return mw.wikibase.renderSnak(snak)
end

local function getQualifierSnak(claim, qualifierId, parameters)
	-- a "snak" is Wikidata terminology for a typed key/value pair
	-- a claim consists of a main snak holding the main information of this claim,
	-- as well as a list of attribute snaks and a list of references snaks
	if qualifierId then
		-- search the attribute snak with the given qualifier as key
		if claim.qualifiers then
			local qualifier = claim.qualifiers[qualifierId]
			if qualifier then
				if qualifier[1].datatype == "monolingualtext" then
					-- iterate over monolingualtext qualifiers to get local language
					for idx in pairs(qualifier) do
						if getSnak(qualifier[idx], {"datavalue", "value", "language"}) == parameters.lang[1] then
							return qualifier[idx]
						end
					end
				elseif parameters.list then
					return qualifier
				else
					return qualifier[1]
				end
			end
		end
		return nil, formatoError("qualifier-not-found")
	else
		return claim.mainsnak
	end
end

local function getValueOfClaim(claim, qualifierId, parameters)
	local snak, error = getQualifierSnak(claim, qualifierId, parameters)
	if not snak then
		return nil, nil, error
	elseif snak[1] then -- a multi qualifier
		local result = {}
		for idx in pairs(snak) do
			result[#result + 1] = getSnakValue(snak[idx], parameters)
		end
		return mw.text.listToText(result), nil
	else -- a property or a qualifier (lo habitual)
		return getSnakValue(snak, parameters)
	end
end

local function getEntityId(args, pargs, unnamed)
	pargs = pargs or {}
	local id = args.item or args.from or (unnamed and mw.text.trim(args[1] or '') or nil)
	if not isSet(id) then
		id = pargs.item or pargs.from or (unnamed and mw.text.trim(pargs[1] or '') or nil)
	end
	if not isSet(id) then
		id = mw.wikibase.getEntityIdForCurrentPage()
	end
	return id
end

local function getArg(value, default, aliases)
	if type(value) == 'boolean' then return value
	elseif value == "false" or value == "no" then return false
	elseif value == "true" or value == "yes" then return true
	elseif value and aliases and aliases[value] then return aliases[value]
	elseif isSet(value) then return value
	elseif default then return default
	else return nil
	end
end

-- Main function claim ---------------------------------------------
-- on debug console use: =p.claim{item="Q...", property="P...", ...}
function p.claim(frame)
	local args = frame.args or frame -- via invoke or require
	local pargs = frame.args and frame:getParent().args or {}

	-- arguments
	local parameters = {}
	parameters.id = getEntityId(args, pargs)
	if parameters.id == nil then return end
	parameters.property = string.upper(args.property or "")
	local qualifierId = {}
	qualifierId[1] = getArg(string.upper(args.qualifier or ""))
	local i = 2
	while isSet(args["qualifier" .. i]) do
		qualifierId[i] = string.upper(args["qualifier" .. i])
		i = i + 1
	end
	parameters.formatting = getArg(args.formatting)
	parameters.list = getArg(args.list, true, {firstrank='bestrank'})
	local default = args.default
	parameters.lang = findLang(args.lang)

	-- fetch property
	local claims = {}
	claims = mw.wikibase.getBestStatements(parameters.id, parameters.property)
	if #claims == 0 then
		return default
	end
	
	-- defaults for table
	local preformat, postformat = "", ""
	-- get initial sort indices
	local sortindices = {}
	for idx in pairs(claims) do
		sortindices[#sortindices + 1] = idx
	end

	local result
	if parameters.list then
		parameters.separator = mw.message.new('Comma-separator'):inLanguage(parameters.lang[1]):plain()
		parameters.conjunction = (mw.message.new('And'):inLanguage(parameters.lang[1]):plain() .. mw.message.new('Word-separator'):inLanguage(parameters.lang[1]):plain())
		-- iterate over all elements and return their value (if existing)
		local value
		result = {}
		local values = {}
		for idx in pairs(claims) do
			local claim = claims[sortindices[idx]]
			value = getValueOfClaim(claim, qualifierId[1], parameters)
			values[#values + 1] = {}
			if value then
				values[#values]["col0"] = value
				result[#values] = value
			end
		end
		result = preformat .. mw.text.listToText(result, parameters.separator, parameters.conjunction) .. postformat
	else
		-- return first element
		local claim = claims[sortindices[1]]
		result = getValueOfClaim(claim, qualifierId[1], parameters)
	end
	
	if not isSet(result) then
		result = default
	end
	return result or ''
end
--------------------------------------------------------------------------------
-- Get an Item based on what's passed in the 'wikidata' or 'page' parameters of
-- the args, or the current page's ID otherwise.
local function getItem( args )
	local id = nil
	-- If args is a table with an appropriate element, use it.
	if type( args ) == 'table' then
		if args.wikidata ~= '' and args.wikidata ~= nil then
			id = args.wikidata
		elseif args.wikidata_id ~= '' and args.wikidata_id ~= nil then
			id = args.wikidata_id
		elseif args.page ~= '' and args.page ~= nil then
			local title = mw.title.new( args.page )
			id = mw.wikibase.getEntityIdForTitle( title.nsText .. title.text )
			-- If no entity for this page, maybe it's a subpage and we should look for the root page's entity.
			if id == nil then
				id = mw.wikibase.getEntityIdForTitle( title.nsText .. title.rootText )
			end
		end
	end
	if type( args ) == 'string' and args ~= '' then
		id = args
	end
	return mw.wikibase.getEntity( id )
end
--------------------------------------------------------------------------------
-- Exported method. Get wikitext for displaying an edition's badges from Wikidata.
-- Test: =p.badge({args={qid='Q30097675'}})
function p.badge( frame )
	local args = frame.args or frame -- via invoke or require
	local item = getItem( args )	--por defecto, id de la página
	
	local badges = {}
	
	if args.qid ~= nil then			--pero si pasamos un qid, id pasado
		item = mw.wikibase.getEntity(args.qid)
	end
	
	local status = args.ws
	-- status en el índice a badge
	if status == 'C' then
		status = "Q20748091"
	elseif status == 'P' then
		status = "Q20748091"
	elseif status == 'V' then
		status = "Q20748092"
	elseif status == 'T' then
		status = "Q20748093"
	elseif status == 'E' then
		status = "Q20748094"
	end

	if not ( item and item.sitelinks and item.sitelinks.eswikisource and #item.sitelinks.eswikisource.badges > 0)  and not (status) then
		return ''
	end
	
	-- alguno con más prioridad que el otro? TODO: hacer algo en caso de discrepancia
	local badges = {}
	if status then
		badges = {status}
	end
	if  ( item and item.sitelinks and item.sitelinks.eswikisource and #item.sitelinks.eswikisource.badges > 0) then
		badges = {unpack(badges), unpack(item.sitelinks.eswikisource.badges)}
	end
	
	local out = ''
	for _, badge in pairs( badges ) do
		local badgeOut = ''
		local badgeItem = mw.wikibase.getEntity( badge )
		local wikisourceBadgeClass = 'Q75042035'
		local badgeName = ''
		if badgeItem.claims.P31[1].mainsnak.datavalue.value.id == wikisourceBadgeClass and badgeItem.claims.P18 ~= nil then
			local imageName = badgeItem.claims.P18[1].mainsnak.datavalue.value
			if mw.wikibase.getLabel( badge ) ~= nil then
				badgeName = mw.wikibase.getLabel( badge )
			end
			-- TODO: Crear una página de ayuda apropiada para el nivel de los *textos*
			badgeOut = '<span class="indicator-badge">[[File:' .. imageName .. '|16px|link=Ayuda:Nivel de las páginas|' .. badgeName .. ']]</span>'
			if args.indicator ~= nil then
				badgeOut = '<indicator name="wikisource-badge-' .. badgeName .. '">' .. badgeOut .. '</indicator>'
			end
			--[=[if args.category ~= nil and badgeItem.claims.P910 ~= nil then
				local categoryQid = badgeItem.claims.P910[1].mainsnak.datavalue.value.id
				local category = mw.wikibase.getEntity( categoryQid )
				badgeOut = badgeOut .. '[[' .. category.sitelinks.enwikisource.title .. ']]' 
			end ]=]--
			
			out = out .. badgeOut
		end
	end
	return mw.getCurrentFrame():preprocess(out)
end

return p