Skip to content

Instantly share code, notes, and snippets.

@rodolfobandeira
Forked from aNNiMON/EnexToJson.java
Created October 18, 2020 21:09
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rodolfobandeira/dc7fb896197f63b7021b284734026be8 to your computer and use it in GitHub Desktop.
Save rodolfobandeira/dc7fb896197f63b7021b284734026be8 to your computer and use it in GitHub Desktop.
Converts Evernote .enex files to json
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.util.EnumSet;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.jsoup.Jsoup;
import org.jsoup.safety.Whitelist;
import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
/**
* Modified from: https://github.com/tonca/EvernoteReader
*
* @author Antonio, aNNiMON
*/
public final class EnexToJson {
private static enum Options { SIMPLE, RESOURCES, CONSOLE, TEXT };
private static final EnumSet<Options> options = EnumSet.noneOf(Options.class);
public static void main(String[] args) {
if (args.length == 0) {
System.out.println("Usage: java EnexToJson file.enex [options]\n"
+ "Options:\n"
+ " -s, --simple include only title and content and date\n"
+ " -r, --resources include resources to json\n"
+ " -c, --console print output to stdout, not json file\n"
+ " -t, --text cleans html content\n"
);
return;
}
final String enexFile = args[0];
for (int i = 1; i < args.length; i++) {
switch (args[i]) {
case "-s":
case "--simple":
options.add(Options.SIMPLE);
break;
case "-r":
case "--resources":
options.add(Options.RESOURCES);
break;
case "-c":
case "--console":
options.add(Options.CONSOLE);
break;
case "-t":
case "--text":
options.add(Options.TEXT);
break;
}
}
process(enexFile);
}
private static void process(String filename) {
final File inputFile = new File(filename);
final File outputFile = new File(inputFile.getParentFile(), inputFile.getName() + ".json");
try (OutputStreamWriter out = new OutputStreamWriter(createOutputStream(outputFile), "UTF-8")) {
final Document document = DocumentBuilderFactory.newInstance()
.newDocumentBuilder()
.parse(inputFile);
if (document.hasChildNodes()) {
final JSONArray jsonArray = new JSONArray();
parse(document.getChildNodes(), jsonArray, new JSONObject());
out.append(jsonArray.toString(2));
}
out.flush();
} catch (ParserConfigurationException | SAXException | IOException ex) {
System.err.println(ex);
}
}
private static OutputStream createOutputStream(File outputFile) throws FileNotFoundException {
if (options.contains(Options.CONSOLE)) {
return System.out;
} else {
return new FileOutputStream(outputFile);
}
}
private static void parse(NodeList childNodes, JSONArray notes, JSONObject data) {
String content;
final int length = childNodes.getLength();
for (int i = 0; i < length; i++) {
switch (childNodes.item(i).getNodeName()) {
case "title":
content = childNodes.item(i).getTextContent();
data.put("title", content);
break;
case "content":
content = childNodes.item(i).getTextContent();
if (options.contains(Options.TEXT)) {
content = cleanHtml(content);
}
data.put("content", content);
break;
case "created":
content = childNodes.item(i).getTextContent();
data.put("created", content);
break;
case "updated":
if (options.contains(Options.SIMPLE)) break;
content = childNodes.item(i).getTextContent();
data.put("updated", content);
break;
case "latitude":
if (options.contains(Options.SIMPLE)) break;
content = childNodes.item(i).getTextContent();
data.put("latitude", content);
break;
case "longitude":
if (options.contains(Options.SIMPLE)) break;
content = childNodes.item(i).getTextContent();
data.put("longitude", content);
break;
case "altitude":
if (options.contains(Options.SIMPLE)) break;
content = childNodes.item(i).getTextContent();
data.put("altitude", content);
break;
case "source":
if (options.contains(Options.SIMPLE)) break;
content = childNodes.item(i).getTextContent();
data.put("source", content);
break;
case "source-url":
if (options.contains(Options.SIMPLE)) break;
content = childNodes.item(i).getTextContent();
data.put("source-url", content);
break;
case "tag":
if (options.contains(Options.SIMPLE)) break;
JSONArray tags = createTags(data);
content = childNodes.item(i).getTextContent();
JSONObject tag = new JSONObject();
tag.put("tag", content);
tags.put(tag);
break;
case "author":
if (options.contains(Options.SIMPLE)) break;
content = childNodes.item(i).getTextContent();
data.put("author", content);
break;
case "resource":
if (options.contains(Options.SIMPLE)) break;
if (!options.contains(Options.RESOURCES)) break;
content = childNodes.item(i).getTextContent();
data.put("resource", content);
break;
case "note":
final JSONObject note = new JSONObject();
parse(childNodes.item(i).getChildNodes(), notes, note);
data.put("note", note);
notes.put(note);
break;
case "note-attributes":
if (options.contains(Options.SIMPLE)) break;
final JSONObject noteAttributes = new JSONObject();
parse(childNodes.item(i).getChildNodes(), notes, noteAttributes);
data.put("note-attributes", noteAttributes);
break;
case "en-export":
parse(childNodes.item(i).getChildNodes(), notes, data);
break;
default:
break;
}
}
}
private static JSONArray createTags(JSONObject jsonObj) throws JSONException {
JSONArray tags;
if (jsonObj.has("tags")) {
tags = jsonObj.getJSONArray("tags");
} else {
tags = new JSONArray();
jsonObj.put("tags", tags);
}
return tags;
}
private static String cleanHtml(String content) {
return Jsoup.clean(content, Whitelist.none());
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment