Модуль:Другие источники

Материал из Викитеки — свободной библиотеки
Перейти к навигации Перейти к поиску
Документация Документация

Подгружает данные из Викиданных и интерпретирует их, показывая в шапках статей. Используется в Модуль:Отексте, Шаблон:Отексте.

local currentProject = 'ruwikisource';
local wd = require("Module:WD");

local otherSources = {
     { id = 'Q42068474', argument = 'ББСРП', title = 'ББСРП', project = 'ruwikisource',	titleVT = 'ББСРП/$1',  titleDO = 'ББСРП/$1'},
     { id = 'Q19133013', argument = 'БСА',   title = 'БСА',   project = 'ruwikisource',	titleVT = 'Ботанический словарь (Анненков)/$1', titleDO = 'Ботанический словарь (Анненков)/$1/ДО'},
     { id = 'Q20078554', argument = 'БСЭ1',  title = 'БСЭ1',  project = 'ruwikisource',	titleVT = 'БСЭ1/$1',   titleDO = 'БСЭ1/$1'},
     { id = 'Q4086271',  argument = 'БЭАН',  title = 'БЭАН',  project = 'ruwikisource',	titleVT = 'БЭАН/$1',   titleDO = 'БЭАН/$1'},
     { id = 'Q4091878',  argument = 'БЭЮ',   title = 'БЭЮ',   project = 'ruwikisource',	titleVT = 'БЭЮ/$1',    titleDO = 'БЭЮ/$1'},
     { id = 'Q42960993', argument = 'БЭЮ2',  title = 'БЭЮ2',  project = 'ruwikisource',	titleVT = 'БЭЮ2/$1',   titleDO = 'БЭЮ2/$1'},
     { id = 'Q4114391',  argument = 'ВЭ',    title = 'ВЭ',    project = 'ruwikisource',	titleVT = 'ВЭ/ВТ/$1',  titleDO = 'ВЭ/ДО/$1'},
     { id = 'Q4114561',  argument = 'ВЭЛ',   title = 'ВЭЛ',   project = 'ruwikisource',	titleVT = 'ВЭЛ/ВТ/$1', titleDO = 'ВЭЛ/ДО/$1'},
     { id = 'Q4135594',  argument = 'ГСС',   title = 'ГСС',   project = 'ruwikisource',	titleVT = 'ГСС/ДО/$1', titleDO = 'ГСС/ДО/$1'},
     { id = 'Q4173137',  argument = 'ЕЭБЕ',  title = 'ЕЭБЕ',  project = 'ruwikisource',	titleVT = 'ЕЭБЕ/$1',   titleDO = 'ЕЭБЕ/$1'},
     { id = 'Q27680201', argument = 'МСР',   title = 'МСР',   project = 'ruwikisource',	titleVT = 'МСР/ВТ/$1', titleDO = 'МСР/ДО/$1'},
     { id = 'Q19180675', argument = 'МЭСБЕ', title = 'МЭСБЕ', project = 'ruwikisource',	titleVT = 'МЭСБЕ/$1',  titleDO = 'МЭСБЕ/$1'},
     { id = 'Q19190511', argument = 'НЭС',   title = 'НЭС',   project = 'ruwikisource',	titleVT = 'НЭС/$1',    titleDO = 'НЭС/$1'},
     { id = 'Q19211082', argument = 'ПБЭ',   title = 'ПБЭ',   project = 'ruwikisource',	titleVT = 'ПБЭ/ВТ/$1', titleDO = 'ПБЭ/ДО/$1'},
     { id = 'Q1960551',  argument = 'РБС',   title = 'РБС',   project = 'ruwikisource',	titleVT = 'РБС/ВТ/$1', titleDO = 'РБС/ДО/$1'},
     { id = 'Q30059240', argument = 'РСКД',  title = 'РСКД',  project = 'ruwikisource',	titleVT = 'РСКД/$1',   titleDO = 'РСКД/$1'},
     { id = 'Q19217220', argument = 'РЭСБ',  title = 'РЭСБ',  project = 'ruwikisource',	titleVT = 'РЭСБ/$1',   titleDO = 'РЭСБ/$1'},
     { id = 'Q4423792',  argument = 'СДЛРЗ', title = 'СДЛРЗ', project = 'ruwikisource',	titleVT = 'СДЛРЗ/ВТ/$1', titleDO = 'СДЛРЗ/ДО/$1'},
     { id = 'Q32361777', argument = 'СЭС',   title = 'СЭС',   project = 'ruwikisource',	titleVT = 'СЭС/ВТ/$1', titleDO = 'СЭС/ДО/$1'},
     { id = 'Q1970746',  argument = 'ТСД',   title = 'ТСД',   project = 'ruwikisource',	titleVT = 'ТСД[123]/$1',    titleDO = 'ТСД[123]/$1/ДО'},
	 { id = 'Q23705360', argument = 'ТСД1',  title = 'ТСД1',  project = 'ruwikisource',	titleVT = 'ТСД1/$1',   titleDO = 'ТСД1/$1/ДО'},
	 { id = 'Q23705356', argument = 'ТСД2',  title = 'ТСД2',  project = 'ruwikisource',	titleVT = 'ТСД2/$1',   titleDO = 'ТСД2/$1/ДО'},
	 { id = 'Q23705304', argument = 'ТСД3',  title = 'ТСД3',  project = 'ruwikisource',	titleVT = 'ТСД3/$1',   titleDO = 'ТСД3/$1/ДО'},
     { id = 'Q20078551', argument = 'ТЭ1',   title = 'ТЭ1',   project = 'ruwikisource',	titleVT = 'ТЭ1/$1',    titleDO = 'ТЭ1/$1'},
     { id = 'Q4532143',  argument = 'ЭВМН',  title = 'ЭВМН',  project = 'ruwikisource',	titleVT = 'ЭВМН/ВТ/$1', titleDO = 'ЭВМН/ДО/$1'},     
     { id = 'Q4532135',  argument = 'ЭЛ',    title = 'ЭЛ',    project = 'ruwikisource',	titleVT = 'ЭЛ/ВТ/$1',  titleDO = 'ЭЛ/ДО/$1'},     
     { id = 'Q602358',   argument = 'ЭСБЕ',  title = 'ЭСБЕ',  project = 'ruwikisource',	titleVT = 'ЭСБЕ/$1',   titleDO = 'ЭСБЕ/$1/ДО'},
     { id = 'Q4532138',  argument = 'ЭСГ',   title = 'ЭСГ',   project = 'ruwikisource',	titleVT = 'ЭСГ/$1',    titleDO = 'ЭСГ/$1/ДО'},

     { id = 'Q590208',		argument = 'ADB',			title = 'ADB',							project = 'dewikisource',	projectCode = 'de:',	prefix='ADB:',											suffix=''	},
     { id = 'Q1138524',		argument = 'RE',			title = 'RE',							project = 'dewikisource',	projectCode = 'de:',	prefix='RE:',											suffix=''	},

     { id = 'Q19077875',	argument = 'AC',			title = 'American Cycl. (1879)',		project = 'enwikisource',	projectCode = 'en:',	prefix='The American Cyclopædia (1879)/',				suffix=''	},
     { id = 'Q19037977',	argument = 'AMB',			title = 'American Med. Biogr. (1920)',	project = 'enwikisource',	projectCode = 'en:',	prefix='American Medical Biographies/',					suffix=''	},
     { id = 'Q12912667',	argument = 'ACAB-1',		title = 'Appletons\' (1887—1901)',		project = 'enwikisource',	projectCode = 'en:',	prefix='Appletons\' Cyclopædia of American Biography/',	suffix=''	},
     { id = 'Q20096917',	argument = 'Британника-9',	title = 'Britannica (9-th)',			project = 'enwikisource',	projectCode = 'en:',	prefix='Encyclopædia Britannica, Ninth Edition/',		suffix=''	},
     { id = 'Q867541',		argument = 'Британника',	title = 'Britannica (11-th)',			project = 'enwikisource',	projectCode = 'en:',	prefix='1911 Encyclopædia Britannica/',					suffix=''	},
     { id = 'Q15987490',	argument = 'Британника-12',	title = 'Britannica (12-th)',			project = 'enwikisource',	projectCode = 'en:',	prefix='1922 Encyclopædia Britannica/',					suffix=''	},
     { id = 'Q302556',		argument = 'Catholic',		title = 'CE (1907—13)',		project = 'enwikisource',	projectCode = 'en:',	prefix='Catholic Encyclopedia (1913)/',					suffix=''	},
     { id = 'Q15987216',	argument = 'DNB', 			title = 'DNB (1885—1900)',			project = 'enwikisource',	projectCode = 'en:',	prefix='',												suffix=' (DNB00)'},
     { id = 'Q16014700',	argument = 'DNB01',			title = 'DNB (1901)',					project = 'enwikisource',	projectCode = 'en:',	prefix='',												suffix=' (DNB01)'},
     { id = 'Q16014697',	argument = 'DNB12',			title = 'DNB (1912)',					project = 'enwikisource',	projectCode = 'en:',	prefix='',												suffix=' (DNB12)'},
     { id = 'Q16011749',	argument = 'DMM',			title = 'DMM (1900)',		project = 'enwikisource',	projectCode = 'en:',	prefix='A Dictionary of Music and Musicians/',							suffix=''	},
     { id = 'Q19051181',	argument = 'CEM',			title = 'CEM',		project = 'enwikisource',	projectCode = 'en:',	prefix='Complete Encyclopaedia of Music/',							suffix=''	},
     { id = 'Q653922',		argument = 'JE',			title = 'JE (1901—06)',		project = 'enwikisource',	projectCode = 'en:',	prefix='Jewish Encyclopedia/',							suffix=''	},
     { id = 'Q20089963',	argument = 'NIE',			title = 'NIE (1902—05)',		project = 'enwikisource',	projectCode = 'en:',	prefix='The New International Encyclopædia/',			suffix=''	},
     { id = 'Q16082057',	argument = 'NSRW',			title = 'NSRW (1914)',		project = 'enwikisource',	projectCode = 'en:',	prefix='The New Student\'s Reference Work/',			suffix=''	},
     { id = 'Q16055052',	argument = 'NBD',			title = 'NBD',		project = 'enwikisource',	projectCode = 'en:',	prefix='A Naval Biographical Dictionary/',			suffix=''},
     { id = 'Q19085957',	argument = 'EA',			title = 'EA (1920)',		project = 'enwikisource',	projectCode = 'en:',	prefix='The Encyclopedia Americana (1920)/', suffix=''},
     { id = 'Q48606171',	argument = 'EBD',			title = 'EBD (1897)',		project = 'enwikisource',	projectCode = 'en:',	prefix='Easton\'s Bible Dictionary (1897)/', suffix=''},
     { id = 'Q47500198',	argument = 'DGRBM',			title = 'DGRBM',		project = 'enwikisource',	projectCode = 'en:',	prefix='Dictionary of Greek and Roman Biography and Mythology/', suffix=''},

     { id = 'Q20961706',	argument = 'DI',			title = 'DI',		project = 'frwikisource',	projectCode = 'fr:',	prefix='Dictionnaire infernal/6e éd., 1863/',			suffix=''},
     
     { id = 'Q2041543', 	argument = 'OSN',			title = 'OSN',		project = 'cswikisource',	projectCode = 'cs:',	prefix='Ottův slovník naučný/', suffix='' },
     { id = 'Q19538713', 	argument = 'VSH',			title = 'VSH',		project = 'cswikisource',	projectCode = 'cs:',	prefix='Vlastenský slovník historický/', suffix='' }
}

local function getClaimValues( entity, propertyId )
    local result = {}
    local claim = entity.claims[ propertyId ];
    if ( claim == nil ) then
        return result;
    end

    for _, statement in pairs( claim ) do
        local mainsnak = statement.mainsnak;
        if ( mainsnak ~= nil and mainsnak.datavalue ~= nil ) then
            if ( mainsnak.datavalue.type == "string" ) then
                result[#result+1] = mainsnak.datavalue.value;
            elseif ( mainsnak.datavalue.type == "wikibase-entityid" ) then
                result[#result+1] = 'Q' .. mainsnak.datavalue.value["numeric-id"];
            else 
                result[#result+1] = mainsnak.datavalue.value;
            end
        end
    end

    return result;
end

local function getQualifierValues( statement, qualifierName )
    local result = {}
        if (statement ~= nil
            and statement.qualifiers ~= nil
            and statement.qualifiers[qualifierName] ~= nil) then
        local qualifiers = statement.qualifiers[qualifierName];
        for _, qualifier in pairs( qualifiers ) do
            if (qualifier.datavalue ~= nil
                and qualifier.datavalue.type ~= nil
                and qualifier.datavalue.value ~= nil) then
 
                if ( qualifier.datavalue.type == "wikibase-entityid" ) then
                    result[#result+1] = 'Q' .. qualifier.datavalue.value["numeric-id"];
                end
            end
        end
    end
    return result;
end

local p = {};

function p.populateOtherSourcesByEntityId( entityId, result )

    if ( result == nil ) then
        result = {};
    end

    if ( entityId == nil ) then
        return result;
    end

    local entity = mw.wikibase.getEntity( entityId );
    if ( entity == nil ) then
        return result;
    end

    return p.populateOtherSourcesByEntity( entity, result );
end

function p.populateOtherSourcesByEntity( entity, result )

    if ( result == nil ) then
        result = {};
    end

    if ( entity == nil or entity.claims == nil ) then
        return result;
    end

    -- first check current item references
    local describedByClaim = entity.claims[ 'P1343' ];
    if ( describedByClaim ~= nil ) then
        for _, statement in pairs( describedByClaim ) do
            if ( statement.mainsnak ~= nil
            		and statement.rank ~= 'deprecated'
                    and statement.mainsnak.datavalue.type == "wikibase-entityid"
                    and statement.mainsnak.datavalue.value["numeric-id"] ~= nil ) then
                local dictId = 'Q' .. statement.mainsnak.datavalue.value["numeric-id"]

                for _, sourceDescription in pairs( otherSources ) do
                    local dictionaryShortTitle = sourceDescription.argument;
                    local dictinaryEntityId = sourceDescription.id;

                    if ( dictinaryEntityId == dictId ) then
                    	local qualifiers = getQualifierValues(statement, 'P805');  -- P805 тема утверждения
                    	if (qualifiers == nil or #qualifiers == 0) then
                    		qualifiers = getQualifierValues(statement, 'P248');    -- P248 утверждается в (deprecated)
                    	end;
                        for _, qualifierValue in pairs( qualifiers ) do
                            local dictLinks = result[ dictionaryShortTitle ];
                            if ( dictLinks == nil ) then
                                dictLinks = {};
                                result[ dictionaryShortTitle ] = dictLinks;
                            end
                            dictLinks[ qualifierValue ] = qualifierValue;
                        end
                    end
                end
            end
        end
    end

    -- check if entity have main topic item
    if ( entity ) then
        if wd.has_valid_item_value (entity, "P31", 17329259) or wd.has_valid_item_value (entity, "P31", 4423781) then
            -- для энциклопедических и словарных статей (P31 = Q17329259/Q4423781) просматриваем P921 ("основная тема произведения")
            local parentEntityIds = getClaimValues( entity, 'P921' );
            for _, parentEntityId in pairs( parentEntityIds ) do
                p.populateOtherSourcesByEntityId( parentEntityId, result );
            end
        end
    end

    -- check if entity have edition of item
    if ( entity ) then
        local parentEntityIds = getClaimValues( entity, 'P629' );
        for _, parentEntityId in pairs( parentEntityIds ) do
            p.populateOtherSourcesByEntityId( parentEntityId, result );
        end
    end

    return result;
end
--[[
parseLink("ЭСБЕ/Пупкин, Иван Васильевич/ДО", "ЭСБЕ/$1/ДО") → "Пупкин, Иван Васильевич"
parseLink("ЭСБЕ/Пупкин, Иван Васильевич",    "ЭСБЕ/$1/ДО") → nil
]]
local function parseLink(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);
--	for s_catch in string.match(s_sitelink, s_regexp) do
--		return s_catch;
--	end;
--	return nil;
end;

--[[
{{#invoke:Другие источники|test_parseLink|ЭСБЕ/Пупкин, Иван Васильевич/ДО|ЭСБЕ/$1/ДО}} → "Пупкин, Иван Васильевич"
{{#invoke:Другие источники|test_parseLink|МЭСБЕ/Аконит|МЭСБЕ/$1}} → "Аконит"
{{#invoke:Другие источники|test_parseLink|ЭСБЕ/Аконит|МЭСБЕ/$1}} → nil
]]
function p.test_parseLink(frame)
  local s_sitelink  = tostring(frame.args[1]);
  local s_pattern   = tostring(frame.args[2]);
  local s_title     = parseLink(s_sitelink, s_pattern);
  if s_title == nil then
    return "nil";
  else
    return '"'..s_title..'"';
  end;
end;

local function getLink( sourceDescription, entityId, isDO )
	if sourceDescription.project ~= currentProject then
	    local entity = mw.wikibase.getEntity( entityId );
	    if not entity then
	    	mw.log("Невозможно загрузить "..tostring(entityId));
	        return nil;
	    end;
	    if (entity.sitelinks == nil) or (entity.sitelinks[sourceDescription.project] == nil) then
	    	mw.log("В "..tostring(entityId).." нет ссылки на "..sourceDescription.project.." для "..sourceDescription.argument);
	    	return nil;
	    end;
		return ':' .. sourceDescription.projectCode .. entity.sitelinks[sourceDescription.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 isDO then
		s_primary_pattern   = sourceDescription.titleDO;
		s_secondary_pattern = sourceDescription.titleVT;
	else
		s_primary_pattern   = sourceDescription.titleVT;
		s_secondary_pattern = sourceDescription.titleDO;
	end;
	if parseLink(s_sitelink, s_primary_pattern) ~= nil then  -- ссылка из Викиданных соответсвует признаку isDO
		return s_sitelink; -- т.к. ссылка  получена из Викиданных, поверять её существование не надо, просто её возвращаем
	end;
	-- Т.к. ссылка из Викиданных не соответсвует признаку isDO,
	-- попробуем возвратить "правильную" ссылку (если она существует, конечно)
	local s_article_title = parseLink(s_sitelink, s_secondary_pattern);
	if s_article_title == nil then
		-- ссылка не соответсвует ни titleDO, ни titleVT
		-- это какая-то ошибка, выводим сообщение на консоль и возвращаем её
		mw.log("ссылка на "..sourceDescription.title.." нарушает правила именования: "..s_sitelink);
        return s_sitelink;
	end;
	local s_link;
	if sourceDescription.id == "Q1970746" then -- workaround для ТСД
		s_link = "ТСД/"..s_article_title;
        if isDO 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;

local function isNotBlank( str )
    return str ~= nil and mw.ustring.len( str ) > 0;
end

local function isCurrentPageDO( )
    local title = mw.title.getCurrentTitle().text;
    return mw.ustring.find( title, '/ДО/' ) ~= nil or mw.ustring.find( title, '/ДО' ) == mw.ustring.len( title ) - 2;
end

local function getPageTitleFromArgument( sourceDescription, title, isDO )
	if ( sourceDescription.project ~= currentProject ) then
		return ':' .. sourceDescription.projectCode .. sourceDescription.prefix .. title .. sourceDescription.suffix;
	end
	local linkVT = nil;
	local linkDO = nil;
	if sourceDescription.id == "Q1970746" then -- workaround для ручного параметра ТСД=
      linkVT = "ТСД/" .. title;
      linkDO = linkVT .. "/ДО"
    else  
      linkVT = string.gsub(sourceDescription.titleVT, "$1", title);
      linkDO = string.gsub(sourceDescription.titleDO, "$1", title);
	end;	
    if ( isDO ) then
        if ( mw.title.new( linkDO , 0 ).exists ) then
            return linkDO;
        elseif ( mw.title.new( linkVT , 0 ).exists ) then
            return linkVT;
        else
        	return linkDO;
        end
    else
    	if ( mw.title.new( linkVT , 0 ).exists ) then
            return linkVT;
    	elseif ( mw.title.new( linkDO , 0 ).exists ) then
        	return linkDO;
        else
            return linkVT;
        end
    end
end

local function getLinkFromArgument( sourceDescription, title, isDO )
    return ': [[' .. getPageTitleFromArgument( sourceDescription, title, isDO ) .. '|' .. sourceDescription.title .. ']] ';
end

function p.renderOtherSources( frame )
    local args = frame:getParent().args;
    local otherSourcesIds = p.populateOtherSourcesByEntity( mw.wikibase.getEntity(), nil );
    local isDO = isCurrentPageDO();
    local result;
    if isDO then
        result = "'''Другіе источники'''";
    else
        result = "'''Другие источники'''";
    end;
    local count = 0;
    for _, sourceDescription in pairs( otherSources ) do
        local dictArgName = sourceDescription.argument;
        local id = sourceDescription.id;
        local s_this_page = mw.title.getCurrentTitle().text;
        if not ((sourceDescription.project == currentProject) and ((parseLink(s_this_page, sourceDescription.titleVT) ~= nil) or (parseLink(s_this_page, sourceDescription.titleDO) ~= nil))) then
            local s_param_value = args[dictArgName];
            local ids = otherSourcesIds[dictArgName];
            if isNotBlank(s_param_value) then
            	-- local keyword to suppress WD output
            	if s_param_value ~= '__NULL__' then
            		for elem in mw.text.gsplit( s_param_value, '%s*~%s*' ) do -- несколько значений в одном параметре
                		result = result .. getLinkFromArgument( sourceDescription, elem, isDO );
            		end
                	result = result .. '[[Категория:Викитека:Ручная ссылка:' .. dictArgName .. ']]';
                	count = count + 1;
            	end;
            elseif ids ~= nil then
                for _, id in pairs(ids) do
                	local link = getLink(sourceDescription, id, isDO);
                	if link == nil then
                		error("Не удаётся получить ссылку на ".. sourceDescription.project .. ' из элемента ' .. id);
                        end;
                  	result = result .. ': [[' .. link .. '|' .. sourceDescription.title .. ']][[Категория:Викитека:Ссылка из Викиданных:' .. dictArgName .. ']] ';
                   	count = count + 1;
                end;
            end;
        end;
    end;
    if count == 0 then
        return nil;
    end
    return frame:preprocess( '{{*}} ' .. result );
end

return p;