Advertisement
pascaliensis

Wikidata Quickstatements update2025

May 29th, 2025
273
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
JavaScript 9.82 KB | Software | 0 0
  1. {
  2.     "translatorID": "51e5355d-9974-484f-80b9-f84d2b55782e-pascal",
  3.     "label": "Wikidata QuickStatements 2025b",
  4.     "creator": "Philipp Zumstein (with minor edits by Pascal Martinolli)",
  5.     "target": "txt",
  6.     "minVersion": "3.1",
  7.     "maxVersion": "",
  8.     "priority": 100,
  9.     "inRepository": false,
  10.     "translatorType": 2,
  11.     "lastUpdated": "2025-05-21 00:00:00"
  12. }
  13.  
  14.  
  15. /*
  16.     ***** BEGIN LICENSE BLOCK *****
  17.  
  18.     Copyright © 2017 Philipp Zumstein
  19.  
  20.     This file is part of Zotero.
  21.  
  22.     Zotero is free software: you can redistribute it and/or modify
  23.     it under the terms of the GNU Affero General Public License as published by
  24.     the Free Software Foundation, either version 3 of the License, or
  25.     (at your option) any later version.
  26.  
  27.     Zotero is distributed in the hope that it will be useful,
  28.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  29.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  30.     GNU Affero General Public License for more details.
  31.  
  32.     You should have received a copy of the GNU Affero General Public License
  33.     along with Zotero. If not, see <http://www.gnu.org/licenses/>.
  34.  
  35.     ***** END LICENSE BLOCK *****
  36. */
  37.  
  38. /*
  39.     ***** BEGIN REVISION BLOCK *****
  40.  
  41.     In 2025, Pascal Martinolli made some revisions to the original code.
  42.    
  43.     They are tagged #PascalMartinolli2025 along the code.
  44.    
  45.     They modify the Description of :
  46.        - encyclopedia entries (which encyclopedia),
  47.        - book sections (which book),
  48.        - thesis (which university),
  49.        - conference papers (which conference).
  50.        
  51.     They add a "default for all languages" Label.
  52.    
  53.     They manage the permanent identifiers from :
  54.        - OpenAlex: P10283
  55.        - Semantic Scholar CorpusID: P8299
  56.        - Web of Science WOS: P8372
  57.        - Microsoft Academic Graph MAG: P6366
  58.  
  59.     ***** END REVISION BLOCK *****
  60. */
  61.  
  62.  
  63. var typeMapping = {
  64.     // Zotero types
  65.     artwork: "Q838948",
  66.     // "attachment" : "Q17709279",
  67.     audioRecording: "Q30070318",
  68.     bill: "Q686822",
  69.     blogPost: "Q17928402",
  70.     book: "Q3331189", // changed from Q571 (work level) to edition level as we want to export maximal amount of properties
  71.     bookSection: "Q1980247",
  72.     case: "Q2334719",
  73.     computerProgram: "Q40056",
  74.     conferencePaper: "Q23927052",
  75.     dictionaryEntry: "Q30070414",
  76.     document: "Q49848",
  77.     email: "Q30070439",
  78.     encyclopediaArticle: "Q17329259",
  79.     film: "Q11424",
  80.     forumPost: "Q7216866",
  81.     hearing: "Q30070550",
  82.     instantMessage: "Q30070565",
  83.     interview: "Q178651",
  84.     journalArticle: "Q13442814",
  85.     letter: "Q133492",
  86.     magazineArticle: "Q30070590",
  87.     manuscript: "Q87167",
  88.     map: "Q4006",
  89.     newspaperArticle: "Q5707594",
  90.     // note
  91.     patent: "Q253623",
  92.     podcast: "Q24634210",
  93.     presentation: "Q604733",
  94.     radioBroadcast: "Q1555508",
  95.     report: "Q10870555",
  96.     statute: "Q820655",
  97.     thesis: "Q1266946",
  98.     tvBroadcast: "Q15416",
  99.     videoRecording: "Q30070675",
  100.     webpage: "Q36774",
  101.     // additional CSL types (can be used in Zotero with a hack)
  102.     dataset: "Q1172284",
  103.     // entry
  104.     figure: "Q30070753",
  105.     musical_score: "Q187947", // eslint-disable-line camelcase
  106.     pamphlet: "Q190399",
  107.     review: "Q265158",
  108.     "review-book": "Q637866",
  109.     treaty: "Q131569"
  110. };
  111.  
  112. // simple properties with string values can be simply mapped here
  113. var propertyMapping = {
  114.     P356: "DOI",
  115.     P953: "url",
  116.     P478: "volume",
  117.     P433: "issue",
  118.     P304: "pages",
  119.     P1104: "numPages",
  120.     P393: "edition"
  121. };
  122.  
  123. // properties which needs no quotes around their values (e.g. ones for numbers)
  124. var nonStringProperties = ["P1104"];
  125.  
  126. // it is important to use here the language codes in the form
  127. // as they are also used in Wikidata for monolingual text
  128. var languageMapping = {
  129.     en: "Q1860",
  130.     zh: "Q7850",
  131.     ru: "Q7737",
  132.     fr: "Q150",
  133.     ja: "Q5287",
  134.     de: "Q188",
  135.     es: "Q1321",
  136.     sr: "Q9299",
  137.     pl: "Q809",
  138.     cs: "Q9056",
  139.     it: "Q652",
  140.     cy: "Q9309",
  141.     pt: "Q5146",
  142.     nl: "Q7411",
  143.     sv: "Q9027",
  144.     ar: "Q13955",
  145.     ko: "Q9176",
  146.     hu: "Q9067",
  147.     da: "Q9035",
  148.     fi: "Q1412",
  149.     eu: "Q8752",
  150.     he: "Q9288",
  151.     la: "Q397",
  152.     nb: "Q25167",
  153.     no: "Q9043",
  154.     el: "Q9129",
  155.     tr: "Q256",
  156.     ca: "Q7026",
  157.     sl: "Q9063",
  158.     ro: "Q7913",
  159.     is: "Q294",
  160.     grc: "Q35497",
  161.     uk: "Q8798",
  162.     fa: "Q9168",
  163.     hy: "Q8785",
  164.     ta: "Q5885"
  165. };
  166.  
  167. var identifierMapping = {
  168.     PMID: "P698",
  169.     PMCID: "P932",
  170.     "JSTOR ID": "P888",
  171.     arXiv: "P818",
  172.     "Open Library ID": "P648",
  173.     OCLC: "P243",
  174.     "IMDb ID": "P345",
  175.     "Google-Books-ID": "P675",
  176.     OpenAlex: "P10283", // added by #PascalMartinolli2025
  177.     CorpusID: "P8299", // added by #PascalMartinolli2025
  178.     WOS: "P8372", // added by #PascalMartinolli2025
  179.     "MAG": "P6366" // added by #PascalMartinolli2025
  180. };
  181.  
  182.  
  183. function zoteroItemToQuickStatements(item) {
  184.     // add numPages if only page range is given
  185.     if (item.pages && !item.numPages) {
  186.         let pagesMatch = item.pages.match(/^(\d+)[–-](\d+)$/);
  187.         if (pagesMatch) {
  188.             item.numPages = parseInt(pagesMatch[2]) - parseInt(pagesMatch[1]) + 1;
  189.         }
  190.     }
  191.     // cleanup edition before to export
  192.     if (item.edition) {
  193.         item.edition = parseInt(item.edition);
  194.         if (item.edition == 1) {
  195.             delete item.edition;
  196.         }
  197.     }
  198.  
  199.     var statements = ['CREATE'];
  200.     var addStatement = function () {
  201.         var args = Array.prototype.slice.call(arguments);
  202.         statements.push('LAST\t' + args.join('\t'));
  203.     };
  204.  
  205.     var itemType = item.itemType;
  206.     // check whether a special itemType is defined in the extra fields
  207.     if (item.extra) {
  208.         var matchItemType = item.extra.match(/itemType: ([\w-]+)($|\n)/);
  209.         if (matchItemType) {
  210.             itemType = matchItemType[1];
  211.         }
  212.     }
  213.     if (typeMapping[itemType]) {
  214.         addStatement('P31', typeMapping[itemType]);
  215.     }
  216.  
  217.     var description = itemType.replace(/([A-Z])/, function (match, firstLetter) {
  218.         return ' ' + firstLetter.toLowerCase();
  219.     });
  220.     if (item.publicationTitle && (itemType == "journalArticle" || itemType == "magazineArticle" || itemType == "newspaperArticle")) {
  221.         description = description + ' from \'' + item.publicationTitle + '\'';
  222.     }
  223.     if (item. proceedingsTitle && (itemType == "conferencePaper")) {
  224.         description = description + ' from \'' + item.proceedingsTitle + '\'';
  225.     }  // added by #PascalMartinolli2025
  226.     if (item. bookTitle && (itemType == "bookSection")) {
  227.         description = description + ' from \'' + item.bookTitle + '\'';
  228.     }  // added by #PascalMartinolli2025
  229.     if (item. encyclopediaTitle && (itemType == "encyclopediaArticle")) {
  230.         description = description + ' from \'' + item.encyclopediaTitle + '\'';
  231.     }  // added by #PascalMartinolli2025
  232.     if (item.university && (itemType == "thesis")) {
  233.         description = description + ' from \'' + item.university + '\'';
  234.     }  // added by #PascalMartinolli2025
  235.     if (item.date) {
  236.         var year = ZU.strToDate(item.date).year;
  237.         if (year) {
  238.             description = description + ' published in ' + year;
  239.         }
  240.     }
  241.     addStatement('Den', '"' + description + '"');
  242.  
  243.     for (var pnumber in propertyMapping) {
  244.         var zfield = propertyMapping[pnumber];
  245.         if (item[zfield]) {
  246.             if (nonStringProperties.includes(pnumber)) {
  247.                 addStatement(pnumber, item[zfield]);
  248.             }
  249.             else {
  250.                 addStatement(pnumber, '"' + item[zfield] + '"');
  251.             }
  252.         }
  253.     }
  254.  
  255.     var index = 1;
  256.     for (var i = 0; i < item.creators.length; i++) {
  257.         var creatorValue = item.creators[i].lastName;
  258.         var creatorType = item.creators[i].creatorType;
  259.         if (item.creators[i].firstName) {
  260.             creatorValue = item.creators[i].firstName + ' ' + creatorValue;
  261.         }
  262.         if (creatorType == "author") {
  263.             addStatement('P2093', '"' + creatorValue + '"', 'P1545', '"' + index + '"');
  264.             index++;
  265.         }
  266.         // other creatorTypes are ignored, because they would need to point an item, rather than just writing the string value
  267.     }
  268.  
  269.     if (item.date) {
  270.         // e.g. +1967-01-17T00:00:00Z/11
  271.         var formatedDate = ZU.strToISO(item.date);
  272.         switch (formatedDate.length) {
  273.             case 4:
  274.                 formatedDate += "-00-00T00:00:00Z/9";
  275.                 break;
  276.             case 7:
  277.                 formatedDate += "-00T00:00:00Z/10";
  278.                 break;
  279.             case 10:
  280.                 formatedDate += "T00:00:00Z/11";
  281.                 break;
  282.             default:
  283.                 formatedDate += "/11";
  284.         }
  285.         addStatement('P577', '+' + formatedDate);
  286.     }
  287.  
  288.     // determining depending entries where the ISBN is part of the larger work
  289.     var dependingWork = ["bookSection", "conferencePaper", "dictionaryEntry", "encyclopediaArticle", "journalArticle", "magazineArticle", "newspaperArticle"].includes(itemType);
  290.     if (item.ISBN && !dependingWork) {
  291.         var isbnDigits = item.ISBN.replace(/-/g, '');
  292.         if (isbnDigits.length == 13) {
  293.             addStatement('P212', '"' + item.ISBN + '"');
  294.         }
  295.         if (isbnDigits.length == 10) {
  296.             addStatement('P957', '"' + item.ISBN + '"');
  297.         }
  298.     }
  299.  
  300.     if (item.language && (item.language.toLowerCase() in languageMapping)) {
  301.         let lang = item.language.toLowerCase();
  302.         addStatement('L' + lang, '"' + item.title + '"');
  303.         addStatement('Lmul', '"' + item.title + '"');     // added by #PascalMartinolli2025
  304.         addStatement('P1476', lang + ':"' + item.title + '"');
  305.         addStatement('P407', languageMapping[lang]);
  306.     }
  307.     else {
  308.         // otherwise use "und" for undetermined language and add the label in english by default
  309.         addStatement('Len', '"' + item.title + '"');
  310.         addStatement('P1476', 'und:"' + item.title + '"');
  311.     }
  312.  
  313.     if (item.extra) {
  314.         var extraLines = item.extra.split('\n');
  315.         for (var j = 0; j < extraLines.length; j++) {
  316.             var colon = extraLines[j].indexOf(':');
  317.             if (colon > -1) {
  318.                 var label = extraLines[j].substr(0, colon);
  319.                 var value = extraLines[j].substr(colon + 1);
  320.                 if (identifierMapping[label]) {
  321.                     addStatement(identifierMapping[label], '"' + value.trim() + '"');
  322.                 }
  323.                 if (label.match(/^P\d+$/)) {
  324.                     if (value.trim().match(/^Q\d+$/)) {
  325.                         addStatement(label, value.trim());
  326.                     }
  327.                     else {
  328.                         addStatement(label, '"' + value.trim() + '"');
  329.                     }
  330.                 }
  331.             }
  332.         }
  333.     }
  334.  
  335.     return statements.join('\n') + '\n';
  336. }
  337.  
  338. function doExport() {
  339.     var item;
  340.     while ((item = Zotero.nextItem())) {
  341.         // skipping items with a QID saved in extra
  342.         if (item.extra && item.extra.match(/^QID: /m)) continue;
  343.  
  344.         // write the statements
  345.         Zotero.write(zoteroItemToQuickStatements(item));
  346.     }
  347. }
  348.  
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement