draft Bibliontology translator
This commit is contained in:
parent
665e1ec826
commit
1d4c2715f1
1 changed files with 994 additions and 0 deletions
994
translators/Bibliontology RDF.js
Normal file
994
translators/Bibliontology RDF.js
Normal file
|
@ -0,0 +1,994 @@
|
||||||
|
{
|
||||||
|
"translatorID":"14763d25-8ba0-45df-8f52-b8d1108e7ac9",
|
||||||
|
"translatorType":3,
|
||||||
|
"label":"Bibliontology RDF",
|
||||||
|
"creator":"Simon Kornblith",
|
||||||
|
"target":"rdf",
|
||||||
|
"minVersion":"2.0",
|
||||||
|
"maxVersion":"",
|
||||||
|
"priority":200,
|
||||||
|
"inRepository":true,
|
||||||
|
"lastUpdated":"2009-06-29 22:16:41"
|
||||||
|
}
|
||||||
|
|
||||||
|
Zotero.configure("getCollections", true);
|
||||||
|
Zotero.configure("dataMode", "rdf");
|
||||||
|
Zotero.addOption("exportNotes", true);
|
||||||
|
Zotero.addOption("exportFileData", false);
|
||||||
|
|
||||||
|
var n = {
|
||||||
|
address:"http://schemas.talis.com/2005/address/schema#", // could also use vcard?
|
||||||
|
bibo:"http://purl.org/ontology/biblio/",
|
||||||
|
dcterms:"http://purl.org/dc/terms/",
|
||||||
|
doap:"http://usefulinc.com/ns/doap#",
|
||||||
|
foaf:"http://xmlns.com/foaf/0.1/",
|
||||||
|
link:"http://purl.org/rss/1.0/modules/link/",
|
||||||
|
po:"http://purl.org/ontology/po/",
|
||||||
|
rdf:"http://www.w3.org/1999/02/22-rdf-syntax-ns#",
|
||||||
|
rel:"http://www.loc.gov/loc.terms/relators/",
|
||||||
|
res:"http://purl.org/vocab/resourcelist/schema#",
|
||||||
|
sc:"http://umbel.org/umbel/sc/",
|
||||||
|
sioct:"http://rdfs.org/sioc/types#",
|
||||||
|
z:"http://www.zotero.org/namespaces/export#"
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
Types should be in the form
|
||||||
|
|
||||||
|
<ZOTERO_TYPE>: [<ITEM_CLASS>, <SUBCONTAINER_CLASS>, <CONTAINER_CLASS>]
|
||||||
|
|
||||||
|
Item classes should be in the form
|
||||||
|
|
||||||
|
[[<PREDICATE>, <OBJECT>]+]
|
||||||
|
|
||||||
|
This generates the triples
|
||||||
|
|
||||||
|
(ITEM <PREDICATE> <OBJECT>)+
|
||||||
|
|
||||||
|
Subcontainer and container classes should be in the form
|
||||||
|
|
||||||
|
[<ALWAYS_INCLUDE>, <ITEM_PREDICATE>, [<CONTAINER_PREDICATE>, <CONTAINER_OBJECT>]*] | null
|
||||||
|
|
||||||
|
If there is a property to be applied to the container, or if <ALWAYS_INCLUDE> is true, then this
|
||||||
|
generates
|
||||||
|
|
||||||
|
ITEM <ITEM_PREDICATE> CONTAINER
|
||||||
|
(CONTAINER <CONTAINER_PREDICATE> <CONTAINER_OBJECT>)*
|
||||||
|
**/
|
||||||
|
|
||||||
|
// ZOTERO TYPE ITEM CLASS SUBCONTAINER CLASS CONTAINER CLASS
|
||||||
|
var TYPES = {
|
||||||
|
"artwork": [[[n.rdf+"type", n.bibo+"Image"]], null, null],
|
||||||
|
"attachment": [[[n.rdf+"type", n.z+"Attachment"]], null, null],
|
||||||
|
"audioRecording": [[[n.rdf+"type", n.bibo+"AudioDocument"]], null, null],
|
||||||
|
"bill": [[[n.rdf+"type", n.bibo+"Bill"]], null, [false, n.dcterms+"isPartOf", [[n.rdf+"type", n.bibo+"Code"]]]],
|
||||||
|
"blogPost": [[[n.rdf+"type", n.sioct+"BlogPost"],
|
||||||
|
[n.rdf+"type", n.bibo+"Article"]], null, [false, n.dcterms+"isPartOf", [[n.rdf+"type", n.sioct+"Weblog"],
|
||||||
|
[n.rdf+"type", n.bibo+"Website"]]]],
|
||||||
|
"book": [[[n.rdf+"type", n.bibo+"Book"]], null, null],
|
||||||
|
"bookSection": [[[n.rdf+"type", n.bibo+"BookSection"]], null, [false, n.dcterms+"isPartOf", [[n.rdf+"type", n.bibo+"EditedBook"]]]],
|
||||||
|
"case": [[[n.rdf+"type", n.bibo+"LegalCaseDocument"]], null, [false, n.dcterms+"isPartOf", [[n.rdf+"type", n.bibo+"CourtReporter"]]]],
|
||||||
|
"computerProgram": [[[n.rdf+"type", n.sc+"ComputerProgram_CW"],
|
||||||
|
[n.rdf+"type", n.bibo+"Document"]], null, null],
|
||||||
|
"conferencePaper": [[[n.rdf+"type", n.bibo+"Article"]], null, [true, n.dcterms+"isPartOf", [[n.rdf+"type", n.bibo+"Proceedings"]]]],
|
||||||
|
"dictionaryEntry": [[[n.rdf+"type", n.bibo+"Article"]], null, [true, n.dcterms+"isPartOf", [[n.rdf+"type", n.sc+"Dictionary"],
|
||||||
|
[n.rdf+"type", n.bibo+"ReferenceSource"]]]],
|
||||||
|
"document": [[[n.rdf+"type", n.bibo+"Document"]], null, null],
|
||||||
|
"email": [[[n.rdf+"type", n.bibo+"Email"]], null, null],
|
||||||
|
"encyclopediaArticle": [[[n.rdf+"type", n.bibo+"Article"]], null, [true, n.dcterms+"isPartOf", [[n.rdf+"type", n.sc+"Encyclopedia"],
|
||||||
|
[n.rdf+"type", n.bibo+"ReferenceSource"]]]],
|
||||||
|
"forumPost": [[[n.rdf+"type", n.sioct+"BoardPost"],
|
||||||
|
[n.rdf+"type", n.bibo+"Article"]], null, [false, n.dcterms+"isPartOf", [[n.rdf+"type", n.sioct+"MessageBoard"],
|
||||||
|
[n.rdf+"type", n.bibo+"Website"]]]],
|
||||||
|
"film": [[[n.rdf+"type", n.bibo+"Film"]], null, null],
|
||||||
|
"hearing": [[[n.rdf+"type", n.bibo+"Hearing"]], null, null],
|
||||||
|
"instantMessage": [[[n.rdf+"type", n.sioct+"InstantMessage"],
|
||||||
|
[n.rdf+"type", n.bibo+"PersonalCommunication"]], null, null],
|
||||||
|
"interview": [[[n.rdf+"type", n.bibo+"Interview"]], null, null],
|
||||||
|
"journalArticle": [[[n.rdf+"type", n.bibo+"AcademicArticle"]], [true, n.dcterms+"isPartOf",
|
||||||
|
[[n.rdf+"type", n.bibo+"Issue"]]], [true, n.dcterms+"isPartOf", [[n.rdf+"type", n.bibo+"Journal"]]]],
|
||||||
|
"letter": [[[n.rdf+"type", n.bibo+"Letter"]], null, null],
|
||||||
|
"magazineArticle": [[[n.rdf+"type", n.bibo+"Article"]], [true, n.dcterms+"isPartOf",
|
||||||
|
[[n.rdf+"type", n.bibo+"Issue"]]], [true, n.dcterms+"isPartOf", [[n.rdf+"type", n.bibo+"Magazine"]]]],
|
||||||
|
"manuscript": [[[n.rdf+"type", n.bibo+"Manuscript"]], null, null],
|
||||||
|
"map": [[[n.rdf+"type", n.bibo+"Map"]], null, null],
|
||||||
|
"newspaperArticle": [[[n.rdf+"type", n.bibo+"Article"]], [true, n.dcterms+"isPartOf",
|
||||||
|
[[n.rdf+"type", n.bibo+"Issue"]]], [true, n.dcterms+"isPartOf", [[n.rdf+"type", n.bibo+"Newspaper"]]]],
|
||||||
|
"note": [[[n.rdf+"type", n.bibo+"Note"]], null, null],
|
||||||
|
"patent": [[[n.rdf+"type", n.bibo+"Patent"]], null, null],
|
||||||
|
"podcast": [[[n.rdf+"type", n.z+"Podcast"],
|
||||||
|
[n.rdf+"type", n.bibo+"AudioDocument"]], null, null],
|
||||||
|
"presentation": [[[n.rdf+"type", n.bibo+"Slideshow"]], null, null],
|
||||||
|
"radioBroadcast": [[[n.rdf+"type", n.po+"AudioDocument"],
|
||||||
|
[n.rdf+"type", n.po+"Episode"],
|
||||||
|
[n.po+"broadcast_on", n.po+"Radio"]], null, [n.rdf+"type", n.po+"Programme"]],
|
||||||
|
"report": [[[n.rdf+"type", n.bibo+"Report"]], null, null],
|
||||||
|
"statute": [[[n.rdf+"type", n.bibo+"Statute"]], null, [false, n.dcterms+"isPartOf", [[n.rdf+"type", n.bibo+"Code"]]]],
|
||||||
|
"thesis": [[[n.rdf+"type", n.bibo+"Thesis"]], null, null],
|
||||||
|
"tvBroadcast": [[[n.rdf+"type", n.bibo+"AudioVisualDocument"],
|
||||||
|
[n.rdf+"type", n.po+"Episode"],
|
||||||
|
[n.po+"broadcast_on", n.po+"TV"]], null, [n.rdf+"type", n.po+"Programme"]],
|
||||||
|
"videoRecording": [[[n.rdf+"type", n.bibo+"AudioVisualDocument"]], null, null],
|
||||||
|
"webpage": [[[n.rdf+"type", n.bibo+"Webpage"]], null, [false, n.dcterms+"isPartOf", [[n.rdf+"type", n.bibo+"Website"]]]]
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This is just a map of un-namespaced BIBO item types to Zotero item types
|
||||||
|
*/
|
||||||
|
var BIBO_TYPES = {
|
||||||
|
"Article": "magazineArticle",
|
||||||
|
"Brief": "case",
|
||||||
|
"Chapter": "bookSection",
|
||||||
|
"CollectedDocument": "document",
|
||||||
|
"DocumentPart": "document",
|
||||||
|
"EditedBook": "book",
|
||||||
|
"Excerpt": "note",
|
||||||
|
"Quote": "note",
|
||||||
|
"Film": "videoRecording",
|
||||||
|
"LegalDecision": "case",
|
||||||
|
"LegalDocument": "case",
|
||||||
|
"Legislation": "bill",
|
||||||
|
"Manual": "book",
|
||||||
|
"Performance": "presentation",
|
||||||
|
"PersonalCommunication": "letter",
|
||||||
|
"PersonalCommunicationDocument": "letter",
|
||||||
|
"Slide": "presentation",
|
||||||
|
"Standard": "report",
|
||||||
|
"Website": "webpage"
|
||||||
|
};
|
||||||
|
|
||||||
|
var USERITEM = 1;
|
||||||
|
var ITEM = 2;
|
||||||
|
var SUBCONTAINER = 3;
|
||||||
|
var CONTAINER = 4;
|
||||||
|
var ITEM_SERIES = 5;
|
||||||
|
var SUBCONTAINER_SERIES = 6; // not used
|
||||||
|
var CONTAINER_SERIES = 7;
|
||||||
|
|
||||||
|
/**
|
||||||
|
Fields should be in the form
|
||||||
|
|
||||||
|
<ZOTERO_FIELD>: ([<SUBJECT>, <PREDICATE>] | <FUNCTION>)
|
||||||
|
|
||||||
|
If a <FUNCTION> is specified, then it is passed the item and should return a set of triples in
|
||||||
|
the form
|
||||||
|
|
||||||
|
[[<SUBJECT>, <PREDICATE>, <OBJECT>, <LITERAL>]*]
|
||||||
|
|
||||||
|
where <SUBJECT> refers to one of the constants defined above. If <LITERAL> is true, then
|
||||||
|
<OBJECT> is treated as a literal.
|
||||||
|
|
||||||
|
If a <FUNCTION> is not used and <PREDICATE> is a string, then the parameters generate a triple
|
||||||
|
in the form
|
||||||
|
|
||||||
|
<SUBJECT> <PREDICATE> FIELD_CONTENT
|
||||||
|
|
||||||
|
where <SUBJECT> refers to one of the constants defined above. Alternatively, <PREDICATE> may be
|
||||||
|
an array in the form
|
||||||
|
|
||||||
|
[<ITEM_PREDICATE>, [<BLANK_NODE_PREDICATE>, <BLANK_NODE_OBJECT>]*, <PREDICATE>]
|
||||||
|
|
||||||
|
This generates the triples
|
||||||
|
|
||||||
|
<SUBJECT> <ITEM_PREDICATE> <BLANK_NODE>
|
||||||
|
(<BLANK_NODE> <BLANK_NODE_PREDICATE> <BLANK_NODE_OBJECT>)*
|
||||||
|
<BLANK_NODE> <PREDICATE> FIELD_CONTENT
|
||||||
|
**/
|
||||||
|
var FIELDS = {
|
||||||
|
"url": [ITEM, n.bibo+"uri"],
|
||||||
|
"rights": [USERITEM, n.dcterms+"rights"],
|
||||||
|
"series": [CONTAINER_SERIES, n.dcterms+"title"],
|
||||||
|
"volume": [SUBCONTAINER, n.bibo+"volume"],
|
||||||
|
"issue": [SUBCONTAINER, n.bibo+"issue"],
|
||||||
|
"edition": [SUBCONTAINER, n.bibo+"edition"],
|
||||||
|
"place": [CONTAINER, [n.dcterms+"publisher", [[n.rdf+"type", n.foaf+"Organization"]], n.address+"localityName"]],
|
||||||
|
"country": [CONTAINER, [n.dcterms+"publisher", [[n.rdf+"type", n.foaf+"Organization"]], n.address+"countryName"]],
|
||||||
|
"publisher": [CONTAINER, [n.dcterms+"publisher", [[n.rdf+"type", n.foaf+"Organization"]], n.foaf+"name"]],
|
||||||
|
"pages": [ITEM, n.bibo+"pages"],
|
||||||
|
"firstPage": [ITEM, n.bibo+"pageStart"],
|
||||||
|
"ISBN": [function(item) {
|
||||||
|
var isbns = item.ISBN.split(/, ?| /g);
|
||||||
|
var triples = [];
|
||||||
|
for each(var isbn in isbns) {
|
||||||
|
if(isbn.length == 10) {
|
||||||
|
triples.push([CONTAINER, n.bibo+"isbn10", isbn, true]);
|
||||||
|
} else {
|
||||||
|
triples.push([CONTAINER, n.bibo+"isbn13", isbn, true]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return triples;
|
||||||
|
}, function(nodes) {
|
||||||
|
var isbns = [];
|
||||||
|
for each(var prop in [n.bibo+"isbn13", n.bibo+"isbn10"]) {
|
||||||
|
var statements = Zotero.RDF.getStatementsMatching(nodes[CONTAINER], prop, null);
|
||||||
|
if(statements) {
|
||||||
|
for each(var statement in statements) {
|
||||||
|
isbns.push(statement[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!isbns.length) return false;
|
||||||
|
return isbns.join(", ");
|
||||||
|
}],
|
||||||
|
"publicationTitle": [CONTAINER, n.dcterms+"title"],
|
||||||
|
"ISSN": [CONTAINER, n.bibo+"issn"],
|
||||||
|
"date": [SUBCONTAINER, n.dcterms+"date"],
|
||||||
|
"section": [ITEM, n.bibo+"section"],
|
||||||
|
"callNumber": [SUBCONTAINER, n.bibo+"lccn"],
|
||||||
|
"archiveLocation": [ITEM, n.dcterms+"source"],
|
||||||
|
"distributor": [SUBCONTAINER, n.bibo+"distributor"],
|
||||||
|
"extra": [ITEM, n.z+"extra"],
|
||||||
|
"journalAbbreviation": [CONTAINER, n.bibo+"shortTitle"],
|
||||||
|
"DOI": [ITEM, n.bibo+"doi"],
|
||||||
|
"accessDate": [USERITEM, n.z+"accessDate"],
|
||||||
|
"seriesTitle": [ITEM_SERIES, n.dcterms+"title"],
|
||||||
|
"seriesText": [ITEM_SERIES, n.dcterms+"description"],
|
||||||
|
"seriesNumber": [CONTAINER_SERIES, n.bibo+"number"],
|
||||||
|
"code": [CONTAINER, n.dcterms+"title"],
|
||||||
|
"session": [ITEM, [n.bibo+"presentedAt", [[n.rdf+"type", n.bibo+"Conference"]], n.dcterms+"title"]],
|
||||||
|
"legislativeBody": [ITEM, [n.bibo+"organizer", [[n.rdf+"type", n.sc+"LegalGovernmentOrganization"], [n.rdf+"type", n.foaf+"Organization"]], n.foaf+"name"]],
|
||||||
|
"history": [ITEM, n.z+"history"],
|
||||||
|
"reporter": [CONTAINER, n.dcterms+"title"],
|
||||||
|
"court": [CONTAINER, n.bibo+"court"],
|
||||||
|
"numberOfVolumes": [CONTAINER_SERIES, n.bibo+"numberOfVolumes"],
|
||||||
|
"committee": [ITEM, [n.bibo+"organizer", [[n.rdf+"type", n.sc+"Committee_Organization"], [n.rdf+"type", n.foaf+"Organization"]], n.foaf+"name"]],
|
||||||
|
"assignee": [ITEM, n.z+"assignee"], // TODO
|
||||||
|
"priorityNumbers": [function(item) { // TODO
|
||||||
|
var priorityNumbers = item.priorityNumbers.split(/, ?| /g);
|
||||||
|
return [[ITEM, n.z+"priorityNumber", number, true] for each(number in priorityNumbers)];
|
||||||
|
}, function(nodes) {
|
||||||
|
var statements = Zotero.RDF.getStatementsMatching(nodes[ITEM], n.z+"priorityNumber", null);
|
||||||
|
if(!statements) return false;
|
||||||
|
return [statement[2] for each(statement in statements)].join(", ");
|
||||||
|
}],
|
||||||
|
"references": [ITEM, n.z+"references"],
|
||||||
|
"legalStatus": [ITEM, n.bibo+"status"],
|
||||||
|
"codeNumber": [CONTAINER, n.bibo+"number"],
|
||||||
|
"number": [ITEM, n.bibo+"number"],
|
||||||
|
"artworkSize": [ITEM, n.dcterms+"extent"],
|
||||||
|
"libraryCatalog": [USERITEM, n.z+"repository"],
|
||||||
|
"archive": [ITEM, n.z+"repository"],
|
||||||
|
"scale": [ITEM, n.z+"scale"],
|
||||||
|
"meetingName": [ITEM, [n.bibo+"presentedAt", [[n.rdf+"type", n.bibo+"Conference"]], n.dcterms+"title"]],
|
||||||
|
"runningTime": [ITEM, n.po+"duration"],
|
||||||
|
"version": [ITEM, n.doap+"revision"],
|
||||||
|
"system": [ITEM, n.doap+"os"],
|
||||||
|
"conferenceName": [ITEM, [n.bibo+"presentedAt", [[n.rdf+"type", n.bibo+"Conference"]], n.dcterms+"title"]],
|
||||||
|
"language": [ITEM, n.dcterms+"language"],
|
||||||
|
"programmingLanguage": [ITEM, n.doap+"programming-language"],
|
||||||
|
"abstractNote": [ITEM, n.dcterms+"abstract"],
|
||||||
|
"type": [ITEM, n.dcterms+"type"],
|
||||||
|
"medium": [ITEM, n.dcterms+"medium"],
|
||||||
|
"title": [ITEM, n.dcterms+"title"],
|
||||||
|
"shortTitle": [ITEM, n.bibo+"shortTitle"],
|
||||||
|
"numPages": [ITEM, n.bibo+"numPages"],
|
||||||
|
"applicationNumber": [ITEM, n.z+"applicationNumber"],
|
||||||
|
"issuingAuthority": [ITEM, [n.bibo+"issuer", [[n.rdf+"type", n.foaf+"Organization"]], n.foaf+"name"]],
|
||||||
|
"filingDate": [ITEM, n.dcterms+"dateSubmitted"]
|
||||||
|
};
|
||||||
|
|
||||||
|
var AUTHOR_LIST = 1;
|
||||||
|
var EDITOR_LIST = 2;
|
||||||
|
var CONTRIBUTOR_LIST = 3;
|
||||||
|
var CREATOR_LISTS = {
|
||||||
|
1:n.bibo+"authorList",
|
||||||
|
2:n.bibo+"editorList",
|
||||||
|
3:n.bibo+"contributorList"
|
||||||
|
};
|
||||||
|
|
||||||
|
var CREATORS = {
|
||||||
|
"author": [ITEM, AUTHOR_LIST, n.dcterms+"creator"],
|
||||||
|
"attorneyAgent": [ITEM, CONTRIBUTOR_LIST, n.z+"attorneyAgent"],
|
||||||
|
"bookAuthor": [CONTAINER, AUTHOR_LIST, n.dcterms+"creator"],
|
||||||
|
"castMember": [ITEM, CONTRIBUTOR_LIST, n.rel+"ACT"],
|
||||||
|
"commenter": [ITEM, CONTRIBUTOR_LIST, [n.sioct+"has_reply", [[n.rdf+"type", n.sioct+"Comment"]], n.dcterms+"creator"]],
|
||||||
|
"composer": [ITEM, CONTRIBUTOR_LIST, n.rel+"CMP"],
|
||||||
|
"contributor": [ITEM, CONTRIBUTOR_LIST, n.dcterms+"contributor"],
|
||||||
|
"cosponsor": [ITEM, CONTRIBUTOR_LIST, n.rel+"SPN"],
|
||||||
|
"counsel": [ITEM, CONTRIBUTOR_LIST, n.z+"counsel"],
|
||||||
|
"director": [ITEM, CONTRIBUTOR_LIST, n.bibo+"director"],
|
||||||
|
"editor": [SUBCONTAINER, EDITOR_LIST, n.bibo+"editor"],
|
||||||
|
"guest": [ITEM, CONTRIBUTOR_LIST, n.po+"participant"],
|
||||||
|
"interviewer": [ITEM, CONTRIBUTOR_LIST, n.bibo+"interviewer"],
|
||||||
|
"interviewee": [ITEM, CONTRIBUTOR_LIST, n.bibo+"interviewee"],
|
||||||
|
"performer": [ITEM, CONTRIBUTOR_LIST, n.bibo+"performer"],
|
||||||
|
"producer": [ITEM, CONTRIBUTOR_LIST, n.bibo+"producer"],
|
||||||
|
"recipient": [ITEM, CONTRIBUTOR_LIST, n.bibo+"recipient"],
|
||||||
|
"reviewedAuthor": [ITEM, CONTRIBUTOR_LIST, [n.bibo+"reviewOf", [], n.dcterms+"creator"]],
|
||||||
|
"scriptwriter": [ITEM, CONTRIBUTOR_LIST, n.rel+"AUS"],
|
||||||
|
"seriesEditor": [CONTAINER_SERIES, EDITOR_LIST, n.bibo+"editor"],
|
||||||
|
"translator": [SUBCONTAINER, CONTRIBUTOR_LIST, n.bibo+"translator"],
|
||||||
|
"wordsBy": [ITEM, CONTRIBUTOR_LIST, n.rel+"LYR"]
|
||||||
|
};
|
||||||
|
|
||||||
|
var SAME_ITEM_RELATIONS = [n.dcterms+"isPartOf", n.dcterms+"isVersionOf", n.bibo+"affirmedBy",
|
||||||
|
n.bibo+"presentedAt", n.bibo+"presents", n.bibo+"reproducedIn",
|
||||||
|
n.bibo+"reviewOf", n.bibo+"translationOf", n.bibo+"transcriptOf"];
|
||||||
|
|
||||||
|
/** COMMON FUNCTIONS **/
|
||||||
|
|
||||||
|
var BIBO_NS_LENGTH = n.bibo.length;
|
||||||
|
var RDF_TYPE = n.rdf+"type";
|
||||||
|
|
||||||
|
function getBlankNode(attachToNode, itemPredicate, blankNodePairs, create) {
|
||||||
|
// check if a node with the same relation and properties already exists
|
||||||
|
var blankNode = null;
|
||||||
|
// look for blank node
|
||||||
|
var statements1 = Zotero.RDF.getStatementsMatching(attachToNode, itemPredicate, undefined);
|
||||||
|
for each(var statement1 in statements1) {
|
||||||
|
// look for appropriate statements on the blank node
|
||||||
|
var testNode = statement1[2];
|
||||||
|
var statements2 = true;
|
||||||
|
for each(var pair in blankNodePairs) {
|
||||||
|
statements2 = Zotero.RDF.getStatementsMatching(testNode, pair[0], pair[1], false, true);
|
||||||
|
if(!statements2) break;
|
||||||
|
}
|
||||||
|
if(statements2) {
|
||||||
|
// if statements are good, then this is our node
|
||||||
|
blankNode = testNode;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if no suitable node exists, generate a new one and add blank node statements
|
||||||
|
if(!blankNode && create) {
|
||||||
|
blankNode = Zotero.RDF.newResource();
|
||||||
|
Zotero.RDF.addStatement(attachToNode, itemPredicate, blankNode, false);
|
||||||
|
[Zotero.RDF.addStatement(blankNode, pair[0], pair[1], false) for each(pair in blankNodePairs)];
|
||||||
|
}
|
||||||
|
|
||||||
|
return blankNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class representing a Zotero-to-BIBO type mapping
|
||||||
|
* @property zoteroType {String} The corresponding Zotero type name
|
||||||
|
*/
|
||||||
|
Type = function(type, typeDefinition) {
|
||||||
|
this.zoteroType = type;
|
||||||
|
this[ITEM] = {"pairs":typeDefinition[0]};
|
||||||
|
this[SUBCONTAINER] = typeDefinition[1] ? {"alwaysAdd":typeDefinition[1][0],
|
||||||
|
"predicate":typeDefinition[1][1],
|
||||||
|
"pairs":typeDefinition[1][2]} : null;
|
||||||
|
this[CONTAINER] = typeDefinition[2] ? {"alwaysAdd":typeDefinition[2][0],
|
||||||
|
"predicate":typeDefinition[2][1],
|
||||||
|
"pairs":typeDefinition[2][2]} : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Score a node to determine how well it matches our type definition
|
||||||
|
* @returns {[Integer, Object]} The score, and an object containing ITEM, SUBCONTAINER, and
|
||||||
|
* CONTAINER nodes
|
||||||
|
*/
|
||||||
|
Type.prototype.getMatchScore = function(node) {
|
||||||
|
var nodes = {2:node};
|
||||||
|
|
||||||
|
// check item (+2 for each match, -1 for each nonmatch)
|
||||||
|
var score = 3*[true for each(pair in this[ITEM].pairs) if(Zotero.RDF.getStatementsMatching(node, pair[0], pair[1]))].length-this[ITEM].pairs.length;
|
||||||
|
// check subcontainer
|
||||||
|
[score, nodes[SUBCONTAINER]] = this._scoreNodeRelationship(node, this[SUBCONTAINER], score);
|
||||||
|
// check container
|
||||||
|
[score, nodes[CONTAINER]] = this._scoreNodeRelationship(
|
||||||
|
(nodes[SUBCONTAINER] ? nodes[SUBCONTAINER] : nodes[ITEM]), this[CONTAINER], score);
|
||||||
|
|
||||||
|
if(!nodes[CONTAINER]) nodes[CONTAINER] = nodes[ITEM];
|
||||||
|
if(!nodes[SUBCONTAINER]) nodes[SUBCONTAINER] = nodes[CONTAINER];
|
||||||
|
|
||||||
|
return [score, nodes];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Score a CONTAINER/SUBCONTAINTER node
|
||||||
|
* @returns {[Integer, Object]} The score, and the node (if it existed)
|
||||||
|
*/
|
||||||
|
Type.prototype._scoreNodeRelationship = function(node, definition, score) {
|
||||||
|
var subNode = null;
|
||||||
|
if(definition) {
|
||||||
|
statements = Zotero.RDF.getStatementsMatching(node, definition.predicate, null);
|
||||||
|
if(statements) {
|
||||||
|
var bestScore = -9999;
|
||||||
|
for each(var statement in statements) {
|
||||||
|
// +2 for each match, -1 for each nonmatch
|
||||||
|
var testScore = 3*[true for each(pair in definition.pairs) if(Zotero.RDF.getStatementsMatching(statement[2], pair[0], pair[1]))].length-definition.pairs.length;
|
||||||
|
if(testScore > bestScore) {
|
||||||
|
subNode = statement[2];
|
||||||
|
bestScore = testScore;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
score += bestScore;
|
||||||
|
} else if(definition.alwaysAdd) {
|
||||||
|
score -= definition.pairs.length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [score, subNode];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get USERITEM and SERIES nodes for this type
|
||||||
|
*/
|
||||||
|
Type.prototype.getItemSeriesNodes = function(nodes) {
|
||||||
|
const seriesDefinition = {"alwaysAdd":true, "predicate":n.dcterms+"isPartOf", "pairs":[[n.rdf+"type", n.bibo+"Series"]]};
|
||||||
|
|
||||||
|
// get user item node
|
||||||
|
var stmt = Zotero.RDF.getStatementsMatching(null, n.res+"resource", nodes[ITEM]);
|
||||||
|
nodes[USERITEM] = stmt ? stmt[0][0] : nodes[ITEM];
|
||||||
|
|
||||||
|
// get ITEM_SERIES node
|
||||||
|
var score, subNode;
|
||||||
|
[score, subNode] = this._scoreNodeRelationship(nodes[ITEM], seriesDefinition, 0);
|
||||||
|
Zotero.debug("got itemSeries with score "+score);
|
||||||
|
if(score >= 1) nodes[ITEM_SERIES] = subNode;
|
||||||
|
|
||||||
|
// get SUBCONTAINER_SERIES node
|
||||||
|
[score, subNode] = this._scoreNodeRelationship(nodes[SUBCONTAINER], seriesDefinition, 0);
|
||||||
|
Zotero.debug("got subcontainerSeries with score "+score);
|
||||||
|
if(score >= 1) nodes[CONTAINER_SERIES] = subNode;
|
||||||
|
|
||||||
|
// get CONTAINER_SERIES node
|
||||||
|
[score, subNode] = this._scoreNodeRelationship(nodes[CONTAINER], seriesDefinition, 0);
|
||||||
|
Zotero.debug("got containerSeries with score "+score);
|
||||||
|
if(score >= 1) nodes[CONTAINER_SERIES] = subNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add triples to relate nodes. Called after all properties have been added, so we know which nodes
|
||||||
|
* need to be related.
|
||||||
|
*/
|
||||||
|
Type.prototype.addNodeRelations = function(nodes) {
|
||||||
|
// add node relations
|
||||||
|
for each(var i in [ITEM_SERIES, SUBCONTAINER_SERIES, CONTAINER_SERIES]) {
|
||||||
|
// don't add duplicate nodes
|
||||||
|
if(!this[i-3]) continue;
|
||||||
|
// don't add nodes with no arcs
|
||||||
|
if(!Zotero.RDF.getArcsOut(nodes[i])) continue;
|
||||||
|
Zotero.RDF.addStatement(nodes[i], RDF_TYPE, n.bibo+"Series", false);
|
||||||
|
Zotero.RDF.addStatement(nodes[i-3], n.dcterms+"isPartOf", nodes[i], false);
|
||||||
|
}
|
||||||
|
|
||||||
|
for each(var i in [ITEM, SUBCONTAINER, CONTAINER]) {
|
||||||
|
if(nodes[i]) {
|
||||||
|
// find predicate
|
||||||
|
if(i == ITEM) {
|
||||||
|
var j = 1;
|
||||||
|
var predicate = n.res+"resource";
|
||||||
|
} else if(i == SUBCONTAINER || i == CONTAINER) {
|
||||||
|
// don't add duplicate nodes
|
||||||
|
if(!this[i]) continue;
|
||||||
|
// don't add nodes with no arcs
|
||||||
|
if(!this[i][0] && !Zotero.RDF.getArcsOut(nodes[i])) {
|
||||||
|
nodes[i] = nodes[i-1];
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var predicate = this[i].predicate;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add type
|
||||||
|
[Zotero.RDF.addStatement(nodes[i], pair[0], pair[1], false)
|
||||||
|
for each(pair in this[i].pairs)];
|
||||||
|
|
||||||
|
// add relation to parent
|
||||||
|
for(var j = i-1; j>1; j--) {
|
||||||
|
if(nodes[j] != nodes[i]) {
|
||||||
|
Zotero.RDF.addStatement(nodes[j], predicate, nodes[i], false);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create USERITEM/ITEM/CONTAINER/SUBCONTAINER nodes for this type
|
||||||
|
* @returns {Object} The created nodes
|
||||||
|
*/
|
||||||
|
Type.prototype.createNodes = function(item) {
|
||||||
|
var nodes = {};
|
||||||
|
nodes[USERITEM] = "#item_"+item.itemID;
|
||||||
|
|
||||||
|
// come up with an item node URI
|
||||||
|
nodes[ITEM] = null;
|
||||||
|
// try the URL as URI
|
||||||
|
if(item.url) {
|
||||||
|
nodes[ITEM] = encodeURI(item.url);
|
||||||
|
if(usedURIs[nodes[ITEM]]) nodes[ITEM] = null;
|
||||||
|
}
|
||||||
|
// try the DOI as URI
|
||||||
|
if(!nodes[ITEM] && item.DOI) {
|
||||||
|
var doi = item.DOI;
|
||||||
|
if(doi.substr(0, 4) == "doi:") {
|
||||||
|
doi = doi.substr(4);
|
||||||
|
} else if(doi.substr(0, 8) == "urn:doi:") {
|
||||||
|
doi = doi.substr(8);
|
||||||
|
} else if(doi.substr(0, 9) == "info:doi/") {
|
||||||
|
doi = doi.substr(9);
|
||||||
|
} else if(doi.substr(0, 18) == "http://dx.doi.org/") {
|
||||||
|
doi = doi.substr(18);
|
||||||
|
}
|
||||||
|
nodes[ITEM] = "info:doi/"+encodeURI(doi);
|
||||||
|
if(usedURIs[nodes[ITEM]]) nodes[ITEM] = null;
|
||||||
|
}
|
||||||
|
// try the ISBN as URI
|
||||||
|
if(!nodes[ITEM] && item.ISBN) {
|
||||||
|
var isbn = item.ISBN.split(/, ?| /g)[0];
|
||||||
|
nodes[ITEM] = "urn:isbn:"+encodeURI(isbn);
|
||||||
|
if(usedURIs[nodes[ITEM]]) nodes[ITEM] = null;
|
||||||
|
}
|
||||||
|
// no suitable item URI; fall back to a blank node
|
||||||
|
if(!nodes[ITEM]) nodes[ITEM] = Zotero.RDF.newResource();
|
||||||
|
usedURIs[Zotero.RDF.getResourceURI(nodes[ITEM])] = true;
|
||||||
|
|
||||||
|
// attach item node to user item node
|
||||||
|
Zotero.RDF.addStatement(nodes[USERITEM], RDF_TYPE, n.z+"UserItem", false);
|
||||||
|
Zotero.RDF.addStatement(nodes[USERITEM], n.res+"resource", nodes[ITEM], false);
|
||||||
|
|
||||||
|
// container node
|
||||||
|
nodes[CONTAINER] = (this[CONTAINER] ? Zotero.RDF.newResource() : nodes[ITEM]);
|
||||||
|
|
||||||
|
// subcontainer node
|
||||||
|
nodes[SUBCONTAINER] = (this[SUBCONTAINER] ? Zotero.RDF.newResource() : nodes[CONTAINER]);
|
||||||
|
|
||||||
|
// series nodes
|
||||||
|
nodes[ITEM_SERIES] = Zotero.RDF.newResource();
|
||||||
|
nodes[CONTAINER_SERIES] = (this[CONTAINER] ? Zotero.RDF.newResource() : nodes[ITEM_SERIES]);
|
||||||
|
nodes[SUBCONTAINER_SERIES] = (this[SUBCONTAINER] ? Zotero.RDF.newResource() : nodes[CONTAINER_SERIES]);
|
||||||
|
|
||||||
|
return nodes;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class representing a BIBO-to-Zotero literal property mapping
|
||||||
|
*/
|
||||||
|
LiteralProperty = function(field) {
|
||||||
|
this.field = field;
|
||||||
|
this.mapping = FIELDS[field];
|
||||||
|
if(!this.mapping) {
|
||||||
|
Zotero.debug("WARNING: unrecognized field "+field+" in Bibliontology RDF; mapping to Zotero namespace");
|
||||||
|
this.mapping = [ITEM, n.z+field];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps property from a set of RDF nodes to an item
|
||||||
|
*/
|
||||||
|
LiteralProperty.prototype.mapToItem = function(newItem, nodes) {
|
||||||
|
if(typeof this.mapping[0] == "function") { // function case: triples returned
|
||||||
|
// check function case
|
||||||
|
var content = this.mapping[1](nodes);
|
||||||
|
if(!content) return false;
|
||||||
|
newItem[this.field] = content;
|
||||||
|
} else {
|
||||||
|
var node = nodes[this.mapping[0]];
|
||||||
|
if(!node) return false;
|
||||||
|
var statements = getStatementsByDefinition(this.mapping[1], node);
|
||||||
|
if(!statements) return false;
|
||||||
|
newItem[this.field] = [stmt[2].toString() for each(stmt in statements)].join(", ");
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps property from an item to a set of RDF nodes
|
||||||
|
*/
|
||||||
|
LiteralProperty.prototype.mapFromItem = function(item, nodes) {
|
||||||
|
if(typeof this.mapping[0] == "function") { // function case: triples returned
|
||||||
|
// check function case
|
||||||
|
[Zotero.RDF.addStatement(nodes[triple[0]], triple[1], triple[2], triple[3])
|
||||||
|
for each(triple in this.mapping[0](item))];
|
||||||
|
} else if(typeof this.mapping[1] == "string") { // string case: simple predicate
|
||||||
|
Zotero.RDF.addStatement(nodes[this.mapping[0]],
|
||||||
|
this.mapping[1], item.uniqueFields[this.field], true);
|
||||||
|
} else { // array case: complex predicate
|
||||||
|
var blankNode = getBlankNode(nodes[this.mapping[0]],
|
||||||
|
this.mapping[1][0], this.mapping[1][1], true);
|
||||||
|
Zotero.RDF.addStatement(blankNode, this.mapping[1][2], item.uniqueFields[this.field], true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A class representing a BIBO-to-Zotero creator mapping
|
||||||
|
*/
|
||||||
|
CreatorProperty = function(field) {
|
||||||
|
this.field = field;
|
||||||
|
this.mapping = CREATORS[field];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps creator from an foaf:Agent
|
||||||
|
*/
|
||||||
|
CreatorProperty.prototype.mapToCreator = function(creatorNode, zoteroType) {
|
||||||
|
Zotero.debug("mapping "+Zotero.RDF.getResourceURI(creatorNode)+" to a creator");
|
||||||
|
var lastNameStmt = Zotero.RDF.getStatementsMatching(creatorNode, n.foaf+"surname", null);
|
||||||
|
if(lastNameStmt) { // look for a person with a last name
|
||||||
|
creator = {lastName:lastNameStmt[0][2].toString()};
|
||||||
|
var firstNameStmt = Zotero.RDF.getStatementsMatching(creatorNode, n.foaf+"givenname", null);
|
||||||
|
if(firstNameStmt) creator.firstName = firstNameStmt[0][2].toString();
|
||||||
|
} else {
|
||||||
|
var nameStmt = Zotero.RDF.getStatementsMatching(creatorNode, n.foaf+"name", null);
|
||||||
|
if(nameStmt) { // an organization
|
||||||
|
creator = {lastName:nameStmt[0][2].toString(), fieldMode:1};
|
||||||
|
} else { // an unnamed entity; ignore it
|
||||||
|
Zotero.debug("Dropping unnamed creator "+creatorNode.toString());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// birthYear and shortName
|
||||||
|
var birthStmt = Zotero.RDF.getStatementsMatching(creatorNode, n.foaf+"birthday", null, true);
|
||||||
|
if(birthStmt) creator.birthYear = birthStmt[2].toString();
|
||||||
|
var nickStmt = Zotero.RDF.getStatementsMatching(creatorNode, n.foaf+"nick", null, true);
|
||||||
|
if(nickStmt) creator.shortName = nickStmt[2].toString();
|
||||||
|
|
||||||
|
if(this.field == "author") {
|
||||||
|
// could be another primary creator
|
||||||
|
var creatorsForType = Zotero.Utilities.getCreatorsForType(zoteroType);
|
||||||
|
if(creatorsForType.indexOf("author") == -1) {
|
||||||
|
creator.creatorType = creatorsForType[0];
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
creator.creatorType = this.field;
|
||||||
|
}
|
||||||
|
return creator;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps creators from a top-level (ITEM/SUBCONTAINER/CONTAINER/SERIES) node to a list
|
||||||
|
*/
|
||||||
|
CreatorProperty.prototype.mapToCreators = function(node, zoteroType) {
|
||||||
|
var creators = [];
|
||||||
|
var creatorNodes = [];
|
||||||
|
var statements = getStatementsByDefinition(this.mapping[2], node);
|
||||||
|
if(statements) {
|
||||||
|
for each(var stmt in statements) {
|
||||||
|
var creator = this.mapToCreator(stmt[2], zoteroType);
|
||||||
|
if(creator) {
|
||||||
|
creators.push(creator);
|
||||||
|
creatorNodes.push(stmt[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return [creators, creatorNodes];
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Maps property from a Zotero creator array to a set of RDF nodes
|
||||||
|
*/
|
||||||
|
CreatorProperty.prototype.mapFromCreator = function(item, creator, nodes) {
|
||||||
|
var creatorsForType = Zotero.Utilities.getCreatorsForType(item.itemType);
|
||||||
|
var isPrimary = creatorsForType[0] == this.field;
|
||||||
|
if(this.mapping) {
|
||||||
|
var mapping = this.mapping;
|
||||||
|
} else {
|
||||||
|
if(isPrimary && creatorsForType.indexOf("author") == -1) {
|
||||||
|
// treat other primary creators as dcterms:creators
|
||||||
|
var mapping = CREATORS["author"];
|
||||||
|
} else {
|
||||||
|
Zotero.debug("WARNING: unrecognized creator type "+this.field+" in Bibliontology RDF; mapping to Zotero namespace");
|
||||||
|
var mapping = [ITEM, AUTHOR_LIST, n.z+this.field];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
var creatorNode = Zotero.RDF.newResource();
|
||||||
|
if(creator.fieldMode == 1) {
|
||||||
|
Zotero.RDF.addStatement(creatorNode, RDF_TYPE, n.foaf+"Organization");
|
||||||
|
if(creator.lastName) Zotero.RDF.addStatement(creatorNode, n.foaf+"name", creator.lastName, true);
|
||||||
|
} else {
|
||||||
|
Zotero.RDF.addStatement(creatorNode, RDF_TYPE, n.foaf+"Person");
|
||||||
|
if(creator.firstName) Zotero.RDF.addStatement(creatorNode, n.foaf+"givenname", creator.firstName, true);
|
||||||
|
if(creator.lastName) Zotero.RDF.addStatement(creatorNode, n.foaf+"surname", creator.lastName, true);
|
||||||
|
}
|
||||||
|
if(creator.birthYear) Zotero.RDF.addStatement(creatorNode, n.foaf+"birthday", creator.birthYear, true);
|
||||||
|
if(creator.shortName) Zotero.RDF.addStatement(creatorNode, n.foaf+"nick", creator.shortName, true);
|
||||||
|
|
||||||
|
// attach creator node
|
||||||
|
var attachTo = nodes[mapping[0]];
|
||||||
|
if(typeof mapping[2] == "string") {
|
||||||
|
var relation = mapping[2];
|
||||||
|
} else {
|
||||||
|
var relation = mapping[2][2];
|
||||||
|
var attachTo = getBlankNode(attachTo, mapping[2][0], mapping[2][1], true);
|
||||||
|
}
|
||||||
|
Zotero.RDF.addStatement(attachTo, relation, creatorNode, false);
|
||||||
|
|
||||||
|
// get appropriate creator list
|
||||||
|
var list = mapping[1];
|
||||||
|
if(list == CONTRIBUTOR_LIST && isPrimary) {
|
||||||
|
// always attach primary to author list instead of contributor list
|
||||||
|
list = AUTHOR_LIST;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add to creator list
|
||||||
|
var creatorList = Zotero.RDF.getStatementsMatching(nodes[mapping[0]], CREATOR_LISTS[list], null);
|
||||||
|
if(creatorList) {
|
||||||
|
var creatorList = creatorList[0][2];
|
||||||
|
} else {
|
||||||
|
var creatorList = Zotero.RDF.newResource();
|
||||||
|
Zotero.RDF.newContainer("seq", creatorList);
|
||||||
|
Zotero.RDF.addStatement(nodes[mapping[0]], CREATOR_LISTS[list], creatorList, false);
|
||||||
|
}
|
||||||
|
Zotero.RDF.addContainerElement(creatorList, creatorNode, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** IMPORT FUNCTIONS **/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets statements matching a statement definition, if it exists
|
||||||
|
*/
|
||||||
|
function getStatementsByDefinition(definition, node) {
|
||||||
|
var statements = null;
|
||||||
|
if(typeof definition == "string") { // string case: simple predicate
|
||||||
|
statements = Zotero.RDF.getStatementsMatching(node, definition, null);
|
||||||
|
} else { // array case: complex
|
||||||
|
var blankNode = getBlankNode(node, definition[0], definition[1], false);
|
||||||
|
if(blankNode) {
|
||||||
|
statements = Zotero.RDF.getStatementsMatching(blankNode, definition[2], null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return statements;
|
||||||
|
}
|
||||||
|
|
||||||
|
function detectImport() {
|
||||||
|
// look for a bibo item type
|
||||||
|
var rdfTypes = Zotero.RDF.getStatementsMatching(null, RDF_TYPE, null);
|
||||||
|
if(rdfTypes) {
|
||||||
|
for each(var rdfType in rdfTypes) {
|
||||||
|
if(rdfType[2].uri && rdfType[2].uri.substr(0, BIBO_NS_LENGTH) == n.bibo) return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
function doImport() {
|
||||||
|
// collapse list of BIBO-only types
|
||||||
|
var collapsedTypes = {};
|
||||||
|
for(var unprefixedBiboType in BIBO_TYPES) {
|
||||||
|
var biboType = n.bibo+unprefixedBiboType;
|
||||||
|
var type = new Type(BIBO_TYPES[unprefixedBiboType], [[[RDF_TYPE, n.bibo+biboType]], null, null]);
|
||||||
|
if(!collapsedTypes[biboType]) {
|
||||||
|
collapsedTypes[biboType] = [type];
|
||||||
|
} else {
|
||||||
|
collapsedTypes[biboType].push(type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// collapse Zotero-to-BIBO type mappings
|
||||||
|
for(var zoteroType in TYPES) {
|
||||||
|
var type = new Type(zoteroType, TYPES[zoteroType]);
|
||||||
|
for each(var pair in TYPES[zoteroType][0]) {
|
||||||
|
if(!collapsedTypes[pair[1]]) {
|
||||||
|
collapsedTypes[pair[1]] = [type];
|
||||||
|
} else {
|
||||||
|
collapsedTypes[pair[1]].push(type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// collapse list of field mappings
|
||||||
|
var collapsedProperties = {1:{}, 2:{}, 3:{}, 4:{}, 5:{}, 6:{}, 7:{}};
|
||||||
|
var functionProperties = {};
|
||||||
|
for(var zoteroField in FIELDS) {
|
||||||
|
if(typeof FIELDS[zoteroField][0] == "function") {
|
||||||
|
functionProperties[zoteroField] = new LiteralProperty(zoteroField);
|
||||||
|
} else {
|
||||||
|
var domain = FIELDS[zoteroField][0];
|
||||||
|
var predicate = FIELDS[zoteroField][1];
|
||||||
|
if(typeof predicate == "object") predicate = predicate[0];
|
||||||
|
var prop = new LiteralProperty(zoteroField);
|
||||||
|
|
||||||
|
if(collapsedProperties[domain][predicate]) {
|
||||||
|
collapsedProperties[domain][predicate].push(prop);
|
||||||
|
} else {
|
||||||
|
collapsedProperties[domain][predicate] = [prop];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// collapse list of creators
|
||||||
|
for(var creatorType in CREATORS) {
|
||||||
|
var domain = CREATORS[creatorType][0];
|
||||||
|
var predicate = CREATORS[creatorType][2];
|
||||||
|
if(typeof predicate == "object") predicate = predicate[0];
|
||||||
|
var prop = new CreatorProperty(creatorType);
|
||||||
|
|
||||||
|
if(collapsedProperties[domain][predicate]) {
|
||||||
|
collapsedProperties[domain][predicate].unshift(prop);
|
||||||
|
} else {
|
||||||
|
collapsedProperties[domain][predicate] = [prop];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Go through all type arcs to find items
|
||||||
|
var itemNode, predicateNode, objectNode;
|
||||||
|
var rdfTypes = Zotero.RDF.getStatementsMatching(null, RDF_TYPE, null);
|
||||||
|
var itemNodes = {};
|
||||||
|
for each(var rdfType in rdfTypes) {
|
||||||
|
[itemNode, predicateNode, objectNode] = rdfType;
|
||||||
|
if(!objectNode.uri || !collapsedTypes[objectNode.uri]) continue;
|
||||||
|
itemNodes[Zotero.RDF.getResourceURI(itemNode)] = itemNode;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Look through found items to see if their rdf:type matches a Zotero item type URI, and if so,
|
||||||
|
// subject to further processing
|
||||||
|
for each(var itemNode in itemNodes) {
|
||||||
|
// check whether the relationship to another item precludes us from extracting this as
|
||||||
|
// top-level
|
||||||
|
var skip = false;
|
||||||
|
for each(var arc in Zotero.RDF.getArcsIn(itemNode)) {
|
||||||
|
if(SAME_ITEM_RELATIONS.indexOf(arc) !== -1) {
|
||||||
|
skip = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(skip) continue;
|
||||||
|
|
||||||
|
var itemRDFTypes = Zotero.RDF.getStatementsMatching(itemNode, RDF_TYPE, null);
|
||||||
|
|
||||||
|
// score types by the number of triples they share with our types
|
||||||
|
var bestTypeScore = -9999;
|
||||||
|
var bestType, score, nodes, bestNodes;
|
||||||
|
for each(var rdfType in itemRDFTypes) {
|
||||||
|
if(!rdfType[2].uri) continue;
|
||||||
|
|
||||||
|
for each(var type in collapsedTypes[rdfType[2].uri]) {
|
||||||
|
[score, nodes] = type.getMatchScore(itemNode);
|
||||||
|
Zotero.debug("Type "+type.zoteroType+" has score "+score);
|
||||||
|
|
||||||
|
// check if this is the best we can do
|
||||||
|
if(score > bestTypeScore) {
|
||||||
|
bestTypeScore = score;
|
||||||
|
bestType = type;
|
||||||
|
bestNodes = nodes;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// skip if this doesn't fit any type very well
|
||||||
|
if(bestTypeScore < 1) {
|
||||||
|
Zotero.debug("No good type mapping; best type was "+bestType.zoteroType+" with score "+bestTypeScore);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
Zotero.debug("Got item of type "+bestType.zoteroType+" with score "+bestTypeScore);
|
||||||
|
nodes = bestNodes;
|
||||||
|
bestType.getItemSeriesNodes(nodes);
|
||||||
|
Zotero.debug([i+" = "+nodes[i].toString() for(i in nodes)]);
|
||||||
|
|
||||||
|
// create item
|
||||||
|
var zoteroType = bestType.zoteroType;
|
||||||
|
var newItem = new Zotero.Item(zoteroType);
|
||||||
|
|
||||||
|
// handle ordinary properties
|
||||||
|
var allCreators = {}
|
||||||
|
for(var i in nodes) {
|
||||||
|
var propertiesHandled = {};
|
||||||
|
var properties = Zotero.RDF.getArcsOut(nodes[i]);
|
||||||
|
for each(var property in properties) {
|
||||||
|
// only handle each property once
|
||||||
|
if(propertiesHandled[property]) continue;
|
||||||
|
propertiesHandled[property] = true;
|
||||||
|
Zotero.debug("handling "+property);
|
||||||
|
|
||||||
|
var propertyMappings = collapsedProperties[i][property];
|
||||||
|
Zotero.debug(propertyMappings);
|
||||||
|
if(propertyMappings) {
|
||||||
|
for each(var propertyMapping in propertyMappings) {
|
||||||
|
if(propertyMapping.mapToItem) { // LiteralProperty
|
||||||
|
propertyMapping.mapToItem(newItem, nodes);
|
||||||
|
} else if(propertyMapping.mapToCreator) { // CreatorProperty
|
||||||
|
var creators, creatorNodes;
|
||||||
|
[creators, creatorNodes] = propertyMapping.mapToCreators(nodes[i], zoteroType);
|
||||||
|
Zotero.debug(creators);
|
||||||
|
if(creators.length) {
|
||||||
|
for(var j in creators) {
|
||||||
|
var creatorNodeURI = Zotero.RDF.getResourceURI(creatorNodes[j]);
|
||||||
|
if(!allCreators[creatorNodeURI]) {
|
||||||
|
allCreators[creatorNodeURI] = creators[j];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle function properties
|
||||||
|
for each(var functionProperty in functionProperties) {
|
||||||
|
functionProperty.mapToItem(newItem, nodes);
|
||||||
|
}
|
||||||
|
|
||||||
|
// get indicies of creators and add
|
||||||
|
var creatorLists = {};
|
||||||
|
var creatorsAdded = {};
|
||||||
|
for(var i in nodes) {
|
||||||
|
for(var j in CREATOR_LISTS) {
|
||||||
|
var statements = Zotero.RDF.getStatementsMatching(nodes[i], CREATOR_LISTS[j], null);
|
||||||
|
for each(var stmt in statements) {
|
||||||
|
var creatorListURI = Zotero.RDF.getResourceURI(stmt[2]);
|
||||||
|
if(creatorLists[creatorListURI]) continue;
|
||||||
|
creatorLists[creatorListURI] = true;
|
||||||
|
var creatorNodes = Zotero.RDF.getContainerElements(stmt[2]);
|
||||||
|
for each(var creatorNode in creatorNodes) {
|
||||||
|
var creatorNodeURI = Zotero.RDF.getResourceURI(creatorNode);
|
||||||
|
if(!creatorsAdded[creatorNodeURI]) {
|
||||||
|
creatorsAdded[creatorNodeURI] = true;
|
||||||
|
if(allCreators[creatorNodeURI]) {
|
||||||
|
// just add to creators list
|
||||||
|
newItem.creators.push(allCreators[creatorNodeURI]);
|
||||||
|
} else {
|
||||||
|
// creator not already processed, use default for this list type
|
||||||
|
if(j == AUTHOR_LIST) {
|
||||||
|
Zotero.debug("WARNING: creator in authorList lacks relationship to item in Bibliontology RDF; treating as primary creator");
|
||||||
|
var prop = new CreatorProperty("author");
|
||||||
|
} else if(j == EDITOR_LIST) {
|
||||||
|
Zotero.debug("WARNING: creator in editorList lacks relationship to item in Bibliontology RDF; treating as editor");
|
||||||
|
var prop = new CreatorProperty("editor");
|
||||||
|
} else {
|
||||||
|
Zotero.debug("WARNING: creator in contributorList lacks relationship to item in Bibliontology RDF; treating as contributor");
|
||||||
|
var prop = new CreatorProperty("contributor");
|
||||||
|
}
|
||||||
|
var creator = prop.mapToCreator(creatorNode, zoteroType);
|
||||||
|
if(creator) newItem.creators.push(creator);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(var creatorNodeURI in allCreators) {
|
||||||
|
if(!creatorsAdded[creatorNodeURI]) {
|
||||||
|
newItem.creators.push(allCreators[creatorNodeURI]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Zotero.debug(newItem);
|
||||||
|
newItem.complete();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** EXPORT FUNCTIONS **/
|
||||||
|
|
||||||
|
var usedURIs = {};
|
||||||
|
|
||||||
|
function doExport() {
|
||||||
|
// add namespaces
|
||||||
|
[Zotero.RDF.addNamespace(i, n[i]) for(i in n)];
|
||||||
|
|
||||||
|
// compile references and create URIs
|
||||||
|
var item;
|
||||||
|
var items = {};
|
||||||
|
while(item = Zotero.nextItem()) {
|
||||||
|
items[item.itemID] = item;
|
||||||
|
}
|
||||||
|
|
||||||
|
// now that we've collected our items, start building the RDF
|
||||||
|
for each(var item in items) {
|
||||||
|
Zotero.debug(item);
|
||||||
|
// set type on item node
|
||||||
|
var type = new Type(item.itemType, TYPES[item.itemType]);
|
||||||
|
var nodes = type.createNodes(item);
|
||||||
|
Zotero.debug(nodes);
|
||||||
|
|
||||||
|
// add fields
|
||||||
|
for(var field in item.uniqueFields) {
|
||||||
|
if(item.uniqueFields[field] == "") continue;
|
||||||
|
|
||||||
|
var property = new LiteralProperty(field);
|
||||||
|
property.mapFromItem(item, nodes);
|
||||||
|
}
|
||||||
|
Zotero.debug("fields added");
|
||||||
|
|
||||||
|
// add creators
|
||||||
|
var creatorLists = [];
|
||||||
|
for each(var creator in item.creators) {
|
||||||
|
// create creator
|
||||||
|
var property = new CreatorProperty(creator.creatorType);
|
||||||
|
property.mapFromCreator(item, creator, nodes);
|
||||||
|
}
|
||||||
|
Zotero.debug("creators added");
|
||||||
|
|
||||||
|
type.addNodeRelations(nodes);
|
||||||
|
Zotero.debug("relations added");
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in a new issue