Procházet zdrojové kódy

Added 'CSV to JSON' and 'JSON to CSV' operations. Closes #277

n1474335 před 6 roky
rodič
revize
863bdffa84

+ 4 - 0
src/core/Utils.mjs

@@ -573,6 +573,10 @@ class Utils {
                 cell = "";
                 lines.push(line);
                 line = [];
+                // Skip next byte if it is also a line delim (e.g. \r\n)
+                if (lineDelims.indexOf(next) >= 0 && next !== b) {
+                    i++;
+                }
             } else {
                 cell += b;
             }

+ 3 - 1
src/core/config/Categories.json

@@ -54,7 +54,9 @@
             "From MessagePack",
             "To Braille",
             "From Braille",
-            "Parse TLV"
+            "Parse TLV",
+            "CSV to JSON",
+            "JSON to CSV"
         ]
     },
     {

+ 80 - 0
src/core/operations/CSVToJSON.mjs

@@ -0,0 +1,80 @@
+/**
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2018
+ * @license Apache-2.0
+ */
+
+import Operation from "../Operation";
+import OperationError from "../errors/OperationError";
+import Utils from "../Utils";
+
+/**
+ * CSV to JSON operation
+ */
+class CSVToJSON extends Operation {
+
+    /**
+     * CSVToJSON constructor
+     */
+    constructor() {
+        super();
+
+        this.name = "CSV to JSON";
+        this.module = "Default";
+        this.description = "Converts a CSV file to JSON format.";
+        this.infoURL = "https://wikipedia.org/wiki/Comma-separated_values";
+        this.inputType = "string";
+        this.outputType = "JSON";
+        this.args = [
+            {
+                name: "Cell delimiters",
+                type: "binaryShortString",
+                value: ","
+            },
+            {
+                name: "Row delimiters",
+                type: "binaryShortString",
+                value: "\\r\\n"
+            },
+            {
+                name: "Format",
+                type: "option",
+                value: ["Array of dictionaries", "Array of arrays"]
+            }
+        ];
+    }
+
+    /**
+     * @param {string} input
+     * @param {Object[]} args
+     * @returns {JSON}
+     */
+    run(input, args) {
+        const [cellDelims, rowDelims, format] = args;
+        let json, header;
+
+        try {
+            json = Utils.parseCSV(input, cellDelims.split(""), rowDelims.split(""));
+        } catch (err) {
+            throw new OperationError("Unable to parse CSV: " + err);
+        }
+
+        switch (format) {
+            case "Array of dictionaries":
+                header = json[0];
+                return json.slice(1).map(row => {
+                    const obj = {};
+                    header.forEach((h, i) => {
+                        obj[h] = row[i];
+                    });
+                    return obj;
+                });
+            case "Array of arrays":
+            default:
+                return json;
+        }
+    }
+
+}
+
+export default CSVToJSON;

+ 72 - 0
src/core/operations/JSONToCSV.mjs

@@ -0,0 +1,72 @@
+/**
+ * @author n1474335 [n1474335@gmail.com]
+ * @copyright Crown Copyright 2018
+ * @license Apache-2.0
+ */
+
+import Operation from "../Operation";
+import OperationError from "../errors/OperationError";
+
+/**
+ * JSON to CSV operation
+ */
+class JSONToCSV extends Operation {
+
+    /**
+     * JSONToCSV constructor
+     */
+    constructor() {
+        super();
+
+        this.name = "JSON to CSV";
+        this.module = "Default";
+        this.description = "Converts JSON data to a CSV.";
+        this.infoURL = "https://wikipedia.org/wiki/Comma-separated_values";
+        this.inputType = "JSON";
+        this.outputType = "string";
+        this.args = [
+            {
+                name: "Cell delimiter",
+                type: "binaryShortString",
+                value: ","
+            },
+            {
+                name: "Row delimiter",
+                type: "binaryShortString",
+                value: "\\r\\n"
+            }
+        ];
+    }
+
+    /**
+     * @param {JSON} input
+     * @param {Object[]} args
+     * @returns {string}
+     */
+    run(input, args) {
+        const [cellDelim, rowDelim] = args;
+
+        try {
+            // If the JSON is an array of arrays, this is easy
+            if (input[0] instanceof Array) {
+                return input.map(row => row.join(cellDelim)).join(rowDelim) + rowDelim;
+            }
+
+            // If it's an array of dictionaries...
+            const header = Object.keys(input[0]);
+            return header.join(cellDelim) +
+                rowDelim +
+                input.map(
+                    row => header.map(
+                        h => row[h]
+                    ).join(cellDelim)
+                ).join(rowDelim) +
+                rowDelim;
+        } catch (err) {
+            throw new OperationError("Unable to parse JSON to CSV: " + err);
+        }
+    }
+
+}
+
+export default JSONToCSV;

+ 1 - 1
src/core/operations/ToTable.mjs

@@ -33,7 +33,7 @@ class ToTable extends Operation {
             {
                 "name": "Row delimiters",
                 "type": "binaryShortString",
-                "value": "\\n\\r"
+                "value": "\\r\\n"
             },
             {
                 "name": "Make first row header",