-
-
Notifications
You must be signed in to change notification settings - Fork 2.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Added option to import CFF files #7946
Changes from 2 commits
32f7297
4ddc414
119c943
b9d3da4
44dd028
78eb210
f4bb7e4
33329c8
4a9d13d
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,155 @@ | ||
package org.jabref.logic.importer.fileformat; | ||
|
||
import java.io.BufferedReader; | ||
import java.io.IOException; | ||
import java.util.ArrayList; | ||
import java.util.HashMap; | ||
import java.util.List; | ||
import java.util.Map; | ||
|
||
import org.jabref.logic.importer.Importer; | ||
import org.jabref.logic.importer.ParserResult; | ||
import org.jabref.logic.util.StandardFileType; | ||
import org.jabref.model.entry.BibEntry; | ||
import org.jabref.model.entry.field.Field; | ||
import org.jabref.model.entry.field.StandardField; | ||
import org.jabref.model.entry.types.StandardEntryType; | ||
|
||
import com.fasterxml.jackson.annotation.JsonAnySetter; | ||
import com.fasterxml.jackson.annotation.JsonProperty; | ||
import com.fasterxml.jackson.databind.ObjectMapper; | ||
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory; | ||
import org.slf4j.Logger; | ||
import org.slf4j.LoggerFactory; | ||
|
||
public class CffImporter extends Importer { | ||
private static final Logger LOGGER = LoggerFactory.getLogger(CffImporter.class); | ||
|
||
@Override | ||
public String getName() { | ||
return "CFF"; | ||
} | ||
|
||
@Override | ||
public StandardFileType getFileType() { | ||
return StandardFileType.CFF; | ||
} | ||
|
||
@Override | ||
public String getId() { | ||
return "cff"; | ||
} | ||
|
||
@Override | ||
public String getDescription() { | ||
return "Importer for the CFF format. Is only used to cite software, one entry per file."; | ||
} | ||
|
||
private static class CffFormat { | ||
private HashMap<String, String> vals = new HashMap<String, String>(); | ||
|
||
@JsonProperty("authors") | ||
private List<CffAuthor> authors; | ||
|
||
public CffFormat() { | ||
} | ||
|
||
@JsonAnySetter | ||
private void setValues(String key, String value) { | ||
vals.put(key, value); | ||
} | ||
} | ||
|
||
private static class CffAuthor { | ||
private HashMap<String, String> vals = new HashMap<String, String>(); | ||
|
||
public CffAuthor() { | ||
} | ||
|
||
@JsonAnySetter | ||
private void setValues(String key, String value) { | ||
vals.put(key, value); | ||
} | ||
|
||
} | ||
|
||
@Override | ||
public ParserResult importDatabase(BufferedReader reader) throws IOException { | ||
ObjectMapper mapper = new ObjectMapper(new YAMLFactory()); | ||
CffFormat citation = mapper.readValue(reader, CffFormat.class); | ||
HashMap<Field, String> entryMap = new HashMap<Field, String>(); | ||
|
||
HashMap<String, StandardField> fieldMap = getFieldMappings(); | ||
for (Map.Entry<String, String> property : citation.vals.entrySet()) { | ||
if (fieldMap.containsKey(property.getKey())) { | ||
entryMap.put(fieldMap.get(property.getKey()), property.getValue()); | ||
} | ||
} | ||
|
||
List<String> authors = new ArrayList<String>(); | ||
for (CffAuthor auth: citation.authors) { | ||
String aName = auth.vals.get("name"); | ||
String aGivenNames = auth.vals.get("given-names"); | ||
String aFamilyNames = auth.vals.get("family-names"); | ||
String aNameParticle = auth.vals.get("name-particle"); | ||
String aAlias = auth.vals.get("alias"); | ||
|
||
if (aName != null) { | ||
authors.add(aName); | ||
} else if (aFamilyNames != null && aNameParticle != null && aGivenNames != null) { | ||
authors.add(aGivenNames + " " + aNameParticle + " " + aFamilyNames); | ||
} else if (aFamilyNames != null && aGivenNames != null) { | ||
authors.add(aGivenNames + " " + aFamilyNames); | ||
} else if (aFamilyNames != null) { | ||
authors.add(aFamilyNames); | ||
} else if (aAlias != null) { | ||
authors.add(aAlias); | ||
} | ||
} | ||
|
||
String authorStr = String.join(", ", authors); | ||
entryMap.put(StandardField.AUTHOR, authorStr); | ||
|
||
BibEntry entry = new BibEntry(StandardEntryType.Software); | ||
entry.setField(entryMap); | ||
|
||
List<BibEntry> entriesList = new ArrayList<BibEntry>(); | ||
entriesList.add(entry); | ||
|
||
return new ParserResult(entriesList); | ||
} | ||
|
||
@Override | ||
public boolean isRecognizedFormat(BufferedReader reader) throws IOException { | ||
|
||
ObjectMapper mapper = new ObjectMapper(new YAMLFactory()); | ||
CffFormat citation; | ||
|
||
try { | ||
citation = mapper.readValue(reader, CffFormat.class); | ||
} catch (IOException e) { | ||
return false; | ||
} | ||
|
||
if (citation != null && citation.vals.get("title") != null) { | ||
calixtus marked this conversation as resolved.
Show resolved
Hide resolved
|
||
return true; | ||
} else { | ||
return false; | ||
} | ||
} | ||
|
||
private HashMap<String, StandardField> getFieldMappings() { | ||
HashMap<String, StandardField> hm = new HashMap<String, StandardField>(); | ||
calixtus marked this conversation as resolved.
Show resolved
Hide resolved
|
||
hm.put("title", StandardField.TITLE); | ||
hm.put("version", StandardField.VERSION); | ||
hm.put("doi", StandardField.DOI); | ||
hm.put("license", StandardField.LICENSE); | ||
hm.put("repository", StandardField.REPOSITORY); | ||
hm.put("url", StandardField.URL); | ||
hm.put("abstract", StandardField.ABSTRACT); | ||
hm.put("message", StandardField.COMMENT); | ||
hm.put("date-released", StandardField.DATE); | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For fields that can't be mapped, you can simply create a new UnkownField: (example is taken from the MSBibImporter) JabRef can show non-standard fields in the entry editor as well There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I think there should be a better solution than prefixing those fields, since none of the citation styles would pick them up - but you might want to have the repository printed in the reference list. I've started a discussion at the biblatex repo how to handle those fields: plk/biblatex#1169 |
||
return hm; | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,86 @@ | ||
package org.jabref.logic.importer.fileformat; | ||
|
||
import java.io.IOException; | ||
import java.net.URISyntaxException; | ||
import java.nio.charset.StandardCharsets; | ||
import java.nio.file.Path; | ||
import java.util.Arrays; | ||
import java.util.List; | ||
import java.util.Optional; | ||
|
||
import org.jabref.logic.util.StandardFileType; | ||
import org.jabref.model.entry.BibEntry; | ||
import org.jabref.model.entry.field.StandardField; | ||
|
||
import org.junit.jupiter.api.BeforeEach; | ||
import org.junit.jupiter.api.Test; | ||
|
||
import static org.junit.jupiter.api.Assertions.assertEquals; | ||
import static org.junit.jupiter.api.Assertions.assertFalse; | ||
import static org.junit.jupiter.api.Assertions.assertTrue; | ||
|
||
public class CffImporterTest { | ||
|
||
private CffImporter importer; | ||
|
||
@BeforeEach | ||
public void setUp() { | ||
importer = new CffImporter(); | ||
} | ||
|
||
@Test | ||
public void testGetFormatName() { | ||
assertEquals("CFF", importer.getName()); | ||
} | ||
|
||
@Test | ||
public void testGetCLIId() { | ||
assertEquals("cff", importer.getId()); | ||
} | ||
|
||
@Test | ||
public void testsGetExtensions() { | ||
assertEquals(StandardFileType.CFF, importer.getFileType()); | ||
} | ||
|
||
@Test | ||
public void testGetDescription() { | ||
assertEquals("Importer for the CFF format. Is only used to cite software, one " | ||
+ "entry per file.", importer.getDescription()); | ||
} | ||
|
||
@Test | ||
public void testIsRecognizedFormat() throws IOException, URISyntaxException { | ||
Path file = Path.of(CffImporterTest.class.getResource("CffImporterTestValid.cff").toURI()); | ||
assertTrue(importer.isRecognizedFormat(file, StandardCharsets.UTF_8)); | ||
} | ||
|
||
@Test | ||
public void testIsRecognizedFormatReject() throws IOException, URISyntaxException { | ||
List<String> list = Arrays.asList("CffImporterTestInvalid1.cff", "CffImporterTestInvalid2.cff"); | ||
|
||
for (String string : list) { | ||
Path file = Path.of(CffImporterTest.class.getResource(string).toURI()); | ||
assertFalse(importer.isRecognizedFormat(file, StandardCharsets.UTF_8)); | ||
} | ||
} | ||
|
||
@Test | ||
public void testImportEntries() throws IOException, URISyntaxException { | ||
Path file = Path.of(CffImporterTest.class.getResource("CffImporterTestValid.cff").toURI()); | ||
List<BibEntry> bibEntries = importer.importDatabase(file, StandardCharsets.UTF_8).getDatabase().getEntries(); | ||
BibEntry entry = bibEntries.get(0); | ||
|
||
assertEquals(entry.getField(StandardField.AUTHOR), Optional.of("Joe van Smith")); | ||
assertEquals(entry.getField(StandardField.TITLE), Optional.of("Test")); | ||
assertEquals(entry.getField(StandardField.URL), Optional.of("www.google.com")); | ||
assertEquals(entry.getField(StandardField.REPOSITORY), Optional.of("www.github.com")); | ||
assertEquals(entry.getField(StandardField.DOI), Optional.of("10.0000/TEST")); | ||
assertEquals(entry.getField(StandardField.DATE), Optional.of("2000-07-02")); | ||
assertEquals(entry.getField(StandardField.COMMENT), Optional.of("Test entry.")); | ||
assertEquals(entry.getField(StandardField.ABSTRACT), Optional.of("Test abstract.")); | ||
assertEquals(entry.getField(StandardField.LICENSE), Optional.of("MIT")); | ||
assertEquals(entry.getField(StandardField.VERSION), Optional.of("1.0")); | ||
|
||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,4 @@ | ||
# YAML 1.2 | ||
--- | ||
test: 123 | ||
... |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
aosdoioifjosdfikbasjc |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
# YAML 1.2 | ||
--- | ||
abstract: "Test abstract." | ||
authors: | ||
- | ||
family-names: Smith | ||
given-names: Joe | ||
name-particle: van | ||
cff-version: "1.1.0" | ||
date-released: 2000-07-02 | ||
doi: "10.0000/TEST" | ||
identifiers: | ||
license: MIT | ||
message: "Test entry." | ||
title: Test | ||
version: "1.0" | ||
url: "www.google.com" | ||
repository: "www.github.com" | ||
... |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JabRef has a class called Author which will handle the construction of authors, see org.jabref.model.entry
public Author(String first, String firstabbr, String von, String last, String jr)
Afterwards, you put in an AuthorLIst and return the and separated value
See for example the Medra-Fetcher (org.jabref.logic.importer.fetcher)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Apart from
String firstabbr
, CFF has the same fields forperson
type objects (e.g., authors). The main difference between these and theentity
type objects (for this use case at least) is that entities only have a single fieldname
instead, which I guess could be imported as is?There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
first
->given-names
von
->name-particle
last
->family-names
jr
->name-suffix
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yep, that seems to be correct, for reference:
jabref/src/main/java/org/jabref/model/entry/Author.java
Lines 22 to 31 in cef4151