Permalink
Join GitHub today
GitHub is home to over 31 million developers working together to host and review code, manage projects, and build software together.
Sign up
translators/WorldCat Discovery Service.js
Find file
Copy path
Fetching contributors…
Cannot retrieve contributors at this time
{ | |
"translatorID": "fd8dc5f6-a6dd-42b2-948f-600f5da844ea", | |
"label": "WorldCat Discovery Service", | |
"creator": "Sebastian Karcher", | |
"target": "^https?://[^/]+\\.worldcat\\.org/", | |
"minVersion": "3.0.9", | |
"maxVersion": "", | |
"priority": 100, | |
"inRepository": true, | |
"translatorType": 4, | |
"browserSupport": "gcsbv", | |
"lastUpdated": "2017-06-25 19:26:46" | |
} | |
/* | |
***** BEGIN LICENSE BLOCK ***** | |
WorldCat Discovery Service translator; Copyright © 2015 Sebastian Karcher | |
This file is part of Zotero. | |
Zotero is free software: you can redistribute it and/or modify | |
it under the terms of the GNU Affero General Public License as published by | |
the Free Software Foundation, either version 3 of the License, or | |
(at your option) any later version. | |
Zotero is distributed in the hope that it will be useful, | |
but WITHOUT ANY WARRANTY; without even the implied warranty of | |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
GNU Affero General Public License for more details. | |
You should have received a copy of the GNU Affero General Public License | |
along with Zotero. If not, see <http://www.gnu.org/licenses/>. | |
***** END LICENSE BLOCK ***** | |
*/ | |
function detectWeb(doc, url) { | |
var results = getSearchResults(doc); | |
if (results.length) { | |
return "multiple"; | |
} | |
//single result | |
// generate item and return type | |
var co = getFirstContextObj(doc); | |
if (!co || url.indexOf("?databaseList") == -1) return false; | |
return generateItem(doc, co).itemType; | |
} | |
/** | |
* Gets Zotero item from a WorldCat icon src | |
*/ | |
function getZoteroType(iconSrc) { | |
// only specify types not specified in COinS | |
if (iconSrc.indexOf("icon-rec") != -1) { | |
return "audioRecording"; | |
} | |
if (iconSrc.indexOf("icon-com") != -1) { | |
return "computerProgram"; | |
} | |
if (iconSrc.indexOf("icon-map") != -1) { | |
return "map"; | |
} | |
return false; | |
} | |
/** | |
* Generates a Zotero item from a single item WorldCat page, | |
* or the first item on a multiple item page | |
*/ | |
function generateItem(doc, co) { | |
var item = new Zotero.Item(); | |
ZU.parseContextObject(co, item); | |
// item types not covered by COinS will still need to be covered. Leaving the corresponding code from open Worldcat | |
// here as a reminder. | |
/* | |
var type = ZU.xpathText(doc, | |
'//img[@class="icn"][contains(@src, "icon-")][1]/@src'); | |
if (type) { | |
type = getZoteroType(type); | |
if (type) item.itemType = type; | |
} */ | |
return item; | |
} | |
function getSearchResults(doc) { | |
var results = ZU.xpath(doc, '//ol[@class="results"]/li[contains(@id, "record")]') | |
return results; | |
} | |
function getTitleNode(searchResult) { | |
return ZU.xpath(searchResult, './div[@class="title"]/a')[0]; | |
} | |
function getFirstContextObj(doc) { | |
return ZU.xpathText(doc, '//span[contains(@class, "Z3988")][1]/@title'); | |
} | |
/** | |
* Given an item URL, extract OCLC ID | |
*/ | |
function extractOCLCID(url) { | |
var id = url.match(/\/oclc\/([^?]+)/); | |
if (!id) return false; | |
return id[1]; | |
} | |
/** | |
* Given an item URL, extract database ID | |
*/ | |
function extractDatabaseID(url) { | |
var id = url.match(/databaseList=([^&#]+)/); | |
if (!id) return false; | |
return decodeURIComponent(id[1]); | |
} | |
function composeURL(oclcID, databaseID) { | |
var risURL = "/share/citation.ris?oclcNumber=" + oclcID + "&databaseIds=" + encodeURIComponent(databaseID); | |
return risURL; | |
} | |
/** | |
* RIS Scraper Function | |
* | |
*/ | |
function scrape(risURL) { | |
ZU.doGet(risURL, function(text) { | |
//Z.debug(text); | |
//conference proceedings exported as CONF, but fields match BOOK better | |
text = text.replace(/TY\s+-\s+CONF\s+[\s\S]+?\n\s*ER\s+-/g, function(m) { | |
return m.replace(/^TY\s+-\s+CONF\s*$/mg, 'TY - BOOK') | |
//authors are actually editors | |
.replace(/^A1\s+-\s+/mg, 'A3 - '); | |
}) | |
//Zotero.debug("Importing corrected RIS: \n" + text); | |
var translator = Zotero.loadTranslator("import"); | |
translator.setTranslator("32d59d2d-b65a-4da4-b0a3-bdd3cfb979e7"); | |
translator.setString(text); | |
translator.setHandler("itemDone", function(obj, item) { | |
item.extra = undefined; | |
item.archive = undefined; | |
//clean up ISBNs | |
if (item.ISBN) { | |
var ISBN = item.ISBN.split(/\s/); | |
var ISBNarray = []; | |
for (var i = 0; i < ISBN.length; i++) { | |
if (ZU.cleanISBN(ISBN[i])) { | |
ISBNarray.push(ZU.cleanISBN(ISBN[i])); | |
} | |
} | |
item.ISBN = ISBNarray.join(" "); | |
} | |
//remove space before colon | |
item.title = item.title.replace(/\s+:/, ":") | |
//remove trailing colon after place | |
if (item.place) { | |
item.place = item.place.replace(/:\s*$/, ""); | |
} | |
//remove traling period after publication | |
if (item.publicationTitle) { | |
item.publicationTitle = item.publicationTitle.replace(/\.\s*$/, ""); | |
} | |
//remove trailing commar after publisher | |
if (item.publisher) { | |
item.publisher = item.publisher.replace(/,\s*$/, ""); | |
} | |
//correct field mode for corporate authors | |
for (var i = 0; i < item.creators.length; i++) { | |
if (!item.creators[i].firstName) { | |
item.creators[i].fieldMode = 1; | |
} | |
} | |
//number of pages gets mapped to section??? | |
if (item.section) { | |
//extract possible roman numerals and number of pages without the p | |
var numPages = item.section.match(/(([lxiv]+,\s*)?\d+)\s*p/); | |
if (numPages) item.numPages = numPages[1]; | |
} | |
//the url field sometimes contains an additional label, e.g. for TOC | |
//"url": "Table of contents http://bvbr.bib-bvb.de:8991/... | |
if (item.url) { | |
var posUrl = item.url.indexOf('http'); | |
if (posUrl>0) { | |
item.attachments.push({ | |
url: item.url.substr(posUrl), | |
title: item.url.substr(0, posUrl), | |
snapshot: false | |
}); | |
delete item.url; | |
} | |
} | |
item.complete(); | |
}); | |
translator.getTranslatorObject(function(trans) { | |
trans.options.defaultItemType = 'book'; //if not supplied, default to book | |
trans.options.typeMap = { | |
'ELEC': 'book' | |
}; //ebooks should be imported as books | |
trans.doImport(); | |
}); | |
}); | |
} | |
function doWeb(doc, url) { | |
var results = getSearchResults(doc); | |
if (detectWeb(doc, url) == "multiple") { | |
var items = {}; | |
var articles = []; | |
for (var i = 0, n = results.length; i < n; i++) { | |
var title = ZU.xpathText(results[i], './/div[contains(@class, "title") and a[@class="record-title"]]'); | |
//Z.debug(title) | |
if (!title) continue; | |
var oclcID = ZU.xpathText(results[i], './@data-oclcnum'); | |
//Z.debug(oclcID) | |
var databaseID = ZU.xpathText(results[i], './@data-database-list'); | |
//Z.debug(databaseID) | |
var risURL = composeURL(oclcID, databaseID); | |
Z.debug(risURL) | |
items[risURL] = title.trim(); | |
} | |
Zotero.selectItems(items, function(items) { | |
if (!items) return true; | |
for (var i in items) { | |
articles.push(i); | |
} | |
scrape(articles); | |
}); | |
} else { | |
var oclcID = extractOCLCID(url); | |
var databaseID = extractDatabaseID(url); | |
if (!oclcID) throw new Error("WorldCat: Failed to extract OCLC ID from URL: " + url); | |
var risURL = composeURL(oclcID, databaseID); | |
Z.debug("risURL= " + risURL) | |
scrape(risURL); | |
} | |
} | |
/** BEGIN TEST CASES **/ | |
var testCases = [ | |
{ | |
"type": "web", | |
"url": "https://sbts.on.worldcat.org/oclc/795005226?databaseList=239,283,638", | |
"items": [ | |
{ | |
"itemType": "journalArticle", | |
"title": "Steven E. Runge. Discourse Grammar of the Greek New Testament", | |
"creators": [ | |
{ | |
"lastName": "Long", | |
"firstName": "C.", | |
"creatorType": "author" | |
} | |
], | |
"date": "2012", | |
"ISSN": "0360-3032", | |
"issue": "1", | |
"libraryCatalog": "WorldCat Discovery Service", | |
"pages": "129-132", | |
"publicationTitle": "Trinity journal", | |
"volume": "33", | |
"attachments": [], | |
"tags": [], | |
"notes": [], | |
"seeAlso": [] | |
} | |
] | |
}, | |
{ | |
"type": "web", | |
"url": "http://lpts.on.worldcat.org/search?queryString=au:Mary%20GrandPre%CC%81&databaseList=638", | |
"items": "multiple" | |
}, | |
{ | |
"type": "web", | |
"url": "http://sbts.on.worldcat.org/search?databaseList=&queryString=runge+discourse+grammar", | |
"items": "multiple" | |
}, | |
{ | |
"type": "web", | |
"url": "https://sbts.on.worldcat.org/oclc/667874424?databaseList=239,283,638", | |
"items": [ | |
{ | |
"itemType": "book", | |
"title": "Discourse grammar of the Greek New Testament: a practical introduction for teaching and exegesis", | |
"creators": [ | |
{ | |
"lastName": "Runge", | |
"firstName": "Steven E.", | |
"creatorType": "author" | |
} | |
], | |
"date": "2010", | |
"ISBN": "9781598565836", | |
"language": "English", | |
"libraryCatalog": "WorldCat Discovery Service", | |
"numPages": "xx, 404", | |
"place": "Peabody, Mass.", | |
"publisher": "Hendrickson Publishers Marketing", | |
"series": "Lexham Bible reference series; Lexham Bible reference series.", | |
"shortTitle": "Discourse grammar of the Greek New Testament", | |
"attachments": [ | |
{ | |
"title": "Table of contents ", | |
"snapshot": false | |
} | |
], | |
"tags": [], | |
"notes": [], | |
"seeAlso": [] | |
} | |
] | |
} | |
] | |
/** END TEST CASES **/ |