Модуль:WDBase: различия между версиями
ru>D6194c-1cc (Утверждения, которым не был присвоен номер в упорядоченном массиве должны автоматически попадать в пропуски упорядоченного массива, оставшиеся – в конец) |
Admin (обсуждение | вклад) м (1 версия импортирована) |
(нет различий)
|
Текущая версия от 18:36, 21 июня 2023
Для документации этого модуля может быть создана страница Модуль:WDBase/doc
require('strict') local p = {} p.P_NAME_WORK_LANG = 'P407' p.P_EDITION_FOR = 'P629' p.P_NAMED_AS = 'P1932' p.P_ORDINAL_NUM = 'P1545' p.Q_MULTILANG = 'Q20923490' local defaultLangObj = mw.getContentLanguage() local defaultLang = defaultLangObj:getCode() local fallbackLang = 'en' function p.statements(entity, property) local statements = mw.wikibase.getBestStatements(entity, property) if not statements or next(statements) == nil then return nil end return statements end function p.statementsByProperties(entity, properties) local orderedStatements = {} local statements = {} for _, property in ipairs(properties) do local currStatements = mw.wikibase.getBestStatements(entity, property) if currStatements and next(currStatements) ~= nil then for _, statement in ipairs(currStatements) do local num local qualifiers = statement.qualifiers if qualifiers then local qualifierSnaks = qualifiers[p.P_ORDINAL_NUM] if qualifierSnaks then local datavalue = qualifierSnaks[1].datavalue if datavalue and datavalue.type == 'string' then num = tonumber(datavalue.value) end end end if num then orderedStatements[num] = statement else table.insert(statements, statement) end end end end if next(orderedStatements) == nil then return statements elseif next(statements) == nil then return orderedStatements end -- We assume that all statements must be neither ordered or unordered, so -- all other cases must be fixed in Wikidata, and the below code allowed -- to be slow (rare exceptional cases) local j = 1 for i = 1, table.getn(orderedStatements) do if orderedStatements[i] == nil then orderedStatements[i] = statements[j] j = j + 1 if statements[j] == nil then break; end end end for i = j, table.getn(statements) do table.insert(statements, statements[i]) end return orderedStatements end function p.valueBySnak(snak) local datavalue = snak.datavalue if not datavalue then return nil end if datavalue.type == 'monolingualtext' then return datavalue.value.text, datavalue.value.language elseif datavalue.type == 'wikibase-entityid' then return datavalue.value.id elseif datavalue.type == 'string' then return datavalue.value elseif datavalue.type == 'time' then return p.dateFromDatavalue(datavalue) elseif datavalue.type == 'quantity' then local unitEntity if datavalue.value.unit then unitEntity = datavalue.value.unit:gsub('^.+/([^/]+)$', '%1') end return datavalue.value.amount, unitEntity end end function p.valueByStatement(statement) local snak = statement.mainsnak if not snak then return nil end return p.valueBySnak(snak) end function p.textByStatement(statement, lang) local datavalue = statement.mainsnak.datavalue if not datavalue then return nil end if datavalue.type == 'monolingualtext' then return datavalue.value.text, datavalue.value.language elseif datavalue.type == 'wikibase-entityid' then local entity = datavalue.value.id if lang then return mw.wikibase.getLabelByLang(entity, lang), lang else return mw.wikibase.getLabelWithLang(entity) end elseif datavalue.type == 'string' then return datavalue.value elseif datavalue.type == 'time' then return p.dateToStr(p.dateFromDatavalue(datavalue)) elseif datavalue.value.amount == 'quantity' then local unit local valueLang if lang then unit = mw.wikibase.getLabelByLang(entity, lang) valueLang = lang else unit, valueLang = mw.wikibase.getLabelWithLang(entity) end return datavalue.value.amount .. ' ' .. datavalue.value.unit, valueLang end end function p.value(entity, property) local statements = p.statements(entity, property) if not statements then return nil end return p.valueByStatement(statements[1]) end function p.text(entity, property, lang) local statements = p.statements(entity, property) if not statements then return nil end return p.textByStatement(statements[1], lang) end function p.valueByQualifier(entity, property, qualifier, qualifierValue) local statements = p.statements(entity, property) if not statements then return nil end for _, statement in ipairs(statements) do if statement.mainsnak and statement.qualifiers then local currQualifiers = statement.qualifiers[qualifier] if currQualifiers and currQualifiers[1] then local currQualifier = currQualifiers[1] local value = p.valueBySnak(currQualifier) if value == qualifierValue then return p.valueByStatement(statement) end end end end return nil end function p.tryFilterSnaksByLang(snaks, lang) if not lang then lang = defaultLang end local suitableValueInCurrLang = {} local suitableValueInFallbackLang = {} local suitableValue = {} for _, snak in ipairs(snaks) do local datavalue = snak.datavalue if datavalue.type == 'monolingualtext' then if datavalue.value.language == lang then table.insert(suitableValue, snak) elseif not suitableValueInCurrLang then if datavalue.value.language == fallbackLang then table.insert(suitableValueInCurrLang, snak) end elseif not suitableValueInFallbackLang then if datavalue.value.language == fallbackLang then table.insert(suitableValueInFallbackLang, snak) end end elseif datavalue.type == 'string' and not suitableValue then table.insert(suitableValue, snak) end end if next(suitableValue) ~= nil then return suitableValue elseif next(suitableValueInCurrLang) ~= nil then return suitableValueInCurrLang elseif next(suitableValueInFallbackLang) ~= nil then return suitableValueInFallbackLang else return snaks end end function p.tryFilterStatementsByLang(statements, lang, forceLang) if not lang then lang = defaultLang end local suitableValueInCurrLang = {} local suitableValueInFallbackLang = {} local suitableValue = {} for _, statement in ipairs(statements) do local datavalue = statement.mainsnak.datavalue if datavalue.type == 'monolingualtext' then if datavalue.value.language == lang then table.insert(suitableValue, statement) elseif not forceLang then if not suitableValueInCurrLang then if datavalue.value.language == fallbackLang then table.insert(suitableValueInCurrLang, statement) end elseif not suitableValueInFallbackLang then if datavalue.value.language == fallbackLang then table.insert(suitableValueInFallbackLang, statement) end end end elseif datavalue.type == 'string' and not suitableValue then table.insert(suitableValue, statement) end end if next(suitableValue) ~= nil then return suitableValue elseif next(suitableValueInCurrLang) ~= nil then return suitableValueInCurrLang elseif next(suitableValueInFallbackLang) ~= nil then return suitableValueInFallbackLang elseif not forceLang then return statements else return nil end end function p.filterStatementsByUnit(statements, unit) local filteredStatements = {} for _, statement in ipairs(statements) do local snak = statement.mainsnak if snak then local datavalue = snak.datavalue if datavalue and datavalue.type == 'quantity' then local currUnit = datavalue.value.unit if currUnit then currUnit = currUnit:match('^.*/([^/]+)') if currUnit == unit then table.insert(filteredStatements, statement) end end end end end if next(filteredStatements) == nil then return nil end return filteredStatements end function p.tryTextByLang(entity, property, lang) local statements = p.statements(entity, property) if not statements then return nil end statements = p.tryFilterStatementsByLang(statements, lang, false) return p.textByStatement(statements[1]) end function p.textByLang(entity, property, lang) local statements = p.statements(entity, property) if not statements then return nil end statements = p.tryFilterStatementsByLang(statements, lang, true) if not statements then return nil end return p.textByStatement(statements[1]) end function p.searchStatementByValue(statements, value) for _, statement in ipairs(statements) do local datavalue = statement.mainsnak.datavalue if datavalue.type == 'string' then if datavalue.value == value then return statement end elseif datavalue.type == 'monolingualtext' then if datavalue.value.text == value then return statement end elseif datavalue.type == 'wikibase-entityid' then if datavalue.value.id == value then return statement end elseif datavalue.type == 'quantity' then if tonumber(datavalue.value.amount) == value then return statement end end end end function p.statementByValue(entity, property, value) local statements = p.statements(entity, property) if not statements then return nil end return p.searchStatementByValue(statements, value) end function p.statementQualifier(statement, quailiferProperty) if not statement.qualifiers then return nil end local qualifiers = statement.qualifiers[quailiferProperty] if not qualifiers then return nil end return p.valueBySnak(qualifiers[1]) end function p.resolveParent(entity) local statements = p.statements(entity, p.P_EDITION_FOR) if not statements then return nil end local datavalue = statements[1].mainsnak.datavalue if datavalue.type == 'wikibase-entityid' then return datavalue.value.id end return nil end function p.wikilink(entity, text) local title = mw.wikibase.getSitelink(entity) if not title then return nil end local wikilink if text and text ~= title then wikilink = '[[' .. title .. '|' .. text .. ']]' else wikilink = '[[' .. title .. ']]' end return wikilink, entity end function p.dateFromDatavalue(datavalue) if datavalue.type ~= 'time' then return nil end local precision = datavalue.value.precision local date = {} date.timestamp = datavalue.value.time local sign sign, date.year, date.month, date.day, date.hour, date.minute, date.second = string.match(date.timestamp, '([+-])(%d+)-(%d+)-(%d+)T(%d+):(%d+):(%d+)') date.year = tonumber(date.year) date.month = tonumber(date.month) date.day = tonumber(date.day) date.hour = tonumber(date.hour) date.minute = tonumber(date.minute) date.second = tonumber(date.second) if sign == '-' then date.year = -date.year end if precision < 14 then date.second = nil end if precision < 13 then date.minute = nil end if precision < 12 then date.hour = nil end if precision < 11 then date.day = nil end if precision < 10 then date.month = nil end if precision == 8 then date.decade = date.year end if precision == 7 then date.century = date.year / 100 end if precision == 6 then date.millenium = date.year / 1000 end return date end function p.dateToStr(date, lang) local langObj = mw.getLanguage(lang) if date.second then return langObj:formatDate('d xg Y H:i:s', date.timestamp) elseif date.minute then return langObj:formatDate('d xg Y H:i', date.timestamp) elseif date.hour then return langObj:formatDate('d xg Y H:00', date.timestamp) elseif date.day then return langObj:formatDate('d xg Y', date.timestamp) elseif date.month then return langObj:formatDate('F Y', date.timestamp) elseif date.year then return langObj:formatDate('Y', date.timestamp) end return date.timestamp end function p.instanceOf(entity, property, ofEntities) local statements = p.statements(entity, property) if not statements then return nil end for i=1, table.getn(statements) do local statement = statements[i] if statement.mainsnak then local datavalue = statement.mainsnak.datavalue if datavalue and datavalue.type == 'wikibase-entityid' then local currEntity = datavalue.value.id for j=1, table.getn(ofEntities) do if currEntity == ofEntities[i] then return currEntity end end end end end return nil end function p.dataBySnak(snak, lang) local datavalue = snak.datavalue if not datavalue then return nil end local entity, value, unit, valueLang if datavalue.type == 'wikibase-entityid' then entity = datavalue.value.id if lang then value = mw.wikibase.getLabelByLang(entity, lang) valueLang = lang else value, valueLang = mw.wikibase.getLabelWithLang(entity) end elseif datavalue.type == 'monolingualtext' then value = datavalue.value.text valueLang = datavalue.value.language elseif datavalue.type == 'time' then value = p.dateFromDatavalue(datavalue) elseif datavalue.type == 'quantity' then value = tonumber(datavalue.value.amount) unit = datavalue.value.unit if unit then unit = unit:match('^.*/([^/]+)') end else value = datavalue.value end return { value = value, lang = valueLang, entity = entity, unitEntity = unit } end function p.dataByStatement(statement, lang, novalueQualifier) local snak = statement.mainsnak if not snak then return nil end if not snak.datavalue then if not novalueQualifier then novalueQualifier = p.P_NAMED_AS end if statement.qualifiers then local qualifierSnaks = statement.qualifiers[novalueQualifier] if qualifierSnaks then return p.dataBySnak(qualifierSnaks[1], lang) end end return nil end return p.dataBySnak(snak, lang) end function p.dataByEntity(entity, lang) local value, valueLang if lang then value = mw.wikibase.getLabelByLang(entity, lang) valueLang = lang else value, valueLang = mw.wikibase.getLabelWithLang(entity) end return { value = value, lang = valueLang, entity = entity } end return p