// Copyright 2013 Michel Kraemer // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. package de.undercouch.citeproc.zotero; import java.util.LinkedHashSet; import java.util.Set; import de.undercouch.citeproc.CSLDateParser; import de.undercouch.citeproc.ItemDataProvider; import de.undercouch.citeproc.ListItemDataProvider; import de.undercouch.citeproc.csl.CSLDate; import de.undercouch.citeproc.csl.CSLItemData; import de.undercouch.citeproc.csl.CSLItemDataBuilder; import de.undercouch.citeproc.csl.CSLName; import de.undercouch.citeproc.helper.StringHelper; /** * A item data provider that translates Zotero IDs to human-readable * citations IDs * @author Michel Kraemer */ public class ZoteroItemDataProvider extends ListItemDataProvider { /** * Creates a data provider that copies items from the given provider * but replaces item IDs with human-readable IDs * @param provider the provider to copy the items from */ public ZoteroItemDataProvider(ItemDataProvider provider) { super(sanitizeItems(provider)); } /** * Copies all items from the given provider and sanitizes its IDs * @param provider the provider * @return the sanitized items */ private static CSLItemData[] sanitizeItems(ItemDataProvider provider) { Set<String> knownIds = new LinkedHashSet<>(); //create a date parser which will be used to get the item's year CSLDateParser dateParser = new CSLDateParser(); //iterate through all items String[] ids = provider.getIds(); CSLItemData[] result = new CSLItemData[ids.length]; for (int i = 0; i < ids.length; ++i) { String id = ids[i]; CSLItemData item = provider.retrieveItem(id); //create a new ID String newId = makeId(item, dateParser); //make ID unique newId = uniquify(newId, knownIds); knownIds.add(newId); //copy item and replace ID item = new CSLItemDataBuilder(item).id(newId).build(); result[i] = item; } return result; } /** * Generates a human-readable ID for an item * @param item the item * @param dateParser a date parser * @return the human-readable ID */ private static String makeId(CSLItemData item, CSLDateParser dateParser) { if (item.getAuthor() == null || item.getAuthor().length == 0) { //there's no author information, return original ID return item.getId(); } //get author's name CSLName firstAuthor = item.getAuthor()[0]; String a = firstAuthor.getFamily(); if (a == null || a.isEmpty()) { a = firstAuthor.getGiven(); if (a == null || a.isEmpty()) { a = firstAuthor.getLiteral(); if (a == null || a.isEmpty()) { //author could not be found, return original ID return item.getId(); } } } a = StringHelper.sanitize(a); //try to get year int year = getYear(item.getIssued(), dateParser); if (year < 0) { year = getYear(item.getContainer(), dateParser); if (year < 0) { year = getYear(item.getOriginalDate(), dateParser); if (year < 0) { year = getYear(item.getEventDate(), dateParser); if (year < 0) { year = getYear(item.getSubmitted(), dateParser); } } } } //append year to author if (year >= 0) { a = a + year; } return a; } /** * Makes the given ID unique * @param id the ID * @param knownIds a set of known IDs to compare to * @return the unique IDs */ private static String uniquify(String id, Set<String> knownIds) { int n = 10; String olda = id; while (knownIds.contains(id)) { id = olda + Integer.toString(n, Character.MAX_RADIX); ++n; } return id; } /** * Retrieves the year from a {@link CSLDate} object. Parses the raw * string if necessary. * @param date the date object * @param dateParser a date parser * @return the year or -1 if the year could not be retrieved */ private static int getYear(CSLDate date, CSLDateParser dateParser) { if (date == null) { return -1; } if (date.getDateParts() == null || date.getDateParts().length == 0 || date.getDateParts()[0] == null || date.getDateParts()[0].length == 0) { if (date.getRaw() != null && !date.getRaw().isEmpty()) { CSLDate d = dateParser.parse(date.getRaw()); return getYear(d, dateParser); } return -1; } return date.getDateParts()[0][0]; } }