Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ Note that this project **does not** adhere to [Semantic Versioning](https://semv
- The `jabkit check` subcommands now support a `github-actions` output format that emits findings as [GitHub Actions workflow commands](https://docs.github.com/en/actions/writing-workflows/choosing-what-your-workflow-does/workflow-commands-for-github-actions#setting-an-error-message), so findings show up as annotations on pull requests. [#15789](https://github.com/JabRef/jabref/pull/15789)
- The `jabkit check` command now runs both the consistency and integrity checks when given an input file without a subcommand (e.g. `jabkit check references.bib`). [#15759](https://github.com/JabRef/jabref/pull/15759)
- We added OCR feature using OCRmyPDF to extract text from scanned PDFs and create searchable PDFs including the extracted text. [#15712](https://github.com/JabRef/jabref/pull/15712)
- We Added generic CSV export filter that exports all standard BibTeX fields [#15711](https://github.com/JabRef/jabref/issues/15711)

### Changed

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ public static ExporterFactory create(CliPreferences preferences) {
exporters.add(new TemplateExporter("ISO 690", "iso690txt", "iso690", "iso690txt", StandardFileType.TXT, layoutPreferences, saveOrder));
exporters.add(new TemplateExporter("Endnote", "endnote", "EndNote", "endnote", StandardFileType.TXT, layoutPreferences, saveOrder));
exporters.add(new TemplateExporter("OpenOffice/LibreOffice CSV", "oocsv", "openoffice-csv", "openoffice", StandardFileType.CSV, layoutPreferences, saveOrder));
exporters.add(new TemplateExporter("CSV", "csv", "csv", "csv", StandardFileType.CSV, layoutPreferences, saveOrder));
exporters.add(new TemplateExporter("RIS", "ris", "ris", "ris", StandardFileType.RIS, layoutPreferences, saveOrder, BlankLineBehaviour.DELETE_BLANKS));
exporters.add(new TemplateExporter("MIS Quarterly", "misq", "misq", "misq", StandardFileType.RTF, layoutPreferences, saveOrder));
exporters.add(new TemplateExporter("CSL YAML", "yaml", "yaml", null, StandardFileType.YAML, layoutPreferences, saveOrder, BlankLineBehaviour.DELETE_BLANKS));
Expand Down
11 changes: 11 additions & 0 deletions jablib/src/main/resources/resource/layout/csv/README
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
A generic CSV export filter that exports all standard BibTeX fields as-is.

The exported file contains a header row with field names, followed by one row
per entry. All standard fields are included as columns:

Citation Key, Author, Title, Year, Journal, Booktitle, Publisher, Volume,
Number, Pages, Month, Edition, Address, Editor, Series, Note, HowPublished,
Organization, Institution, School, DOI, URL, Keywords, Abstract, ISBN, ISSN

This filter is intended as a simple, general-purpose CSV export suitable for
use in spreadsheet applications such as Microsoft Excel or LibreOffice Calc.
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"Citation Key","Author","Title","Year","Journal","Booktitle","Publisher","Volume","Number","Pages","Month","Edition","Address","Editor","Series","Note","HowPublished","Organization","Institution","School","Chapter","Annote","DOI","URL","Keywords","Abstract","ISBN","ISSN"
1 change: 1 addition & 0 deletions jablib/src/main/resources/resource/layout/csv/csv.layout
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
"\format[ReplaceWithEscapedDoubleQuotes]{\citationkey}","\format[ReplaceWithEscapedDoubleQuotes]{\author}","\format[ReplaceWithEscapedDoubleQuotes]{\title}","\format[ReplaceWithEscapedDoubleQuotes]{\year}","\format[ReplaceWithEscapedDoubleQuotes]{\journal}","\format[ReplaceWithEscapedDoubleQuotes]{\booktitle}","\format[ReplaceWithEscapedDoubleQuotes]{\publisher}","\format[ReplaceWithEscapedDoubleQuotes]{\volume}","\format[ReplaceWithEscapedDoubleQuotes]{\number}","\format[ReplaceWithEscapedDoubleQuotes]{\pages}","\format[ReplaceWithEscapedDoubleQuotes]{\month}","\format[ReplaceWithEscapedDoubleQuotes]{\edition}","\format[ReplaceWithEscapedDoubleQuotes]{\address}","\format[ReplaceWithEscapedDoubleQuotes]{\editor}","\format[ReplaceWithEscapedDoubleQuotes]{\series}","\format[ReplaceWithEscapedDoubleQuotes]{\note}","\format[ReplaceWithEscapedDoubleQuotes]{\howpublished}","\format[ReplaceWithEscapedDoubleQuotes]{\organization}","\format[ReplaceWithEscapedDoubleQuotes]{\institution}","\format[ReplaceWithEscapedDoubleQuotes]{\school}","\format[ReplaceWithEscapedDoubleQuotes]{\chapter}","\format[ReplaceWithEscapedDoubleQuotes]{\annote}","\format[ReplaceWithEscapedDoubleQuotes]{\doi}","\format[ReplaceWithEscapedDoubleQuotes]{\url}","\format[ReplaceWithEscapedDoubleQuotes]{\keywords}","\format[Replace(\n, ),ReplaceWithEscapedDoubleQuotes]{\abstract}","\format[ReplaceWithEscapedDoubleQuotes]{\isbn}","\format[ReplaceWithEscapedDoubleQuotes]{\issn}"
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package org.jabref.logic.exporter;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.List;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.TransformerException;

import org.jabref.logic.layout.LayoutFormatterPreferences;
import org.jabref.logic.util.StandardFileType;
import org.jabref.model.database.BibDatabaseContext;
import org.jabref.model.entry.BibEntry;
import org.jabref.model.entry.field.StandardField;
import org.jabref.model.metadata.SaveOrder;

import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.junit.jupiter.api.parallel.Execution;
import org.junit.jupiter.api.parallel.ExecutionMode;
import org.junit.jupiter.api.parallel.ResourceLock;
import org.mockito.Answers;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.mock;

@Execution(ExecutionMode.SAME_THREAD)
@ResourceLock("exporter")
public class GenericCsvExportFormatTest {

public BibDatabaseContext databaseContext;
private Exporter exportFormat;

@BeforeEach
void setUp() {
exportFormat = new TemplateExporter(
"CSV",
"csv",
"csv",
"csv",
StandardFileType.CSV,
mock(LayoutFormatterPreferences.class, Answers.RETURNS_DEEP_STUBS),
SaveOrder.getDefaultSaveOrder());

databaseContext = new BibDatabaseContext();
}

@AfterEach
void tearDown() {
exportFormat = null;
}

@Test
void performExportForSingleAuthor(@TempDir Path testFolder) throws IOException, SaveException, ParserConfigurationException, TransformerException {
Path path = testFolder.resolve("test.csv");
BibEntry entry = new BibEntry()
.withCitationKey("Doe2023")
.withField(StandardField.AUTHOR, "Doe, John")
.withField(StandardField.TITLE, "Test Article")
.withField(StandardField.YEAR, "2023");
List<BibEntry> entries = List.of(entry);

exportFormat.export(databaseContext, path, entries);

List<String> lines = Files.readAllLines(path);
assertEquals(2, lines.size());
assertEquals(
"""
"Citation Key","Author","Title","Year","Journal","Booktitle","Publisher","Volume","Number","Pages","Month","Edition","Address","Editor","Series","Note","HowPublished","Organization","Institution","School","Chapter","Annote","DOI","URL","Keywords","Abstract","ISBN","ISSN"\
""",
lines.getFirst());
assertEquals(
"""
"Doe2023","Doe, John","Test Article","2023","","","","","","","","","","","","","","","","","","","","","","","",""\
""",
lines.get(1));
}

@Test
void performExportForMultipleEntries(@TempDir Path testFolder) throws IOException, SaveException, ParserConfigurationException, TransformerException {
Path path = testFolder.resolve("test.csv");
BibEntry entry1 = new BibEntry()
.withCitationKey("Doe2023")
.withField(StandardField.AUTHOR, "Doe, John")
.withField(StandardField.TITLE, "Article 1")
.withField(StandardField.YEAR, "2023");
BibEntry entry2 = new BibEntry()
.withCitationKey("Smith2024")
.withField(StandardField.AUTHOR, "Smith, Jane")
.withField(StandardField.TITLE, "Article 2")
.withField(StandardField.YEAR, "2024");
List<BibEntry> entries = List.of(entry1, entry2);

exportFormat.export(databaseContext, path, entries);

List<String> lines = Files.readAllLines(path);
assertEquals(3, lines.size());
}

@Test
void performExportEscapesDoubleQuotesInFields(@TempDir Path testFolder) throws IOException, SaveException, ParserConfigurationException, TransformerException {
Path path = testFolder.resolve("test.csv");
BibEntry entry = new BibEntry()
.withCitationKey("Doe2023")
.withField(StandardField.TITLE, "Title with \"quotes\" inside");
List<BibEntry> entries = List.of(entry);

exportFormat.export(databaseContext, path, entries);

List<String> lines = Files.readAllLines(path);
assertEquals(2, lines.size());
assertEquals(
"""
"Doe2023","","Title with ""quotes"" inside","","","","","","","","","","","","","","","","","","","","","","","","",""\
""",
lines.get(1));
}
}
Loading