Created
August 16, 2016 10:40
-
-
Save aNNiMON/e6ac408894b0cb2ed3da0e5414b74f75 to your computer and use it in GitHub Desktop.
Converts Evernote .enex files to json
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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
@roddaut not sure if it'll work, as enex file structure may be different right now. But you can try.
You need Java JDK from https://adoptium.net/
Download libraries:
https://repo1.maven.org/maven2/org/jsoup/jsoup/1.12.2/jsoup-1.12.2.jar
https://repo1.maven.org/maven2/org/json/json/20230618/json-20230618.jar
Then download this
EnexToJson.java
Put everything in the same folder, including your enex file, then run: