Módulo:Info/wd
40x40px | Este módulo é usado em mais de 30 000 páginas. (Ver Wikihelp:Predefinições em alto risco) Para evitar sobrecargas desnecessárias ao servidor e outros transtornos, quaisquer mudanças devem ser previamente testadas, seja na predefinição de testes ou em Módulo:Info/wd/Testes (ou ainda em sua página de testes). Por favor, sempre considere expor eventuais mudanças na página de discussão, antes de implementá-las. |
40x40px | This module is subject to page protection. It is a highly visible module in use by a very large number of pages, or is substituted very frequently. Because vandalism or mistakes would affect many pages, and even trivial editing might cause substantial load on the servers, it is protected from editing. |
Índice
Descrição
Este módulo gera os campos do Módulo:Info que pedem dados do Wikidata. Algumas fuções podem ser usadas de forma idependente para exibir os dados fora da infobox.
Uso
Dentro dos campos da infobox é preciso colocar o prefixo #wd:
ou #WD:
seguido da propriedade que deve ser preenchida.
Por exemplo #wd:P17
vai buscar a propriedade P17 (país) no item da página no Wikidata. Cada campo pode ter mais de uma propriedade, por exemplo #wd:P569 P19
vai gerar a P569 (data de nascimento) seguido da P19 (local de nascimento).
Este módulo pode também ser usado fora da infobox com a função dados para obter uma propriedade, por exemplo {{#invoke:Info/wd|dados|P17}}
, ou a função expandir para obter uma ou mais propriedades.
Grupos condicionais
Quando o campo tem mais de uma propriedade pode ser usados grupos condicionais delimitados por { }
(chaves simples), o que estiver dentro das chaves só será exibido se uma propriedade dentro desse grupo foi obtida da Wikidata. Por exemplo se em uma página P569 é "1 de janeiro de 1959" e não existir a P19, então #wd:P569 em P19
vai retornar "1 de janeiro de 1959 em" e #wd:P569{ em P19}
vai retornar "1 de janeiro de 1959", pois o "em" está dentro do grupo em que nenhuma propriedade foi obtida.
Funções especiais
Para diferentes tipos de dados existem diferentes funções especiais que podem ser usadas para modificar o valor obtido do Wikidata.
Itens da Wikidata
Quando a propriedade é um item do Wikidata é possível usar a função :link para gerar um link se aquele item for ligado a uma página da wIRChelp. Se P17 for Alemanha, P17
retorna Alemanha e P17:link
retorna Alemanha.
Números com unidades
Os números com unidades usam os dados do Módulo:Unidades para colocar links e fazer conversões.
Sintaxe | descrição | Exemplo com P2048 = 324 m | |
---|---|---|---|
:link | coloca link na unidade | P2048:link |
325 m |
:unidade:<nome ou simbolo da unidade> | força uma unidade específica | P2048:ft |
1063 ft |
:unidade:<nome ou simbolo da unidade>:link | força uma unidade e coloca link | P2048:ft:link |
1063 ft |
:converter:<nome ou simbolo da unidade> | adiciona a conversão para outra unidade | P2048:converter:ft |
324 m (1063 ft) |
:link:converter:<nome ou simbolo da unidade>:link | o mesmo com link nas unidades | P2048:link:converter:ft:link |
324 m (1063 ft) |
:alg:<algarismos significativos> | altera o número de algarismos significativos (o padrão é 4) | P2048:alg:2 |
320 m |
:link:converter:<nome ou simbolo da unidade>:alg:<algarismos significativos>:link | todas as funções acima | P2048:link:converter:ft:alg:6:link |
324 m (1062.99 ft) |
:mais:<número ou propriedade> | soma | P2048:mais:10 |
334 |
:menos:<número ou propriedade> | subtrai | P2048:menos:20 |
304 |
:vezes:<número ou propriedade> | multiplica | P2048:vezes:1000 |
334000 |
:dividido:<número ou propriedade> | divide | P2048:dividido:P123 (sendo P123 = 20) |
16,2 |
Coordenadas
As coordenadas tem também a função :link que faz com que as coordenadas tenham um link para o geohack como é usual em coordenadas geográficas na wIRChelp. Após o :link podem haver pares de argumentos que serão passados para o link como parâmetros do geohack. Por exemplo, se as coordenadas forem 12° 34' 56" S 12° 34' 56" O, P625:link:scale:300000
retorna 12° 34' 56" S 12° 34' 56" O.
Qualificadores
Além do formato #wd:P1 também são aceitos outros formatos que pegam outros dados das propriedades do item no Wikidata:
- #wd:P1:P2 → pega o qualificador P2 da propriedade P1.
- #wd:P1:P2:Q2 → pega o valor da propriedade P1 onde o valor do qualificador P2 é igual a Q2.
- #wd:P1:Q1:P2 → pega o valor do qualificador P2 da propriedade P1 onde o valor de P1 é Q1.
Exemplo:
Exemplo (P123) | Valor A (Q456) | |
Qualificador (P789) | Valor X (Q2468) | |
Valor B (Q654) | ||
Qualificador (P789) | Valor Y (Q8642) | |
- #wd:P123 → Valor A
- #wd:P123:P789 → Valor X
- #wd:P123:P789:Q8642 → Valor B
- #wd:P123:Q654:P789 → Valor Y
Exemplo em d:Q243 (Torre Eiffel):
- #wd:P2048 → 324 m (altura)
- #wd:P2048:P1013 → altura máxima (critério usado (P1013) para a altura (P2048))
- #wd:P2048:P1013:Q31271474 → 300 m (altura (P2048) onde o critério usado (P1013) é a altura arquitetônica (Q31271474))
- #wd:P127:Q90:P580 → 1889 (data de início (P580) em que Paris (P90) é o proprietário (P127))
Testes
Este módulo também pode ser invocado diretamente para testes, com a função dados para retornar somente um propriedade, por exemplo {{#invoke:Info/wd|dados|P6:link}}
, ou com a função expandir para retornar mais de uma unidade da forma como seria processado no campo da infobox, por exemplo {{#invoke:Info/wd|expandir|P569{ em P19} }}
. Adicione |debug
após a propriedade para obter mensagens de debug.
Este módulo não deve ser invocado dessa forma ao preencher a infobox, pois isso impediria que a infobox identifique que o dado veio do Wikidata e contabilize como dado do Wikidata para categorizações de contagem de campos.
Ver também
wd = {} -- Carrega as propriedades da página no Wikidata, se existir e não tiverem já sido carregadas if not wdEntity then wdEntity = mw.wikibase.getEntity() end wd.props = wdEntity and wdEntity['claims'] -- Tabela para dados temporários, mantidos durante o processamento de uma propriedade wd.temp = {} -- Processa a propriedade ou qulificador pedido wd.dados = function (prop) local p = {} local lingua = params and params['língua'] for i in string.gmatch(prop, '[^:]+') do table.insert(p, i) end if not p[1] or not string.match(p[1], '^P%d+$') then wd.temp.debug = 'não é uma propriedade' return nil end if ext and ext.prop and ext.prop[p[1]] then wd.temp.debug = 'processada pela extensão' return ext.prop[p[1]](prop) end prop = wd.props and wd.props[p[1]] if not prop then wd.temp.debug = 'item não tem essa propriedade' return nil end local snak local arg = 2 if p[2] then if string.match(p[2], '^P%d$') then local qprop = table.remove(p, 2) -- qualificador da propriedade (Pq) for _, propn in ipairs(prop) do if propn['qualifiers'] and propn['quailifiers'][qprop] then if p[2] and string.match(p[2], '^Q%d$') then -- P:Pq:Qq local qvalue = table.remove(p, 2) -- valor do qualificador (Qq) for i, v in ipairs(propn['qualifiers'][qprop]) do if v['datatype'] == 'wikibase-item' and v['datavalue']['value']['id'] == qvalue then snak = propn['mainsnak'] arg = 4 break end end else -- P:Pq snak = propn['quaifiers'][qprop][1] arg = 3 break end end end elseif string.match(p[2], '^Q%d$') then local pvalue = table.remove(p, 2) -- valor da propriedade (Qv) if p[2] and string.match(p[2], '^P%d$') then -- P:Qv:Pq local qprop = table.remove(p, 2) -- qualificador (Pq) for _, propn in ipairs(prop) do if propn['mainsnak']['datatype'] == 'wikibase-item' and propn['mainsnak']['datavalue']['value']['id'] == pvalue then if propn['qualifiers'] and propn['qualifiers'][qprop] then snak = propn['quaifiers'][qprop][1] arg = 4 else wd.temp.debug = 'esse valor não possui o qualificador ' .. qprop return nil end end end else wd.temp.debug = 'faltou o qualificador (último P do formato P:Qv:Pq)' return nil end end end if arg == 2 and p[2] == 'lista' then -- Listar todos valores de uma propriedade local lista = {} for _, propn in ipairs(prop) do local datatype = propn['mainsnak']['datatype'] wd.temp.tipo = datatype if datatype == 'string' or datatype == 'external-id' then table.insert(lista, propn['mainsnak']['datavalue']['value']) elseif datatype == 'wikibase-item' then if not propn['mainsnak']['datavalue'] then wd.temp.debug = 'propriedade não possui valor' return nil end local qid = propn['mainsnak']['datavalue']['value']['id'] local labels = mw.wikibase.getEntity(qid)['labels'] if lingua and labels[lingua] then table.insert(lista, labels[lingua]) else local pt, en, outra for lang, v in pairs(labels) do if lang == 'pt' then pt = v['value'] break elseif lang == 'pt-br' then pt = v['value'] elseif lang == 'en' then en = v['value'] elseif lang == 'es' or lang == 'fr' or lang == 'it' then -- outras linguas latinas outra = v['value'] end end if pt or en or outra then table.insert(lista, pt or en or outra) end end else wd.temp.debug = 'esse tipo de dados em pt, pt-br, en, es, fr, ou it' return nil end end if #lista > 1 then wd.temp.debug = 'lista com ' .. #lista .. ' valores' return table.concat(lista, ', ', 1, #lista - 1) .. ' e ' .. lista[#lista] elseif #lista == 1 then wd.temp.debug = 'lista só possui um valor' return lista[1] else wd.temp.debug = 'não possui nenhum valor que pode ser retornado' return nil end end -- Escolher só um valor para retornar if not snak then if prop[1]['mainsnak']['datatype'] == 'monolingualtext' then wd.temp.tipo = 'monolingualtext' -- A FAZER: escolher língua local i = 1 for n, v in pairs(prop) do if v['mainsnak']['datavalue']['value']['language'] == 'pt' then i = n break elseif v['mainsnak']['datavalue']['value']['language'] == 'pt-br' then i = n end end wd.temp.debug = 'valor obtido' return prop[i]['mainsnak']['datavalue']['value']['text'] else for _, propn in ipairs(prop) do if propn['rank'] == 'preferred' then snak = propn['mainsnak'] break elseif not snak and propn['rank'] == 'normal' then snak = propn['mainsnak'] end end end end local args = {} for n, a in ipairs(p) do if n >= arg then table.insert(args, p[n]) end end if snak then return wd.valorsnak(snak, args) end end -- Retorna o valor de um snak de acordo com o tipo de dado wd.valorsnak = function(snak, args) local datatype = snak['datatype'] wd.temp.tipo = datatype if datatype == 'string' or datatype == 'url' or datatype == 'external-id' or datatype == 'math' or datatype == 'commonsMedia' then wd.temp.debug = #args == 0 and 'valor obtido' or 'esse tipo de dado não recebe modificações' return snak['datavalue']['value'] elseif datatype == 'monolingualtext' then wd.temp.debug = 'obtido valor na língua ' .. snak['datavalue']['value']['language'] return snak['datavalue']['value']['text'] elseif datatype == 'wikibase-item' then if not snak['datavalue'] then wd.temp.debug = 'propriedade não possui valor' return nil end local qid = snak['datavalue']['value']['id'] local item = mw.wikibase.getEntity(qid) local labels = item['labels'] local pt, en, outra for lang, v in pairs(labels) do if lang == 'pt' then pt = v['value'] break elseif lang == 'pt-br' then pt = v['value'] elseif lang == 'en' then en = v['value'] elseif lang == 'es' or lang == 'fr' or lang == 'it' then -- outras linguas latinas outra = v['value'] end end local valor = pt or en or outra if not valor then wd.temp.debug = 'item não tem rótulo em pt, pt-br, en, es, fr ou it' return qid end if args[1] == 'link' and item['sitelinks'] and item['sitelinks']['ptwiki'] then wd.temp.debug = 'valor obtido e adicionado link' return '[[' .. item['sitelinks']['ptwiki']['title'] .. '|' .. valor .. ']]' end wd.temp.debug = args[1] == 'link' and 'valor obtido sem link pois não possui artigo' or 'valor obtido' return valor elseif datatype == 'time' then local ac, ano, mes, dia, hora, minuto, segundo = string.match( snak['datavalue']['value']['time'], '([+-])(%d+)%-(%d%d)%-(%d%d)T(%d%d):(%d%d):(%d%d)Z') if hora == '00' and minuto == '00' and segundo == '00' then if mes == '00' then wd.temp.debug = 'data só possui o ano' return ano .. (ac == '-' and ' AC' or '') end local meses = {['01']='janeiro', ['02']='fevereiro', ['03']='março', ['04']='abril', ['05']='maio', ['06']='junho', ['07']='julho', ['08']='agosto', ['09']='setembro', ['10']='outubro', ['11']='novembro', ['12']='dezembro' } wd.temp.debug = 'data obtida, não possui hora' return dia .. ' de ' .. meses[mes] .. ' de ' .. ano .. (ac == '-' and ' AC' or '') else wd.temp.debug = 'obtida data e hora' return string.format('%d/%d/%d %d:%d:%d', dia, mes, ano, hora, minuto, segundo) end elseif datatype == 'quantity' then local amount = tonumber(snak['datavalue']['value']['amount']) local unit = string.match(snak['datavalue']['value']['unit'], '//www.wikidata.org/entity/(Q%d+)') return wd.quantidade(amount, unit, args) elseif datatype == 'globe-coordinate' then local lat = tonumber(snak['datavalue']['value']['latitude']) local long = tonumber(snak['datavalue']['value']['longitude']) return wd.coordenadas(lat, long, args) else wd.temp.debug = 'esse tipo de dado não é suportado' return nil end end -- Retorna número com determinados algarimos significativos local algSig = function(n, alg) local a = alg - math.ceil(math.log10(math.abs(n))) return math.floor(n * 10 ^ a + 0.5) / 10 ^ a end -- Formata um número usando espaço como separador de milhar e vírgula como separador decimal local formatnum = function(n) n = tostring(n) local m = 1 while m > 0 do n, m = string.gsub(n, '^(%-?%d+)(%d%d%d)', '%1 %2') end return string.gsub(n, '(%d)%.(%d)', '%1,%2') end -- Retorna valor de uma quantidade de acordo com argumentos wd.quantidade = function(n, qid, args) if args[1] == 'dividido' or args[1] == 'vezes' or args[1] == 'mais' or args[1] == 'menos' then wd.temp.debug = 'valor com operação matemática' resp = wd.matematica(n, args) return resp and formatnum(resp) elseif qid then return wd.unidade(n, qid, args) else wd.temp.debug = 'obtido valor sem unidade' return n and formatnum(n) end end -- Retorna unidade relacionada a um item do Wikidata baseado nos dados do Módulo:Unidades wd.unidade = function(n, qid, args, loop) if not unidades then unidades = mw.loadData('Módulo:Unidades') end local u = type(unidades[qid]) == 'string' and unidades[unidades[qid]] or unidades[qid] if not u then wd.temp.debug = 'a unidade ' .. qid .. 'não é conhecida, se ela existir adicione no [[Módilo:Unidades]]' return n .. ' (unidade ' .. qid .. ')' end local nome = u['nome'] local arg = table.remove(args, 1) -- Mudar a unidade se for pedido -- if arg == 'unidade' and args[1] then nome = table.remove(args, 1) arg = table.remove(args, 1) local u2 = type(unidades[nome]) == 'string' and unidades[unidades[nome]] or unidades[nome] if u2 and u['grandeza'] ~= u2['grandeza'] then wd.temp.debug = 'tentando converter grandezas diferentes: ' .. u['nome'] .. ' (' .. u['grandeza'] .. ') para ' .. u2['nome'] .. ' (' .. u2['grandeza'] .. ')' return nil end if u2 and u ~= u2 then n = n * u['si'] / u2['si'] -- convertendo u = u2 end end local unidade if u['unidade'] then unidade = u['unidade'] elseif n ~= 1 and u['plural'] then unidade = u['plural'] elseif n == 1 and u['nome'] then unidade = u['nome'] else wd.temp.debug = 'unidade ' .. nome .. ' não possui nome da unidade' .. (n ~= 1 and ' nem plural' or '') .. ' para se colocado após o número, corrija no [[Módulo:Unidades]]' return ' (unidade ' .. qid .. ')' end local alg = 4 if arg == 'alg' and tonumber(args[1]) then alg = math.max(1, math.min(12, math.floor(table.remove(args, 1)))) arg = table.remove(args, 1) end wd.temp.debug = alg .. ' algarísmos significativos' local resp = formatnum(algSig(n, alg)) .. ' ' if arg == 'link' and u['artigo'] then arg = table.remove(args, 1) resp = resp .. '[[' .. u['artigo'] .. '|' .. unidade .. ']]' wd.temp.debug = wd.temp.debug .. ', adicionado link' else resp = resp .. unidade end -- Exibir a conversão quando for pedido -- if arg == 'converter' and args[1] and unidades[args[1]] and not loop then table.insert(args, 1, 'unidade') resp = resp .. ' (' .. wd.unidade(n, nome or qid, args, true) .. ')' wd.temp.debug = wd.temp.debug .. ', adicionado conversão' end return resp end -- Realiza operações matemáticas com quantidades wd.matematica = function(n, args) local op = table.remove(args, 1) local prop = table.remove(args, 1) local n2 if string.match(prop, '^%-?%d+$') then n2 = tonumber(prop) wd.temp.debug = 'valor ' .. n .. ' ' .. op .. (op == 'dividido' and ' por' or '') .. ' ' .. n2 elseif string.match(prop, '^P%d+$') then local p2 = wd.props and wd.props[prop] and wd.props[prop][1] if not (p2 and p2['mainsnak']['datatype'] == 'quantity') then wd.temp.debug = p2 and prop .. ' não é do tipo quantity' or prop .. ' não existe no item' return end n2 = p2['mainsnak']['datavalue']['value']['amount'] wd.temp.debug = 'operação com ' .. prop .. ' = ' .. n2 else wd.temp.debug = 'operação matemática sem informar propriedade ou número' return nil end if op == 'dividido' then local r = n / n2 if r ~= math.floor(r) then return tostring(algSig(r, 4)) else return tostring(r) end elseif op == 'vezes' then return tostring(n * n2) elseif op == 'mais' then return tostring(n + n2) elseif op == 'menos' then return tostring(n - n2) end end -- Retorna as coordenadas no formato G° M' S" [NS] G° M' S" [LO] e coloca link quando pedido wd.coordenadas = function(lat, long, args) local abs = math.abs(lat) local grau = math.floor(abs) local min = math.floor((abs - grau) * 60) local seg = math.floor(((abs - grau) * 60 - min) * 60) local hemi = lat >= 0 and 'N' or 'S' lat = string.format('%02d° %02d\' %02d" %s', grau, min, seg, hemi) abs = math.abs(long) grau = math.floor(abs) min = math.floor((abs - grau) * 60) seg = math.floor(((abs - grau) * 60 - min) * 60) hemi = long >= 0 and 'L' or 'O' long = string.format('%02d° %02d\' %02d" %s', grau, min, seg, hemi) local coor = string.gsub(lat, ' ', ' ') .. ' ' .. string.gsub(long, ' ', ' ') if args[1] == 'link' then local link = '<span class="plainlinks" style="white-space:nowrap" title="Mapas, fotos aéreas e outros dados para este local">[//tools.wmflabs.org/geohack/geohack.php?language=pt&pagename=' local pagename = mw.uri.encode(mw.title.getCurrentTitle().fullText) local coorlink = string.gsub(string.gsub(string.gsub(coor, '[^0-9NSLO]+', '_'), 'O', 'W'), 'L', 'E') local i = 2 while #args > i do if args[i] == '' or args[i + 1] == '' then break end coorlink = coorlink .. '_' .. args[i] .. ':' .. string.gsub(args[i + 1], ' ', '_') i = i + 2 end wd.temp.debug = 'obtida coordenada e adicionado link' return link .. pagename .. '¶ms=' .. coorlink .. ' ' .. coor .. ']</span>' end wd.temp.debug = 'obtida coordenada' return coor end parser = function(s) local i = 1 local grupos = {} local props = {} while i < #s do local abre = string.find(s, '{', i, true) local fecha = string.find(s, '}', i, true) if abre and not (fecha and fecha < abre) then table.insert(grupos, {abre}) i = abre + 1 else if fecha and #grupos > 0 then local encontrou for n = 0, #grupos - 1 do if not grupos[#grupos - n][2] then grupos[#grupos - n][2] = fecha encontrou = true end end if encontrou then i = fecha + 1 end elseif fecha then i = fecha + 1 else break end end end i = 1 while i < #s do local pos, fim = mw.ustring.find(s, 'P%d[%w:%-/]*', i) if pos then props[string.sub(s, pos, fim)] = pos i = fim + 1 else break end end return grupos, props end -- Processa expressões que pedem dados do Wikidata wd.expandir = function(str) local grupos, props = parser(str) local expandido = {} local debug = {} for prop, pos in pairs(props) do local valor = wd.dados(prop) if valor then table.insert(expandido, pos) props[prop] = valor else props[prop] = false end table.insert(debug, prop .. ' [' .. (wd.temp.tipo or '?') .. ']: ' .. (wd.temp.debug or '')) wd.temp = {} end if #expandido == 0 then wd.temp.debug = #debug > 0 and table.concat(debug, '\n') or 'nenhuma propriedade em "' .. str .. '"' return nil end wd.temp.debug = #debug > 0 and table.concat(debug, '\n') or 'houve algum problema ao espandir "' .. str .. '"' for _, g in ipairs(grupos) do if #g == 2 then local apagar = true for _, pos in ipairs(expandido) do if g[1] < pos and g[2] > pos then apagar = false break end end if apagar then -- os grupos sem propriedades expandidas é preenchido com caracteres { para ser apagado str = str:sub(1, g[1]) .. string.rep('{', g[2] - g[1] - 1) .. str:sub(g[2]) end end end str = str:gsub('[{}]+', '') -- apaga caracteres { e } local oprops = {} -- Ordenando as propriedades pelo tamanho da string para evitar problemas quando uma é substring da outra for prop, valor in pairs(props) do local i = #oprops + 1 for n, s in ipairs(oprops) do if #s < #prop then i = n break end end table.insert(oprops, i, prop) end -- Substituindo as propriedades pelo seu valor expandido for n, prop in ipairs(oprops) do local escprop = prop:gsub('[%^%$%(%)%%%.%[%]%*%+%-%?]','%%%1') -- escapando caracteres especiais str = str:gsub(escprop, type(props[prop]) == 'string' and props[prop] or '') end return str end -- Processa os campos da infobox que pedem propriedades do Wikidata wd.infocampos = function() debug.wikidata = {} for _, i in ipairs(verwikidata) do while campos[i][1] do local arg = string.match(campos[i][1], '^#[Ww][Dd]: *(.*)') if arg then local campo = wd.expandir(arg) if wd.temp.debug then table.insert(debug.wikidata, wd.temp.debug) wd.temp = {} end if campo then campos[i][1] = campo campos[i]['wikidata'] = true break else table.remove(campos[i], 1) end elseif campos[i][1] == '' then table.remove(campos[i], 1) else break end end end end -- Tabela para funções invocadas diretamente, usadas para testes invoke = {} invoke.dados = function(frame) local arg = frame.args['1'] if arg and arg ~= '' then local resp = (wd.dados(arg) or '') if frame.args['2'] == 'debug' then resp = resp .. (wd.temp.debug and ' (' .. wd.temp.debug .. ')' or '') end return resp end return '(erro: nenhuma propriedade fornecida)' end invoke.expandir = function(frame) local arg = frame.args['1'] if arg and arg ~= '' then local resp = (wd.expandir(arg) or '') if frame.args['2'] == 'debug' then resp = resp .. (wd.temp.debug and ' (' .. wd.temp.debug .. ')' or '') end return resp end return '(erro: nenhuma propriedade fornecida)' end return invoke