af36412a11
Mapping both import and export. The spec doesn't actually give any indication that ED is for editors (and, given that AB isn't actually abstract, you can't really make assumptions when it comes to RIS), but other apps seem to put editors in ED A forum user suggested that mixing and matching A1/A2 and ED caused creator data to be skipped altogether on import to EndNote. I haven't checked this, but I'm adding editor export to ED on the grounds that more data is better than less, and users can update other import filters if necessary.
527 lines
No EOL
13 KiB
JavaScript
527 lines
No EOL
13 KiB
JavaScript
{
|
|
"translatorID":"32d59d2d-b65a-4da4-b0a3-bdd3cfb979e7",
|
|
"translatorType":3,
|
|
"label":"RIS",
|
|
"creator":"Simon Kornblith",
|
|
"target":"ris",
|
|
"minVersion":"1.0.2",
|
|
"maxVersion":"",
|
|
"priority":100,
|
|
"inRepository":true,
|
|
"lastUpdated":"2010-02-04 02:24:27"
|
|
}
|
|
|
|
Zotero.configure("dataMode", "line");
|
|
Zotero.addOption("exportNotes", true);
|
|
Zotero.addOption("exportCharset", "UTF-8");
|
|
|
|
function detectImport() {
|
|
var line;
|
|
var i = 0;
|
|
while((line = Zotero.read()) !== false) {
|
|
line = line.replace(/^\s+/, "");
|
|
if(line != "") {
|
|
if(line.substr(0, 6).match(/^TY {1,2}- /)) {
|
|
return true;
|
|
} else {
|
|
if(i++ > 3) {
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
var fieldMap = {
|
|
ID:"itemID",
|
|
T1:"title",
|
|
T3:"series",
|
|
JF:"publicationTitle",
|
|
CY:"place",
|
|
JA:"journalAbbreviation",
|
|
M3:"DOI"
|
|
};
|
|
|
|
var inputFieldMap = {
|
|
TI:"title",
|
|
CT:"title",
|
|
CY:"place"
|
|
};
|
|
|
|
// TODO: figure out if these are the best types for letter, interview, webpage
|
|
var typeMap = {
|
|
book:"BOOK",
|
|
bookSection:"CHAP",
|
|
journalArticle:"JOUR",
|
|
magazineArticle:"MGZN",
|
|
newspaperArticle:"NEWS",
|
|
thesis:"THES",
|
|
letter:"PCOMM",
|
|
manuscript:"PAMP",
|
|
interview:"PCOMM",
|
|
film:"MPCT",
|
|
artwork:"ART",
|
|
report:"RPRT",
|
|
bill:"BILL",
|
|
case:"CASE",
|
|
hearing:"HEAR",
|
|
patent:"PAT",
|
|
statute:"STAT",
|
|
map:"MAP",
|
|
blogPost:"ELEC",
|
|
webpage:"ELEC",
|
|
instantMessage:"ICOMM",
|
|
forumPost:"ICOMM",
|
|
email:"ICOMM",
|
|
audioRecording:"SOUND",
|
|
presentation:"GEN",
|
|
videoRecording:"VIDEO",
|
|
tvBroadcast:"GEN",
|
|
radioBroadcast:"GEN",
|
|
podcast:"GEN",
|
|
computerProgram:"COMP",
|
|
conferencePaper:"CONF",
|
|
document:"GEN"
|
|
};
|
|
|
|
// supplements outputTypeMap for importing
|
|
// TODO: DATA, MUSIC
|
|
var inputTypeMap = {
|
|
ABST:"journalArticle",
|
|
ADVS:"film",
|
|
CTLG:"magazineArticle",
|
|
INPR:"manuscript",
|
|
JFULL:"journalArticle",
|
|
PAMP:"manuscript",
|
|
SER:"book",
|
|
SLIDE:"artwork",
|
|
UNBILL:"manuscript"
|
|
};
|
|
|
|
function processTag(item, tag, value) {
|
|
if (Zotero.Utilities.unescapeHTML) {
|
|
value = Zotero.Utilities.unescapeHTML(value.replace("\n", "<br>", "g"));
|
|
}
|
|
|
|
if(fieldMap[tag]) {
|
|
item[fieldMap[tag]] = value;
|
|
} else if(inputFieldMap[tag]) {
|
|
item[inputFieldMap[tag]] = value;
|
|
} else if(tag == "TY") {
|
|
// look for type
|
|
|
|
// first check typeMap
|
|
for(var i in typeMap) {
|
|
if(value == typeMap[i]) {
|
|
item.itemType = i;
|
|
}
|
|
}
|
|
// then check inputTypeMap
|
|
if(!item.itemType) {
|
|
if(inputTypeMap[value]) {
|
|
item.itemType = inputTypeMap[value];
|
|
} else {
|
|
// default to generic from inputTypeMap
|
|
item.itemType = inputTypeMap["GEN"];
|
|
}
|
|
}
|
|
} else if(tag == "JO") {
|
|
if (item.itemType == "conferencePaper"){
|
|
item.conferenceName = value;
|
|
} else {
|
|
item.publicationTitle = value;
|
|
}
|
|
} else if(tag == "BT") {
|
|
// ignore, unless this is a book or unpublished work, as per spec
|
|
if(item.itemType == "book" || item.itemType == "manuscript") {
|
|
item.title = value;
|
|
} else {
|
|
item.backupPublicationTitle = value;
|
|
}
|
|
} else if(tag == "T2") {
|
|
item.backupPublicationTitle = value;
|
|
} else if(tag == "A1" || tag == "AU") {
|
|
// primary author (patent: inventor)
|
|
// store Zotero "creator type" in temporary variable
|
|
var tempType;
|
|
if (item.itemType == "patent") {
|
|
tempType = "inventor";
|
|
} else {
|
|
tempType = "author";
|
|
}
|
|
var names = value.split(/, ?/);
|
|
item.creators.push({lastName:names[0], firstName:names[1], creatorType:tempType});
|
|
} else if(tag == "ED") {
|
|
var names = value.split(/, ?/);
|
|
item.creators.push({lastName:names[0], firstName:names[1], creatorType:"editor"});
|
|
} else if(tag == "A2") {
|
|
// contributing author (patent: assignee)
|
|
if (item.itemType == "patent") {
|
|
if (item.assignee) {
|
|
// Patents can have multiple assignees (applicants) but Zotero only allows a single
|
|
// assignee field, so we have to concatenate them together
|
|
item.assignee += ", "+value;
|
|
} else {
|
|
item.assignee = value;
|
|
}
|
|
} else {
|
|
var names = value.split(/, ?/);
|
|
item.creators.push({lastName:names[0], firstName:names[1], creatorType:"contributor"});
|
|
}
|
|
} else if(tag == "Y1" || tag == "PY") {
|
|
// year or date
|
|
var dateParts = value.split("/");
|
|
|
|
if(dateParts.length == 1) {
|
|
// technically, if there's only one date part, the file isn't valid
|
|
// RIS, but EndNote writes this, so we have to too
|
|
// Nick: RIS spec example records also only contain a single part
|
|
// even though it says the slashes are not optional (?)
|
|
item.date = value;
|
|
} else {
|
|
// in the case that we have a year and other data, format that way
|
|
|
|
var month = parseInt(dateParts[1]);
|
|
if(month) {
|
|
month--;
|
|
} else {
|
|
month = undefined;
|
|
}
|
|
|
|
item.date = Zotero.Utilities.formatDate({year:dateParts[0],
|
|
month:month,
|
|
day:dateParts[2],
|
|
part:dateParts[3]});
|
|
}
|
|
} else if(tag == "Y2") {
|
|
// the secondary date field can mean two things, a secondary date, or an
|
|
// invalid EndNote-style date. let's see which one this is.
|
|
// patent: application (filing) date -- do not append to date field
|
|
// for now. Zotero needs a filing date field added to make use of this.
|
|
var dateParts = value.split("/");
|
|
if(dateParts.length != 4 && item.itemType != "patent") {
|
|
// an invalid date and not a patent.
|
|
// It's from EndNote or Delphion (YYYY-MM-DD)
|
|
if(item.date && value.indexOf(item.date) == -1) {
|
|
// append existing year
|
|
value += " " + item.date;
|
|
}
|
|
item.date = value;
|
|
}
|
|
// ToDo: Handle correctly formatted Y2 fields (secondary date)
|
|
} else if(tag == "N1" || tag == "AB") {
|
|
// notes
|
|
if(value != item.title) { // why does EndNote do this!?
|
|
item.notes.push({note:value});
|
|
}
|
|
} else if(tag == "N2") {
|
|
// abstract
|
|
item.abstractNote = value;
|
|
} else if(tag == "KW") {
|
|
// keywords/tags
|
|
|
|
// technically, treating newlines as new tags breaks the RIS spec, but
|
|
// it's required to work with EndNote
|
|
item.tags = item.tags.concat(value.split("\n"));
|
|
} else if(tag == "SP") {
|
|
// start page
|
|
if(!item.pages) {
|
|
item.pages = value;
|
|
} else if(item.pages[0] == "-") { // already have ending page
|
|
item.pages = value + item.pages;
|
|
} else { // multiple ranges? hey, it's a possibility
|
|
item.pages += ", "+value;
|
|
}
|
|
} else if(tag == "EP") {
|
|
// end page
|
|
if(value) {
|
|
if(!item.pages) {
|
|
item.pages = value;
|
|
} else if(value != item.pages) {
|
|
item.pages += "-"+value;
|
|
}
|
|
}
|
|
} else if(tag == "SN") {
|
|
// ISSN/ISBN - just add both
|
|
if(!item.ISBN) {
|
|
item.ISBN = value;
|
|
}
|
|
if(!item.ISSN) {
|
|
item.ISSN = value;
|
|
}
|
|
} else if(tag == "UR" || tag == "L1" || tag == "L2" || tag == "L4") {
|
|
// URL
|
|
if(!item.url) {
|
|
item.url = value;
|
|
}
|
|
if(tag == "UR") {
|
|
item.attachments.push({url:value});
|
|
} else if(tag == "L1") {
|
|
item.attachments.push({url:value, mimeType:"application/pdf",
|
|
title:"Full Text (PDF)", downloadable:true});
|
|
} else if(tag == "L2") {
|
|
item.attachments.push({url:value, mimeType:"text/html",
|
|
title:"Full Text (HTML)", downloadable:true});
|
|
} else if(tag == "L4") {
|
|
item.attachments.push({url:value,
|
|
title:"Image", downloadable:true});
|
|
}
|
|
} else if (tag == "IS") {
|
|
// Issue Number (patent: patentNumber)
|
|
if (item.itemType == "patent") {
|
|
item.patentNumber = value;
|
|
} else {
|
|
item.issue = value;
|
|
}
|
|
} else if (tag == "VL") {
|
|
// Volume Number (patent: applicationNumber)
|
|
if (item.itemType == "patent") {
|
|
item.applicationNumber = value;
|
|
} else {
|
|
item.volume = value;
|
|
}
|
|
} else if (tag == "PB") {
|
|
// publisher (patent: references)
|
|
if (item.itemType == "patent") {
|
|
item.references = value;
|
|
} else {
|
|
item.publisher = value;
|
|
}
|
|
} else if (tag == "M1" || tag == "M2") {
|
|
// Miscellaneous fields
|
|
if (!item.extra) {
|
|
item.extra = value;
|
|
} else {
|
|
item.extra += "; "+value;
|
|
}
|
|
}
|
|
}
|
|
|
|
function completeItem(item) {
|
|
// if backup publication title exists but not proper, use backup
|
|
// (hack to get newspaper titles from EndNote)
|
|
if(item.backupPublicationTitle) {
|
|
if(!item.publicationTitle) {
|
|
item.publicationTitle = item.backupPublicationTitle;
|
|
}
|
|
item.backupPublicationTitle = undefined;
|
|
}
|
|
// hack for sites like Nature, which only use JA, journal abbreviation
|
|
if(item.journalAbbreviation && !item.publicationTitle){
|
|
item.publicationTitle = item.journalAbbreviation;
|
|
}
|
|
item.complete();
|
|
}
|
|
|
|
function doImport(attachments) {
|
|
var line = true;
|
|
var tag = data = false;
|
|
do { // first valid line is type
|
|
line = Zotero.read();
|
|
line = line.replace(/^\s+/, "");
|
|
} while(line !== false && !line.substr(0, 6).match(/^TY {1,2}- /));
|
|
|
|
var item = new Zotero.Item();
|
|
var i = 0;
|
|
if(attachments && attachments[i]) {
|
|
item.attachments = attachments[i];
|
|
}
|
|
|
|
var tag = "TY";
|
|
|
|
// Handle out-of-spec old EndNote exports
|
|
if (line.substr(0, 5) == "TY - ") {
|
|
var data = line.substr(5);
|
|
}
|
|
else {
|
|
var data = line.substr(6);
|
|
}
|
|
|
|
var rawLine;
|
|
while((rawLine = Zotero.read()) !== false) { // until EOF
|
|
// trim leading space if this line is not part of a note
|
|
line = rawLine.replace(/^\s+/, "");
|
|
if(line.substr(2, 4) == " - " || line == "ER -" || line.substr(0, 5) == "TY - ") {
|
|
// if this line is a tag, take a look at the previous line to map
|
|
// its tag
|
|
if(tag) {
|
|
Zotero.debug("tag: '"+tag+"'; data: '"+data+"'");
|
|
processTag(item, tag, data);
|
|
}
|
|
|
|
// then fetch the tag and data from this line
|
|
tag = line.substr(0,2);
|
|
|
|
// Handle out-of-spec old EndNote exports
|
|
if (line.substr(0, 5) == "TY - ") {
|
|
data = line.substr(5);
|
|
}
|
|
else {
|
|
data = line.substr(6);
|
|
}
|
|
|
|
if(tag == "ER") { // ER signals end of reference
|
|
// unset info
|
|
tag = data = false;
|
|
// new item
|
|
completeItem(item);
|
|
item = new Zotero.Item();
|
|
i++;
|
|
if(attachments && attachments[i]) {
|
|
item.attachments = attachments[i];
|
|
}
|
|
}
|
|
} else {
|
|
// otherwise, assume this is data from the previous line continued
|
|
if(tag == "N1" || tag == "N2" || tag == "AB" || tag == "KW") {
|
|
// preserve line endings for N1/N2/AB fields, for EndNote
|
|
// compatibility
|
|
data += "\n"+rawLine;
|
|
} else if(tag) {
|
|
// otherwise, follow the RIS spec
|
|
if(data[data.length-1] == " ") {
|
|
data += rawLine;
|
|
} else {
|
|
data += " "+rawLine;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if(tag && tag != "ER") { // save any unprocessed tags
|
|
Zotero.debug(tag);
|
|
processTag(item, tag, data);
|
|
completeItem(item);
|
|
}
|
|
}
|
|
|
|
function addTag(tag, value) {
|
|
if(value) {
|
|
Zotero.write(tag+" - "+value+"\r\n");
|
|
}
|
|
}
|
|
|
|
function doExport() {
|
|
var item;
|
|
|
|
while(item = Zotero.nextItem()) {
|
|
// can't store independent notes in RIS
|
|
if(item.itemType == "note" || item.itemType == "attachment") {
|
|
continue;
|
|
}
|
|
|
|
// type
|
|
addTag("TY", typeMap[item.itemType] ? typeMap[item.itemType] : "GEN");
|
|
|
|
// use field map
|
|
for(var j in fieldMap) {
|
|
if(item[fieldMap[j]]) addTag(j, item[fieldMap[j]]);
|
|
}
|
|
|
|
// creators
|
|
for(var j in item.creators) {
|
|
// only two types, primary and secondary
|
|
var risTag;
|
|
// authors and inventors are primary creators
|
|
if (item.creators[j].creatorType == "author" || item.creators[j].creatorType == "inventor") {
|
|
risTag = "A1";
|
|
} else if (item.creators[j].creatorType == "editor") {
|
|
risTag = "ED";
|
|
} else {
|
|
risTag = "A2";
|
|
}
|
|
|
|
addTag(risTag, item.creators[j].lastName+","+item.creators[j].firstName);
|
|
}
|
|
|
|
// assignee (patent)
|
|
if(item.assignee) {
|
|
addTag("A2", item.assignee);
|
|
}
|
|
|
|
// volume (patent: applicationNumber)
|
|
if(item.volume || item.applicationNumber) {
|
|
var value = (item.volume) ? item.volume : item.applicationNumber;
|
|
addTag("VL", value);
|
|
}
|
|
|
|
// issue (patent: patentNumber)
|
|
if(item.issue || item.patentNumber) {
|
|
var value = (item.issue) ? item.issue : item.patentNumber;
|
|
addTag("IS", value);
|
|
}
|
|
|
|
// publisher (patent: references)
|
|
if(item.publisher || item.references) {
|
|
var value = (item.publisher) ? item.publisher : item.references;
|
|
addTag("PB", value);
|
|
}
|
|
|
|
|
|
// date
|
|
if(item.date) {
|
|
var date = Zotero.Utilities.strToDate(item.date);
|
|
var string = date.year+"/";
|
|
if(date.month != undefined) {
|
|
// deal with javascript months
|
|
date.month++;
|
|
if(date.month < 10) string += "0";
|
|
string += date.month;
|
|
}
|
|
string += "/";
|
|
if(date.day != undefined) {
|
|
if(date.day < 10) string += "0";
|
|
string += date.day;
|
|
}
|
|
string += "/";
|
|
if(date.part != undefined) {
|
|
string += date.part;
|
|
}
|
|
addTag("PY", string);
|
|
}
|
|
|
|
// notes
|
|
if(Zotero.getOption("exportNotes")) {
|
|
for(var j in item.notes) {
|
|
addTag("N1", item.notes[j].note.replace(/(?:\r\n?|\n)/g, "\r\n"));
|
|
}
|
|
}
|
|
|
|
if(item.abstractNote) {
|
|
addTag("N2", item.abstractNote.replace(/(?:\r\n?|\n)/g, "\r\n"));
|
|
}
|
|
else if(item.abstract) {
|
|
// patent type has abstract
|
|
addTag("N2", item.abstract.replace(/(?:\r\n?|\n)/g, "\r\n"));
|
|
}
|
|
|
|
// tags
|
|
for each(var tag in item.tags) {
|
|
addTag("KW", tag.tag);
|
|
}
|
|
|
|
// pages
|
|
if(item.pages) {
|
|
if(item.itemType == "book") {
|
|
addTag("EP", item.pages);
|
|
} else {
|
|
var range = Zotero.Utilities.getPageRange(item.pages);
|
|
addTag("SP", range[0]);
|
|
addTag("EP", range[1]);
|
|
}
|
|
}
|
|
|
|
// ISBN/ISSN
|
|
addTag("SN", item.ISBN);
|
|
addTag("SN", item.ISSN);
|
|
|
|
// URL
|
|
if(item.url) {
|
|
addTag("UR", item.url);
|
|
} else if(item.source && item.source.substr(0, 7) == "http://") {
|
|
addTag("UR", item.source);
|
|
}
|
|
|
|
Zotero.write("ER - \r\n\r\n");
|
|
}
|
|
} |