如何在 GWT 中将 JSONObject 转换为 .csv 文件?

7

我对GWT完全不熟悉,如果这是一个简单的问题,请见谅。我有一个可用于将表格导出为.xlsx文件的函数,这个函数已经工作正常了。这很好,没有任何问题地导出了文件。这是使用这个第三方工具:https://github.com/stephenliberty/excel-builder.js/

我的问题是,我想将文件保存为.csv格式,但我无法将这个gwt版本的JSONObject (com.google.gwt.json.client.JSONObject.JSONObject()) 转换成csv,并且我找不到有用的关于excel-builder-js的文档,是否可以导出为csv... 这怎么可能呢?

    ...
            JSONObject object = new JSONObject();
            object.put("head", head);
            object.put("cols", columns);
            object.put("data", array);
            exportXlsxFromTable(JsonUtils.safeEval(object.toString()), GWT.getModuleName(), name);
    ...

    public static native void exportXlsxFromTable(JavaScriptObject originalData, String project, String name) /*-{
        var uri = 'data:application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;base64,';
    $wnd
            .require(
                    [ project + '/excelbuilderjs/excel-builder', project + '/excelbuilderjs/Template/BasicReport' ],
                    function(EB, BR, downloader) {
                        var basicReport = new BR({
                            name : name
                        });
                        basicReport.setHeader([
                            {bold: false, text: name}, "", ""
                        ]);
                        var head = originalData['head'];
                        for (var i=0;i<head.length;i++) {
                            for (var j=0;j<head[i].length;j++) {
                                head[i][j].metadata = { type: 'string' };
                            }
                        }
                        basicReport.setData(head.concat(originalData['data']));
                        basicReport.setColumns(originalData['cols']);

                        var data = EB.createFile(basicReport.prepare());
                        //          window.location.href = uri + data;
                        $entry(@com.mycompany.gxt.framework.view.dom.DOMUtils::downloadFile(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)("myfile.xlsx", uri, data));

                    });
    }-*/;

public static native void downloadFile(String filename, String uri, String base64) /*-{
    var iframeDownloadFn = function(filename, uri, base64) {
        var values = {
            fn : 'b64d',
            fname : filename,
            fcont : uri + base64
        };
        try {
            $wnd.document.body.removeChild($wnd.downloadIframe);
        } catch (e) {
        }
        var iframe = $wnd.document.createElement("iframe");
        $wnd.document.body.appendChild(iframe);

        var iDoc = iframe.contentWindow.document;
        var form = iDoc.createElement("form");
        form
                .setAttribute("action",
                        @com.mycompany.gxt.framework.client.FrameworkClient::DOWNLOAD_URL);
        form.setAttribute("method", 'POST');
        form.setAttribute("style", 'display: none');
        for ( var property in values) {
            if (values.hasOwnProperty(property)) {
                var value = values[property];
                if (value instanceof Array) {
                    for (var i = 0, l = value.length; i < l; i++) {
                        var el = iDoc.createElement("input");
                        el.setAttribute("type", 'hidden');
                        el.setAttribute("name", property);
                        el.setAttribute("value", value[i]);

                        form.appendChild(el);
                    }
                } else {
                    var el1 = iDoc.createElement("input");
                    el1.setAttribute("type", 'hidden');
                    el1.setAttribute("name", property);
                    el1.setAttribute("value", value);
                    form.appendChild(el1);
                }
            }
        }
        iDoc.body.appendChild(form);
        form.submit();
        $wnd.downloadIframe = iframe;
    }
    var clickLink = function(link, uri, base64) {
        var cancelled = true;

        try {
            if (document.createEvent) {
                var event = document.createEvent("MouseEvents");
                event.initMouseEvent("click", true, true, window, 0, 0, 0,
                        0, 0, false, false, false, false, 0, null);
                cancelled = !link.dispatchEvent(event);
            } else if (link.fireEvent) {
                cancelled = !link.fireEvent("onclick");
            }
        } catch (e) {
            cancelled = true;
        }

        link.parentNode.removeChild(link);

        if (cancelled) {
            iframeDownloadFn(filename, uri, base64);
        }
    }
    var link = $wnd.document.createElement("a");
    link.setAttribute("href", uri + base64);
    link.setAttribute("name", filename);
    link.setAttribute("title", filename);
    link.setAttribute("download", filename);
    $wnd.document.body.appendChild(link);
    clickLink(link, uri, base64);
}-*/;

编辑:

我试过了"Mon Mohon Singha"的javascript建议,现在我在这里:

  JSONObject object = new JSONObject();
object.put("head", head);
object.put("cols", columns);
object.put("data", array);

exportCsvFromTable(object.toString(), GWT.getModuleName(), name);

public static native void exportCsvFromTable(String originalData, String project, String name) /*-{
var uri = 'text/csv;charset=utf-8;';

function convertToCSV(jsData){
     var json = jsData;
     var fields = Object.keys(json[0]);
     var replacer = function(key, value) { return value === null ? '' : value }
     var csv = json.map(function(row){
       return fields.map(function(fieldName){
         return JSON.stringify(row[fieldName], replacer)
       }).join(',')
     })
     csv.unshift(fields.join(',')) // add header column
     return csv.join('\r\n');
   }

var data = convertToCSV(originalData);
//     window.location.href = uri + data;
$entry(@com.mycompany.gxt.framework.view.dom.DOMUtils::downloadFile(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)("export.csv", uri, data));

}-*/;

但我遇到了这个错误,所以我认为我没有使用正确的类型...

com.google.gwt.logging.client.LogConfiguration
SEVERE: Exception caught: Exception caught: (TypeError) : json_0_g$.map is not a function com.google.gwt.event.shared.UmbrellaException: Exception caught: Exception caught: (TypeError) : json_0_g$.map is not a function
 at Unknown.fillInStackTrace_0_g$(as-0.js@3:130944)
 at Unknown.Throwable_3_g$(as-0.js@8:130899)
 at Unknown.Exception_3_g$(as-0.js@18:131042)
 at Unknown.RuntimeException_3_g$(as-0.js@18:287158)
 at Unknown.UmbrellaException_3_g$(as-0.js@25:313985)

编辑2:

这是已注销的JavaScript对象。删除了一些“data”行以更清晰地呈现:

Object
cols: Array(10)
0: {name: "ID", type: "string"}
1: {name: "NAME", type: "string"}
2: {name: "FIRST NAME", type: "string"}
3: {name: "BIRTHDAY", type: "string"}
4: {name: "BIRTH PLACE", type: "string"}
5: {name: "BIRTH COUNTRY", type: "string"}
6: {name: "NATIONALITY", type: "string"}
7: {name: "ORGANISATION", type: "string"}
8: {name: "FUNCTION", type: "string"}
9: {name: "PLACE", type: "string"}
length: 10
__proto__: Array(0)
data: Array(100)
0: (10) [1470, "John", "Doe", "03.03.1988", "", "", "CANADA", "BPA", "", ""]
1: (10) [1469, "Test", "NAme", "25.03.1999", "CANADA", "CANADA", "CANADA", "test", "", "LA"]
2: (10) [1467, "Mike", "Test2", "06.05.2019", "Paris", "", "", "test", "ikol", "LA"]
3: (10) [1465, "Flanders", "Ned2", "23.12.1974", "Salt Lake City", "", "", "Orgatest", "BPA", ""]
4: (10) [1462, "Bro", "Jo", "03.07.2018", "abc", "USA", "USA", "MY COMPANY", "Catering", "A"]
5: (10) [1461, "Bro", "Jo", "01.08.2018", "abc", "USA", "USA", "MY COMPANY", "Catering", "A"]
...
length: 100
__proto__: Array(0)
head: Array(1)
0: (10) ["ID", "NAME", "FIRST NAME", "BIRTHDAY", "BIRTH PLACE", "BIRTH COUNTRY", "NATIONALITY", "ORGANISATION", "FUNCTION", "PLACE"]
length: 1
__proto__: Array(0)
__proto__: Object

编辑3:

正如罗布·牛顿所建议的那样,我将转换函数编辑为如下形式:

public static native void exportCsvFromTable(JavaScriptObject originalData, String project, String name) /*-{
        var uri = 'text/csv;charset=utf-8;';

        function convertToCSV(jsData){
              //console.log(originalData);
              var json = jsData;
              //var fields = Object.keys(json);
              //var replacer = function(key, value) { return value === null ? '' : value }

              var headerCSV = json.head[0].join(',');

              var rowsCSV = json.data.map( function(row) {
                return row.join(',');
              } );

              rowsCSV.unshift(headerCSV);

              console.log(rowsCSV.join('\r\n'));

              return rowsCSV.join('\r\n');
            }

            var data = convertToCSV(originalData);
            //          window.location.href = uri + data;
            $entry(@com.mycompany.gxt.framework.view.dom.DOMUtils::downloadFile(Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)("export.csv", uri, data));

}-*/;

转换后的数据看起来还不错:
ID,NAME,FIRST NAME,BIRTHDAY,BIRTH PLACE,BIRTH COUNTRY,NATIONALITY,ORGANISATION,FUNCTION,PLACE
31471,Test,Test,07.05.2019,New,,,XYZ,ikl,
31470,John,Doe,03.03.1988,,,Canada,XYZ,,
31469,New,Test,25.03.1999,Right,USA,USA,,LA
...

很遗憾,下载的文件是无效的,大小为0字节 :(

你正在将包含JSON文本的字符串传递给exportCsvFromTable()和convertToCSV()函数。该函数期望一个JavaScript对象作为参数。 - Robert Newton
是的,我也在尝试着记录这个,但我不知道如何在这个GWT中做到这一点... :( - VORiAND
那个数据的CSV文件应该长什么样呢? - Robert Newton
如表格中所示。列标题名称在“cols”中,行数据在“data”中。我不知道为什么有头部... - VORiAND
你已经测试了哪些浏览器来下载? - Robert Newton
显示剩余2条评论
2个回答

0

将JSON数据转换为CSV格式的JS代码

我不了解GWT,也许它能帮到你

function convertToCSV(jsData){
      var json = jsData;
      var fields = Object.keys(json[0]);
      var replacer = function(key, value) { return value === null ? '' : value }
      var csv = json.map(function(row){
        return fields.map(function(fieldName){
          return JSON.stringify(row[fieldName], replacer)
        }).join(',')
      })
      csv.unshift(fields.join(',')) // add header column
      return csv.join('\r\n');
    }

function exportCSVFile(items, fileTitle) {
        var csv = convertToCSV(items);
        var exportedFilenmae = fileTitle + '.csv' || 'export.csv';
        var blob = new Blob([csv], { type: 'text/csv;charset=utf-8;' });
        if (navigator.msSaveBlob) {
            navigator.msSaveBlob(blob, exportedFilenmae);
        } else {
            var link = document.createElement("a");
            if (link.download !== undefined) {
                var url = URL.createObjectURL(blob);
                link.setAttribute("href", url);
                link.setAttribute("download", exportedFilenmae);
                link.style.visibility = 'hidden';
                document.body.appendChild(link);
                link.click();
                document.body.removeChild(link);
            }
        }
        return true
    }

谢谢,我想我已经在这个网站上找到了这个函数,我的问题是与GWT的集成 :( - VORiAND
好的,我尝试了一下,发现在我的Javascript控制台中出现了以下错误:SEVERE: Exception caught: Exception caught: (TypeError) : json_0_g$.map is not a function com.google.gwt.event.shared.UmbrellaException: Exception caught: Exception caught: (TypeError) : json_0_g$.map is not a function。 - VORiAND

0
你需要将一个JavaScriptObject传递给你的转换函数,而不是包含JSON的字符串。尝试对你的代码进行以下更改:
exportCsvFromTable(object.getJavaScriptObject(), GWT.getModuleName(), name);

public static native void exportCsvFromTable(JavaScriptObject originalData, String project, String name) /*-{

您展示了您的对象具有一个名为head的属性,它是长度为1的数组,并且head [0]是您的标题行列名称的数组。因此,类似以下内容的东西将为您提供标题行字符串:

var headerCSV = json.head[0].join(',');

实际数据行位于名为data的属性中,该属性是一个数组,数组中的每个项都是行中值的数组。
var rowsCSV = json.data.map( function(row) {
    return row.join(',');
  } );

现在将表头和行连接起来,如下所示:

rowsCSV.unshift(headerCSV) // add header column
return rowsCSV.join('\r\n');

尝试后,这是我在浏览器控制台中看到的内容:Caused by: com.google.gwt.core.client.JavaScriptException: (TypeError) : Cannot convert undefined or null to object at Unknown.keys(Unknown@-1) at Unknown.convertToCSV_0_g$(as-0.js@30:238179) - VORiAND
尝试后,我得到了这个:Caused by: com.google.gwt.core.client.JavaScriptException: (TypeError) : json_0_g$.map 不是一个函数 at Unknown.convertToCSV_0_g$(zs-0.js@30:238185) at Unknown.exportCsvFromTable_1_g$(as- - VORiAND
我现在会添加已注销的JavaScript对象。 - VORiAND
注销的JavaScriptObject对我来说非常奇怪...你认为语法没问题,可以用这个函数解析吗?我看到它也使用了{}和[]... - VORiAND
@VORIAND 不,我不认为现有的代码会解析该对象以给出典型的CSV格式。请参考我的更新。 - Robert Newton
看起来不错 :) 我已经记录了创建的 .csv 文件,我认为格式没问题,下载也开始了,但是创建的文件大小为 0 字节,所以下载函数还不够完善... 下载文件的函数在我的问题中,但我现在也会发布转换函数。 - VORiAND

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接