Модуль:Источники по теме/wikidata
Для документации этого модуля может быть создана страница Модуль:Источники по теме/wikidata/doc
local RU = 'ru' local RUWIKISOURCE = 'ruwikisource' local wd = require("Module:WD") local util = require("Module:Util") local encyclopediasData = util.get_json("MediaWiki:Encyclopedias settings.json") -- настройки заголовков энциклопедий и их id в ВД local encyclopedias_sites_cfg = util.get_json("MediaWiki:Encyclopedias sites.json") -- настройки энциклопедий на внеших сайтах local p = {} local page function p.getQualifierValues(statement, qualifierName) local result = {} if statement then local q = statement.qualifiers if q and q[qualifierName] ~= nil then for _, qualifier in pairs(q[qualifierName]) do local d = qualifier.datavalue if d and d.type ~= nil and d.value ~= nil then if d.type == "wikibase-entityid" then result[#result + 1] = d.value["id"] end end end end end return result end -- deprecated, не используется local function check_backlink(entity) local has_backlink if entity and entity.claims and entity.claims.P1343 then for _, refs in pairs(entity.claims.P1343) do if refs.qualifiers and refs.qualifiers.P805 then for _, ref in pairs(refs.qualifiers.P805) do if ref.datavalue and ref.datavalue.value and ref.datavalue.value.id then local ref_id = ref.datavalue.value.id if ref_id == page.entity.id then has_backlink = true break end end end if has_backlink then break end end end end return has_backlink end function p.get_sitelinks_from_entity(entity, result) -- populate from entity interwiki local result = result or {} local sitelinks = entity.sitelinks if sitelinks ~= nil then for sitecode, sitelink in pairs(sitelinks) do -- mw.log(" "..sitecode.." = "..sitelink.title) if result[sitecode] == nil then result[sitecode] = sitelink.title end end end if result['commons'] == nil then local commonsCategories = wd.getClaimValues_ranked(entity, 'P373') for _, commonsCategory in pairs(commonsCategories) do result['commons'] = 'Category:' .. commonsCategory break end -- если commons нет в интервиках и в P373, то использовать изображение из P18 if result['commons'] == nil then local commonsCategories = wd.getClaimValues_ranked(entity, 'P18') for _, commonsCategory in pairs(commonsCategories) do result['commons'] = 'File:' .. commonsCategory break end end end return result end function p.get_ext_enc_sites(entity, result) local result = page.external_sites for _, site in pairs(encyclopedias_sites_cfg) do local enc_name, property_id, url_pattern = site.argument, site.property, site.url_pattern local id local ids = wd.getClaimValues_ranked(entity, property_id); if ids then id = ids[1] end -- local ids_sts = entity:getBestStatements(site.property); if ids_sts then id = wd.get_statement_value(ids_sts, wd.DT_EXT_ID, wd.VT_STRING)[1] end if id and not result[enc_name] then site.wikilink = util.make_ext_link(url_pattern:gsub("$1", id), enc_name) site.id = id result[enc_name] = site end end return result end -- загрузка ссылок из элементов в списке указанного свойства local function get_links_from_items_of_property(entity, property_id) local targets = wd.getClaimValues_ranked(entity, property_id) -- mw.logObject(targets, "targets") if #targets > 0 then for key, entity_id in pairs(targets) do if property_id == 'P921' then -- P921 "основная тема произведения" page.has_topic_property = true end local entity_target = wd.get_entity_by_id(entity_id) if entity_target then p.populate_data(entity_target) end end end end -- загрузка данных из элемента страницы local is_topic_entity_reached = false local is_edition_as_topic_reached = false function p.populate_data(entity) if not entity or not entity.claims then return end if wd.has_valid_item_value(entity, "P31", 'Q3331189') and not is_topic_entity_reached and not is_edition_as_topic_reached then -- Q3331189 "версия или издание" -- Переменные `is_topic_entity_reached` и `is_edition_as_topic_reached` ограничивают глубину подгрузки элементов. -- Проверка: -- На странице [[Ветхий Завет (Макарий)]] [[d:Q4350033]] должна показываться ссылка на [[w:Перевод Библии архимандрита Макария]]. При этом элемент является Q3331189 версией Библии. -- На странице [[ЕЭБЕ/Пешитта]] [[d:Q24922704]] должна показываться ссылка на [[w:Пешитта]]. При этом темой указана "Пешита", которая является Q3331189 версией Библии. -- Не должно быть перехода на глубокий элемент [[w:Библия]]. local sitelinks_ = p.get_sitelinks_from_entity(entity) sitelinks_['ruwikisource'] = nil if next( sitelinks_ ) then is_edition_as_topic_reached = true end end if wd.has_valid_item_value(entity, "P31", 'Q3331189') and not is_topic_entity_reached and not is_edition_as_topic_reached then -- Q3331189 "версия или издание" -- загрузка из элементов в списке P629 "является изданием или переводом" get_links_from_items_of_property(entity, "P629") elseif wd.is_encyclopedic_article(entity) and entity.claims['P921'] and not is_topic_entity_reached then -- для энциклопедических, словарных статей и перенаправлений (P31 in [Q10389811, Q13433827, Q1580166, Q1302249]) -- загрузка из элементов в списке P921 "основная тема произведения" if wd.has_valid_item_value(entity, "P31", 'Q1302249') then -- Q1302249 "перекрёстная ссылка" page.has_xref_property = true end is_topic_entity_reached = true get_links_from_items_of_property(entity, "P921") else -- загрузка из текущего элемента local label = entity.labels and ((entity.labels.ru and entity.labels.ru.value) or (entity.labels.en and entity.labels.en.value)) or entity.id table.insert( page.sitelinks, { label = label, id = entity.id, data = p.get_sitelinks_from_entity(entity) } ) page.sitelinks[#page.sitelinks]['data']['wikidata'] = entity.id page.encyclopedias_ids = p.get_ids_of_described_encs(entity) p.get_ext_enc_sites(entity) end return page end -- проход P1343 - списка «описывается в источниках» function p.get_ids_of_described_encs(entity) local result = page.encyclopedias_ids -- local describedByClaim = wd.getClaimValues_ranked( entity, 'P1343' ) local describedByClaim = entity:getBestStatements('P1343') -- P1343 «описывается в источниках» for _, statement in pairs( describedByClaim ) do local snak = statement["mainsnak"] if snak.datavalue.type == wd.VT_ENTITY_ID then local dictId = snak.datavalue.value["id"] local qualifiers = p.getQualifierValues(statement, 'P805') -- P805 тема утверждения if qualifiers == nil or #qualifiers == 0 then qualifiers = p.getQualifierValues(statement, 'P248') -- P248 утверждается в (deprecated) end for _, articleId in pairs(qualifiers) do for _, enc in pairs(encyclopediasData) do local dictionaryShortTitle = enc.argument if enc.id == dictId then -- todo: enc.id == dictId не работает для элементов отдельных томов, напр. [[d:Q23892934]], ибо их нет в encyclopediasData. Надо см. наличие P361 "часть от" и сверять с ним, если эти лишние запросы вообще нужны. local dictLinks = result[dictionaryShortTitle] if dictLinks == nil then dictLinks = {} result[dictionaryShortTitle] = dictLinks end dictLinks[articleId] = articleId break end end if page.entity and articleId == page.entity.id then page.has_backlink = true end -- проверка обратной ссылки, используется для категоризации end end end return result end --[[ is_match_pagenames("ЭСБЕ/Пупкин, Иван Васильевич/ДО", "ЭСБЕ/$1/ДО") → "Пупкин, Иван Васильевич" is_match_pagenames("ЭСБЕ/Пупкин, Иван Васильевич", "ЭСБЕ/$1/ДО") → nil ]] function p.is_match_pagenames(s_sitelink, s_pattern) local s_regexp = string.gsub(s_pattern, "%(", "%%(") s_regexp = string.gsub(s_regexp, "%)", "%%)") s_regexp = "^" .. string.gsub(s_regexp, "$1", "(.+)") .. "$" -- mw.log("regexp: "..s_regexp) return string.match(s_sitelink, s_regexp) end --[[ {{#invoke:Другие источники|test_is_match_pagenames|ЭСБЕ/Пупкин, Иван Васильевич/ДО|ЭСБЕ/$1/ДО}} → "Пупкин, Иван Васильевич" {{#invoke:Другие источники|test_is_match_pagenames|МЭСБЕ/Аконит|МЭСБЕ/$1}} → "Аконит" {{#invoke:Другие источники|test_is_match_pagenames|ЭСБЕ/Аконит|МЭСБЕ/$1}} → nil ]] local function test_is_match_pagenames(frame) local s_sitelink = tostring(frame.args[1]) local s_pattern = tostring(frame.args[2]) local s_title = p.is_match_pagenames(s_sitelink, s_pattern) if s_title == nil then return "nil" else return '"' .. s_title .. '"' end end local function getDefaultTitle() for _, enc in pairs(encyclopediasData) do if enc.project == RUWIKISOURCE and enc.titleDO then local DO = (enc.default == 'DO') local titleVT, titleDO = enc.titleVT, enc.titleDO local nameVT, nameDO = p.is_match_pagenames(page.title, titleVT), p.is_match_pagenames(page.title, titleDO) if nameDO then if DO then return titleDO:gsub('$1', nameDO) else return titleVT:gsub('$1', nameDO) end elseif nameVT then if DO then return titleDO:gsub('$1', nameVT) else return titleVT:gsub('$1', nameVT) end end end end return page.title end function p.getLink(enc, entityId, isPRS) if enc.project ~= RUWIKISOURCE then local entity = wd.get_entity_by_id(entityId) if not entity then mw.log("Невозможно загрузить " .. tostring(entityId)) return nil end if (entity.sitelinks == nil) or (entity.sitelinks[enc.project] == nil) then mw.log("В " .. tostring(entityId) .. " нет ссылки на " .. enc.project .. " для " .. enc.argument) return nil end return ':' .. enc.projectCode .. entity.sitelinks[enc.project].title end local s_sitelink = mw.wikibase.sitelink(entityId) if s_sitelink == nil then return nil end local s_primary_pattern = nil local s_secondary_pattern = nil if isPRS then s_primary_pattern = enc.titleDO s_secondary_pattern = enc.titleVT else s_primary_pattern = enc.titleVT s_secondary_pattern = enc.titleDO end -- mw.log(isPRS, s_primary_pattern, s_secondary_pattern, s_sitelink) if p.is_match_pagenames(s_sitelink, s_primary_pattern) ~= nil then -- ссылка из Викиданных соответствует признаку isPRS return s_sitelink -- т.к. ссылка получена из Викиданных, поверять её существование не надо, просто её возвращаем end local s_article_title if enc.titleDO then s_article_title = p.is_match_pagenames(s_sitelink, s_secondary_pattern) end if not s_article_title then -- ссылка не соответствует ни titleDO, ни titleVT mw.log("ссылка на " .. enc.title .. " нарушает правила именования: " .. s_sitelink) return s_sitelink end local s_link if enc.id == "Q1970746" then -- для ТСД s_link = "ТСД/" .. s_article_title if isPRS then s_link = s_link .. "/ДО" end else s_link = string.gsub(s_primary_pattern, "$1", s_article_title) end if mw.title.new(s_link, 0).exists then return s_link else return s_sitelink end end -- загружает элемент текущей страницы function p.get_page_entity() entity = mw.wikibase.getEntity() if not entity then local default_title = getDefaultTitle() entity = mw.wikibase.getEntity(mw.wikibase.getEntityIdForTitle(default_title)) end return entity end -- загружает элемент темы если даны параметры шаблона ВИКИДАННЫЕ или ВИКИПЕДИЯ function p.get_page_entity_topic_by_template_arg(args) local topic_id = is(args['ВИКИДАННЫЕ']) local wp_pagename = is(args['ВИКИПЕДИЯ']) if topic_id or wp_pagename then if not topic_id then local lang, title = string.match(wp_pagename, '^:?([a-z]+):(.+)') -- ссылка формата ':код_языка:Название' в параметрах if not lang then lang, title = RU, wp_pagename end topic_id = mw.wikibase.getEntityIdForTitle(title, lang .. 'wiki') end return wd.get_entity_by_id(topic_id) end end function p.get_links(_page) page = _page page.entity = p.get_page_entity() page.entity_topic_by_template_arg = p.get_page_entity_topic_by_template_arg(page.args) -- элемент темы, указанный в параметрах ВИКИПЕДИЯ/ВИКИДАННЫЕ или в элементе Викиданных page.has_encyclopedic_article_status_in_wd = wd.is_encyclopedic_article(page.entity) local entity = page.entity_topic_by_template_arg or page.entity -- загружать ссылки из элемента темы если задан, иначе - из элемента страницы p.populate_data(entity) -- mw.logObject(page, "page") return page end -- проверка переменной, возврат её или nil если пустая function is(var) if (var == '' or var == nil) then return nil else return var end end return p