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
Fetching contributors…
Cannot retrieve contributors at this time
{ | |
"translatorID": "14763d24-8ba0-45df-8f52-b8d1108e7ac9", | |
"translatorType": 2, | |
"label": "Zotero RDF", | |
"creator": "Simon Kornblith", | |
"target": "rdf", | |
"minVersion": "1.0.0b4.r1", | |
"maxVersion": "", | |
"priority": 25, | |
"configOptions": { | |
"getCollections": "true", | |
"dataMode": "rdf/xml" | |
}, | |
"displayOptions": { | |
"exportNotes": true, | |
"exportFileData": false | |
}, | |
"inRepository": true, | |
"lastUpdated": "2019-01-14 05:55:13" | |
} | |
var item; | |
var rdf = "http://www.w3.org/1999/02/22-rdf-syntax-ns#"; | |
var n = { | |
bib:"http://purl.org/net/biblio#", | |
dc:"http://purl.org/dc/elements/1.1/", | |
dcterms:"http://purl.org/dc/terms/", | |
prism:"http://prismstandard.org/namespaces/1.2/basic/", | |
foaf:"http://xmlns.com/foaf/0.1/", | |
vcard:"http://nwalsh.com/rdf/vCard#", | |
vcard2:"http://www.w3.org/2006/vcard/ns#", // currently used only for NSF, but is probably | |
// very similar to the nwalsh vcard ontology in a | |
// different namespace | |
link:"http://purl.org/rss/1.0/modules/link/", | |
z:"http://www.zotero.org/namespaces/export#" | |
}; | |
function generateRelations(resource, relations) { | |
for (let predicate in relations) { | |
if (predicate == 'dc:relation') { | |
for (let uri of relations[predicate]) { | |
if (itemResources[uri]) { | |
Zotero.RDF.addStatement(resource, n.dc + "relation", itemResources[uri], false); | |
} | |
} | |
} | |
} | |
} | |
function generateTags(resource, tags) { | |
Zotero.debug("processing tags"); | |
for (var i=0; i<tags.length; i++) { | |
var tag = tags[i]; | |
if (tag.type == 1) { | |
var tagResource = Zotero.RDF.newResource(); | |
// set tag type and value | |
Zotero.RDF.addStatement(tagResource, rdf+"type", n.z+"AutomaticTag", false); | |
Zotero.RDF.addStatement(tagResource, rdf+"value", tag.tag, true); | |
// add relationship to resource | |
Zotero.RDF.addStatement(resource, n.dc+"subject", tagResource, false); | |
} else { | |
Zotero.RDF.addStatement(resource, n.dc+"subject", tag.tag, true); | |
} | |
} | |
} | |
function generateCollection(collection) { | |
var collectionResource = "#collection_"+collection.id; | |
Zotero.RDF.addStatement(collectionResource, rdf+"type", n.z+"Collection", false); | |
Zotero.RDF.addStatement(collectionResource, n.dc+"title", collection.name, true); | |
var children = collection.children ? collection.children : collection.descendents; | |
if (!children) return; | |
for (var i=0; i<children.length; i++) { | |
var child = children[i]; | |
// add child list items | |
if (child.type == "collection") { | |
Zotero.RDF.addStatement(collectionResource, n.dcterms+"hasPart", "#collection_"+child.id, false); | |
// do recursive processing of collections | |
generateCollection(child); | |
} else if (itemResources[child.id]) { | |
Zotero.RDF.addStatement(collectionResource, n.dcterms+"hasPart", itemResources[child.id], false); | |
} | |
} | |
} | |
/** | |
* Get display title | |
* Analogous to getDisplayTitle in item.js, but returns null if no display title distinct from | |
* title property | |
*/ | |
function getDisplayTitle(item) { | |
if (!item.title && (item.itemType == "interview" || item.itemType == "letter")) { | |
var participants = []; | |
for (var i=0; i<item.creators.length; i++) { | |
var creator = item.creators[i]; | |
if (item.itemType == "letter" && creator.creatorType == "recipient" || | |
item.itemType == "interview" && creator.creatorType == "interviewer") { | |
participants.push(creator); | |
} | |
} | |
var displayTitle = "["+(item.itemType == "letter" ? "Letter" : "Interview"); | |
if (participants.length) { | |
//var names = [creator.firstName ? creator.firstName+" "+creator.lastName : creator.lastName | |
var names = []; | |
for (var i=0; i<participants.length; i++) { | |
names.push(participants[i].lastName); | |
} | |
displayTitle += (item.itemType == "letter" ? " to " : " of ")+names[0]; | |
if (participants.length == 2) { | |
displayTitle += " and "+names[1]; | |
} else if (participants.length == 3) { | |
displayTitle += ", "+names[1]+", and "+names[2]; | |
} else if (participants.length > 3) { | |
displayTitle += " et al."; | |
} | |
} | |
return displayTitle+"]"; | |
} if (item.itemType == "case" && item.title && item.reporter) { // 'case' itemTypeID | |
return item.title+' (' + item.reporter + ')'; | |
} | |
return null; | |
} | |
function generateItem(item, zoteroType, resource) { | |
var container = null; | |
var containerElement = null; | |
/** CORE FIELDS **/ | |
// type | |
var type = null; | |
if (zoteroType == "book") { | |
type = n.bib+"Book"; | |
} else if (zoteroType == "bookSection") { | |
type = n.bib+"BookSection"; | |
container = n.bib+"Book"; | |
} else if (zoteroType == "journalArticle") { | |
type = n.bib+"Article"; | |
container = n.bib+"Journal"; | |
} else if (zoteroType == "magazineArticle") { | |
type = n.bib+"Article"; | |
container = n.bib+"Periodical"; | |
} else if (zoteroType == "newspaperArticle") { | |
type = n.bib+"Article"; | |
container = n.bib+"Newspaper"; | |
} else if (zoteroType == "thesis") { | |
type = n.bib+"Thesis"; | |
} else if (zoteroType == "letter") { | |
type = n.bib+"Letter"; | |
} else if (zoteroType == "manuscript") { | |
type = n.bib+"Manuscript"; | |
} else if (zoteroType == "interview") { | |
type = n.bib+"Interview"; | |
} else if (zoteroType == "film") { | |
type = n.bib+"MotionPicture"; | |
} else if (zoteroType == "artwork") { | |
type = n.bib+"Illustration"; | |
} else if (zoteroType == "webpage") { | |
type = n.bib+"Document"; | |
container = n.z+"Website"; | |
} else if (zoteroType == "note") { | |
type = n.bib+"Memo"; | |
if (!Zotero.getOption("exportNotes")) { | |
return; | |
} | |
} else if (zoteroType == "attachment") { | |
type = n.z+"Attachment"; | |
} else if (zoteroType == "report") { | |
type = n.bib+"Report"; | |
} else if (zoteroType == "bill") { | |
type = n.bib+"Legislation"; | |
} else if (zoteroType == "case") { | |
type = n.bib+"Document"; // ?? | |
container = n.bib+"CourtReporter"; | |
} else if (zoteroType == "hearing") { | |
type = n.bib+"Report"; | |
} else if (zoteroType == "patent") { | |
type = n.bib+"Patent"; | |
} else if (zoteroType == "statute") { | |
type = n.bib+"Legislation"; | |
} else if (zoteroType == "email") { | |
type = n.bib+"Letter"; | |
} else if (zoteroType == "map") { | |
type = n.bib+"Image"; | |
} else if (zoteroType == "blogPost") { | |
type = n.bib+"Document"; | |
container = n.z+"Blog"; | |
} else if (zoteroType == "instantMessage") { | |
type = n.bib+"Letter"; | |
} else if (zoteroType == "forumPost") { | |
type = n.bib+"Document"; | |
container = n.z+"Forum"; | |
} else if (zoteroType == "audioRecording") { | |
type = n.bib+"Recording"; | |
} else if (zoteroType == "presentation") { | |
type = n.bib+"ConferenceProceedings"; | |
} else if (zoteroType == "videoRecording") { | |
type = n.bib+"Recording"; | |
} else if (zoteroType == "tvBroadcast") { | |
type = n.bib+"Recording"; | |
} else if (zoteroType == "radioBroadcast") { | |
type = n.bib+"Recording"; | |
} else if (zoteroType == "podcast") { | |
type = n.bib+"Recording"; | |
} else if (zoteroType == "computerProgram") { | |
type = n.bib+"Data"; | |
} else if (zoteroType == "encyclopediaArticle" | |
|| zoteroType == "dictionaryEntry") { | |
container = n.bib+"Book"; | |
} else if (zoteroType == "conferencePaper") { | |
container = n.bib+"Journal"; | |
} | |
if (type) { | |
Zotero.RDF.addStatement(resource, rdf+"type", type, false); | |
} | |
Zotero.RDF.addStatement(resource, n.z+"itemType", zoteroType, true); | |
// generate section | |
if (item.section) { | |
var section = Zotero.RDF.newResource(); | |
// set section type | |
Zotero.RDF.addStatement(section, rdf+"type", n.bib+"Part", false); | |
// set section title | |
Zotero.RDF.addStatement(section, n.dc+"title", item.section, true); | |
// add relationship to resource | |
Zotero.RDF.addStatement(resource, n.dcterms+"isPartOf", section, false); | |
} | |
// generate container | |
if (container) { | |
var testISSN = "urn:issn:"+encodeURI(item.ISSN); | |
if (item.ISSN && !Zotero.RDF.getArcsIn(testISSN)) { | |
// use ISSN as container URI if no other item is | |
containerElement = testISSN; | |
} else { | |
containerElement = Zotero.RDF.newResource(); | |
} | |
// attach container to section (if exists) or resource | |
Zotero.RDF.addStatement((section ? section : resource), n.dcterms+"isPartOf", containerElement, false); | |
// add container type | |
Zotero.RDF.addStatement(containerElement, rdf+"type", container, false); | |
} | |
// generate series | |
if (item.series || item.seriesTitle || item.seriesText || item.seriesNumber) { | |
var series = Zotero.RDF.newResource(); | |
// set series type | |
Zotero.RDF.addStatement(series, rdf+"type", n.bib+"Series", false); | |
// add relationship to resource | |
Zotero.RDF.addStatement((containerElement ? containerElement : resource), n.dcterms+"isPartOf", series, false); | |
} | |
// generate publisher | |
// BEGIN NSF | |
if (zoteroType == "nsfReviewer") { | |
var organization = Zotero.RDF.newResource(); | |
Zotero.RDF.addStatement(organization, rdf+"type", n.vcard2+"Organization", false); | |
Zotero.RDF.addStatement(resource, n.vcard2+"org", organization, false); | |
} else { | |
// END NSF | |
if (item.publisher || item.distributor || item.label || item.company || item.institution || item.place) { | |
var organization = Zotero.RDF.newResource(); | |
// set organization type | |
Zotero.RDF.addStatement(organization, rdf+"type", n.foaf+"Organization", false); | |
// add relationship to resource | |
Zotero.RDF.addStatement(resource, n.dc+"publisher", organization, false); | |
} | |
} | |
var typeProperties = ["reportType", "videoRecordingType", "letterType", | |
"manuscriptType", "mapType", "thesisType", "websiteType", | |
"audioRecordingType", "presentationType", "postType", | |
"audioFileType"]; | |
var ignoreProperties = ["itemID", "itemType", "firstCreator", "dateAdded", | |
"dateModified", "section", "sourceItemID"]; | |
// creators | |
if (item.creators) { // authors/editors/contributors | |
var creatorContainers = new Object(); | |
// not yet in biblio | |
var biblioCreatorTypes = ["author", "editor", "contributor"]; | |
for (var j in item.creators) { | |
var creator = Zotero.RDF.newResource(); | |
Zotero.RDF.addStatement(creator, rdf+"type", n.foaf+"Person", false); | |
// gee. an entire vocabulary for describing people, and these aren't even | |
// standardized in it. oh well. using them anyway. | |
Zotero.RDF.addStatement(creator, n.foaf+"surname", item.creators[j].lastName, true); | |
if (item.creators[j].firstName) { | |
Zotero.RDF.addStatement(creator, n.foaf+"givenname", item.creators[j].firstName, true); | |
} | |
if (biblioCreatorTypes.indexOf(item.creators[j].creatorType) != -1) { | |
var cTag = n.bib+item.creators[j].creatorType+"s"; | |
} else { | |
var cTag = n.z+item.creators[j].creatorType+"s"; | |
} | |
if (!creatorContainers[cTag]) { | |
var creatorResource = Zotero.RDF.newResource(); | |
// create new seq for author type | |
creatorContainers[cTag] = Zotero.RDF.newContainer("seq", creatorResource); | |
// attach container to resource | |
Zotero.RDF.addStatement(resource, cTag, creatorResource, false); | |
} | |
Zotero.RDF.addContainerElement(creatorContainers[cTag], creator, false); | |
} | |
} | |
// notes | |
if (item.notes && Zotero.getOption("exportNotes")) { | |
for (let note of item.notes) { | |
let noteResource = itemResources[note.itemID]; | |
// add note tag | |
Zotero.RDF.addStatement(noteResource, rdf+"type", n.bib+"Memo", false); | |
// add note item.notes | |
Zotero.RDF.addStatement(noteResource, rdf + "value", note.note, true); | |
// add relationship between resource and note | |
Zotero.RDF.addStatement(resource, n.dcterms+"isReferencedBy", noteResource, false); | |
// Add note relations to RDF | |
if (note.relations) generateRelations(noteResource, note.relations); | |
generateTags(noteResource, note.tags); | |
} | |
} | |
// child attachments | |
if (item.attachments) { | |
for (var i=0; i<item.attachments.length; i++) { | |
var attachment = item.attachments[i]; | |
var attachmentResource = itemResources[attachment.itemID]; | |
Zotero.RDF.addStatement(resource, n.link+"link", attachmentResource, false); | |
generateItem(attachment, "attachment", attachmentResource); | |
} | |
} | |
// relative file path for attachment items | |
if (item.defaultPath) { // For Zotero 3.0 | |
item.saveFile(item.defaultPath, true); | |
Zotero.RDF.addStatement(resource, rdf+"resource", item.defaultPath, false); | |
} else if (item.path) { // For Zotero 2.1 | |
Zotero.RDF.addStatement(resource, rdf+"resource", item.path, false); | |
} | |
// Related items and tags | |
if (item.relations) generateRelations(resource, item.relations); | |
if (item.tags) generateTags(resource, item.tags); | |
for (var property in item.uniqueFields) { | |
var value = item[property]; | |
if (!value) continue; | |
if (property == "title") { // title | |
// BEGIN NSF | |
if (zoteroType == "nsfReviewer") { | |
Zotero.RDF.addStatement(resource, n.vcard2+"fn", value, true); | |
} else { | |
// END NSF | |
Zotero.RDF.addStatement(resource, n.dc+"title", value, true); | |
} | |
} else if (property == "source") { // authors/editors/contributors | |
Zotero.RDF.addStatement(resource, n.dc+"source", value, true); | |
} else if (property == "url") { // url | |
// BEGIN NSF | |
if (item.homepage) { | |
Zotero.RDF.addStatement(resource, n.vcard2+"url", value, false); | |
} else { | |
// END NSF | |
// add url as identifier | |
var term = Zotero.RDF.newResource(); | |
// set term type | |
Zotero.RDF.addStatement(term, rdf+"type", n.dcterms+"URI", false); | |
// set url value | |
Zotero.RDF.addStatement(term, rdf+"value", value, true); | |
// add relationship to resource | |
Zotero.RDF.addStatement(resource, n.dc+"identifier", term, false); | |
} | |
} else if (property == "accessionNumber") { // accessionNumber as generic ID | |
Zotero.RDF.addStatement(resource, n.dc+"identifier", value, true); | |
} else if (property == "rights") { // rights | |
Zotero.RDF.addStatement(resource, n.dc+"rights", value, true); | |
} else if (property == "edition" || // edition | |
property == "version") { // version | |
Zotero.RDF.addStatement(resource, n.prism+"edition", value, true); | |
} else if (property == "date") { // date | |
if (item.dateSent) { | |
Zotero.RDF.addStatement(resource, n.dcterms+"dateSubmitted", value, true); | |
} else { | |
Zotero.RDF.addStatement(resource, n.dc+"date", value, true); | |
} | |
} else if (property == "accessDate") { // accessDate | |
Zotero.RDF.addStatement(resource, n.dcterms+"dateSubmitted", value, true); | |
} else if (property == "issueDate") { // issueDate | |
Zotero.RDF.addStatement(resource, n.dcterms+"issued", value, true); | |
} else if (property == "pages") { // pages | |
// not yet part of biblio, but should be soon | |
Zotero.RDF.addStatement(resource, n.bib+"pages", value, true); | |
} else if (property == "extra") { // extra | |
Zotero.RDF.addStatement(resource, n.dc+"description", value, true); | |
} else if (property == "mimeType") { // mimeType | |
Zotero.RDF.addStatement(resource, n.link+"type", value, true); | |
} else if (property == "charset") { // charset | |
Zotero.RDF.addStatement(resource, n.link+"charset", value, true); | |
// THE FOLLOWING ARE ALL PART OF THE CONTAINER | |
} else if (property == "ISSN") { // ISSN | |
Zotero.RDF.addStatement((containerElement ? containerElement : resource), n.dc+"identifier", "ISSN "+value, true); | |
} else if (property == "ISBN") { // ISBN | |
Zotero.RDF.addStatement((containerElement ? containerElement : resource), n.dc+"identifier", "ISBN "+value, true); | |
} else if (property == "DOI") { // DOI | |
Zotero.RDF.addStatement((containerElement ? containerElement : resource), n.dc+"identifier", "DOI "+value, true); | |
} else if (property == "publicationTitle" || // publicationTitle | |
property == "reporter") { // reporter | |
Zotero.RDF.addStatement((containerElement ? containerElement : resource), n.dc+"title", value, true); | |
} else if (property == "journalAbbreviation") { // journalAbbreviation | |
Zotero.RDF.addStatement((containerElement ? containerElement : resource), n.dcterms+"alternative", value, true); | |
} else if (property == "volume") { // volume | |
Zotero.RDF.addStatement((containerElement ? containerElement : resource), n.prism+"volume", value, true); | |
} else if (property == "issue" || // issue | |
property == "number" || // number | |
property == "patentNumber") { // patentNumber | |
Zotero.RDF.addStatement((containerElement ? containerElement : resource), n.prism+"number", value, true); | |
} else if (property == "callNumber") { | |
var term = Zotero.RDF.newResource(); | |
// set term type | |
Zotero.RDF.addStatement(term, rdf+"type", n.dcterms+"LCC", false); | |
// set callNumber value | |
Zotero.RDF.addStatement(term, rdf+"value", value, true); | |
// add relationship to resource | |
Zotero.RDF.addStatement(resource, n.dc+"subject", term, false); | |
} else if (property == "abstractNote") { | |
Zotero.RDF.addStatement(resource, n.dcterms+"abstract", value, true); | |
// THE FOLLOWING ARE ALL PART OF THE SERIES | |
} else if (property == "series") { // series | |
Zotero.RDF.addStatement(series, n.dc+"title", value, true); | |
} else if (property == "seriesTitle") { // seriesTitle | |
Zotero.RDF.addStatement(series, n.dcterms+"alternative", value, true); | |
} else if (property == "seriesText") { // seriesText | |
Zotero.RDF.addStatement(series, n.dc+"description", value, true); | |
} else if (property == "seriesNumber") { // seriesNumber | |
Zotero.RDF.addStatement(series, n.dc+"identifier", value, true); | |
// THE FOLLOWING ARE ALL PART OF THE PUBLISHER | |
} else if (property == "publisher" || // publisher | |
property == "distributor" || // distributor (film) | |
property == "label" || // label (audioRecording) | |
property == "company" || // company (computerProgram) | |
property == "institution") { // institution (report) | |
// BEGIN NSF | |
if (zoteroType == "nsfReviewer") { | |
Zotero.RDF.addStatement(organization, n.vcard2+"organization-name", value, true); | |
} else { | |
// END NSF | |
Zotero.RDF.addStatement(organization, n.foaf+"name", value, true); | |
} | |
} else if (property == "place") { // place | |
var address = Zotero.RDF.newResource(); | |
// set address type | |
Zotero.RDF.addStatement(address, rdf+"type", n.vcard+"Address", false); | |
// set address locality | |
Zotero.RDF.addStatement(address, n.vcard+"locality", value, true); | |
// add relationship to organization | |
Zotero.RDF.addStatement(organization, n.vcard+"adr", address, false); | |
} else if (property == "archiveLocation") { // archiveLocation | |
Zotero.RDF.addStatement(resource, n.dc+"coverage", value, true); | |
} else if (property == "interviewMedium" || | |
property == "artworkMedium") { // medium | |
Zotero.RDF.addStatement(resource, n.dcterms+"medium", value, true); | |
} else if (property == "conferenceName") { | |
var conference = Zotero.RDF.newResource(); | |
// set conference type | |
Zotero.RDF.addStatement(conference, rdf+"type", n.bib+"Conference", false); | |
// set conference title | |
Zotero.RDF.addStatement(conference, n.dc+"title", value, true); | |
// add relationship to conference | |
Zotero.RDF.addStatement(resource, n.bib+"presentedAt", conference, false); | |
} else if (typeProperties.indexOf(property) != -1) { | |
Zotero.RDF.addStatement(resource, n.dc+"type", value, true); | |
// THE FOLLOWING RELATE TO NOTES | |
} else if (property == "note") { | |
if (Zotero.getOption("exportNotes")) { | |
if (item.itemType == "attachment") { | |
Zotero.RDF.addStatement(resource, n.dc+"description", value, true); | |
} else if (item.itemType == "note") { | |
Zotero.RDF.addStatement(resource, rdf+"value", value, true); | |
} | |
} | |
// BEGIN NSF | |
} else if (property == "address") { | |
var address = Zotero.RDF.newResource(); | |
Zotero.RDF.addStatement(address, rdf+"type", n.vcard2+"Address", false); | |
Zotero.RDF.addStatement(address, n.vcard2+"label", value, true); | |
Zotero.RDF.addStatement(resource, n.vcard2+"adr", address, false); | |
} else if (property == "telephone") { | |
Zotero.RDF.addStatement(resource, n.vcard2+"tel", value, true); | |
} else if (property == "email") { | |
Zotero.RDF.addStatement(resource, n.vcard2+"email", value, true); | |
} else if (property == "accepted") { | |
Zotero.RDF.addStatement(resource, n.dcterms+"dateAccepted", value, true); | |
// END NSF | |
// THIS CATCHES ALL REMAINING PROPERTIES | |
} else if (ignoreProperties.indexOf(property) == -1) { | |
Zotero.debug("Zotero RDF: using Zotero namespace for property "+property); | |
Zotero.RDF.addStatement(resource, n.z+property, value, true); | |
} | |
} | |
var displayTitle = getDisplayTitle(item); | |
if (displayTitle) Zotero.RDF.addStatement(resource, n.z+"displayTitle", displayTitle, true); | |
} | |
function doExport() { | |
// add namespaces | |
for (var i in n) { | |
Zotero.RDF.addNamespace(i, n[i]); | |
} | |
// leave as global | |
itemResources = new Array(); | |
// keep track of resources already assigned (in case two book items have the | |
// same ISBN, or something like that) | |
var usedResources = new Array(); | |
var items = new Array(); | |
// first, map each ID to a resource | |
while (item = Zotero.nextItem()) { | |
items.push(item); | |
Zotero.debug(item); | |
var testISBN = "urn:isbn:"+encodeURI(item.ISBN); | |
if (item.ISBN && !usedResources[testISBN]) { | |
itemResources[item.itemID] = itemResources[item.uri] = testISBN; | |
usedResources[itemResources[item.itemID]] = true; | |
} else if (item.itemType != "attachment" && item.url && !usedResources[item.url]) { | |
itemResources[item.itemID] = itemResources[item.uri] = item.url; | |
usedResources[itemResources[item.itemID]] = true; | |
} else { | |
// just specify a node ID | |
itemResources[item.itemID] = itemResources[item.uri] = "#item_" + item.itemID; | |
} | |
if (item.notes) { | |
for (var j in item.notes) { | |
itemResources[item.notes[j].itemID] = itemResources[item.notes[j].uri] = "#item_" + item.notes[j].itemID; | |
} | |
} | |
if (item.attachments) { | |
for (var i=0; i<item.attachments.length; i++) { | |
var attachment = item.attachments[i]; | |
// just specify a node ID | |
itemResources[attachment.itemID] = itemResources[attachment.uri] = "#item_" + attachment.itemID; | |
} | |
} | |
} | |
for (var i=0; i<items.length; i++) { | |
var item = items[i]; | |
// these items are global | |
generateItem(item, item.itemType, itemResources[item.itemID]); | |
} | |
/** RDF COLLECTION STRUCTURE **/ | |
var collection; | |
while (collection = Zotero.nextCollection()) { | |
generateCollection(collection); | |
} | |
} |