Экспорт JSON в CSV или Excel с кодировкой UTF-8 (например, греческий) с использованием JavaScript

Я пытаюсь экспортировать и загрузить объект JSON в CSV файл, и у меня проблема с греческими символами. Мой код работает; он не идеален, но он работает.

Проблема в том, что греческие символы выглядят как мусор.

Вот мой существующий код:

function downloadJsonToCsv(jsonObject) {
    var array = typeof jsonObject != "object" ? JSON.parse(jsonObject) : jsonObject;

    if (array == null) {
        return; // No data found on the jsonObject
    }

    var str = "";

    for (var i = 0; i < array.length; i++) {
        var line = "";

        for (var index in array[i]) {
            line += array[i][index] + ";"; // Set delimiter
        }

        // Here is an example where you would wrap the values in double quotes
        // for (var index in array[i]) {
        //    line += '"' + array[i][index] + '",';
        // }

        line.slice(0,line.Length-1); 

        str += line + "\r\n";
    }

    window.open("data:text/csv;charset=utf-8," + encodeURI(str));
}

У меня есть два вопроса.

  • Как экспортировать этот файл CSV с правильными греческими символами?
  • Как экспортировать эти данные в формате Excel, а не в формате CSV?

Ответы

Ответ 1

Экспорт в CSV

Для экспорта в CSV с символами, отличными от ASCII, необходимо добавить файл с Byte Order Mark aka BOM. При изменении кода

var str = "";

в

var str = "\uFEFF";

Вам нужна современная версия Excel для распознавания спецификации. Как упоминалось в этой полезной статье fooobar.com/questions/15205/..., Excel 2003 и ранее не будут правильно оценивать спецификацию. У меня только есть доступ к Excel 2003 в Windows, поэтому я не могу проверить это на данный момент, но он достаточно хорошо документирован.

К сожалению, Excel 2011 для Macintosh НЕ является "современным Excel" в этом смысле. К счастью, Google Таблицы поступают правильно.

Экспорт непосредственно в Excel

Здесь jsFiddle реализация кода ниже. Он генерирует документ SpreadsheetXml. Потенциал этого метода заключается в том, что вы можете получить ОЧЕНЬ сложно... добавив в формулы и сделав намного больше вещей, характерных для Excel.

// Test script to generate a file from JavaScript such
// that MS Excel will honor non-ASCII characters.

testJson = [
    {
        "name": "Tony Peña",
        "city": "New York",
        "country": "United States",
        "birthdate": "1978-03-15",
        "amount": 42

    },
    {
        "name": "Ζαλώνης Thessaloniki",
        "city": "Athens",
        "country": "Greece",
        "birthdate": "1987-11-23",
        "amount": 42
    }
];

// Simple type mapping; dates can be hard
// and I would prefer to simply use `datevalue`
// ... you could even add the formula in here.
testTypes = {
    "name": "String",
    "city": "String",
    "country": "String",
    "birthdate": "String",
    "amount": "Number"
};

emitXmlHeader = function () {
    var headerRow =  '<ss:Row>\n';
    for (var colName in testTypes) {
        headerRow += '  <ss:Cell>\n';
        headerRow += '    <ss:Data ss:Type="String">';
        headerRow += colName + '</ss:Data>\n';
        headerRow += '  </ss:Cell>\n';        
    }
    headerRow += '</ss:Row>\n';    
    return '<?xml version="1.0"?>\n' +
           '<ss:Workbook xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet">\n' +
           '<ss:Worksheet ss:Name="Sheet1">\n' +
           '<ss:Table>\n\n' + headerRow;
};

emitXmlFooter = function() {
    return '\n</ss:Table>\n' +
           '</ss:Worksheet>\n' +
           '</ss:Workbook>\n';
};

jsonToSsXml = function (jsonObject) {
    var row;
    var col;
    var xml;
    var data = typeof jsonObject != "object" 
             ? JSON.parse(jsonObject) 
             : jsonObject;

    xml = emitXmlHeader();

    for (row = 0; row < data.length; row++) {
        xml += '<ss:Row>\n';

        for (col in data[row]) {
            xml += '  <ss:Cell>\n';
            xml += '    <ss:Data ss:Type="' + testTypes[col]  + '">';
            xml += data[row][col] + '</ss:Data>\n';
            xml += '  </ss:Cell>\n';
        }

        xml += '</ss:Row>\n';
    }

    xml += emitXmlFooter();
    return xml;  
};

console.log(jsonToSsXml(testJson));

Это создает XML-документ ниже. Если этот XML сохраняется в файле с именем test.xls, Excel должен распознать это и открыть его с надлежащей кодировкой.

<?xml version="1.0"?>
<ss:Workbook xmlns:ss="urn:schemas-microsoft-com:office:spreadsheet">
<ss:Worksheet ss:Name="Sheet1">
<ss:Table>

<ss:Row>
  <ss:Cell>
    <ss:Data ss:Type="String">name</ss:Data>
  </ss:Cell>
  <ss:Cell>
    <ss:Data ss:Type="String">city</ss:Data>
  </ss:Cell>
  <ss:Cell>
    <ss:Data ss:Type="String">country</ss:Data>
  </ss:Cell>
  <ss:Cell>
    <ss:Data ss:Type="String">birthdate</ss:Data>
  </ss:Cell>
  <ss:Cell>
    <ss:Data ss:Type="String">amount</ss:Data>
  </ss:Cell>
</ss:Row>

<ss:Row>
  <ss:Cell>
    <ss:Data ss:Type="String">Tony Peña</ss:Data>
  </ss:Cell>
  <ss:Cell>
    <ss:Data ss:Type="String">New York</ss:Data>
  </ss:Cell>
  <ss:Cell>
    <ss:Data ss:Type="String">United States</ss:Data>
  </ss:Cell>
  <ss:Cell>
    <ss:Data ss:Type="String">1978-03-15</ss:Data>
  </ss:Cell>
  <ss:Cell>
    <ss:Data ss:Type="Number">42</ss:Data>
  </ss:Cell>
</ss:Row>
<ss:Row>
  <ss:Cell>
    <ss:Data ss:Type="String">Ζαλώνης Thessaloniki</ss:Data>
  </ss:Cell>
  <ss:Cell>
    <ss:Data ss:Type="String">Athens</ss:Data>
  </ss:Cell>
  <ss:Cell>
    <ss:Data ss:Type="String">Greece</ss:Data>
  </ss:Cell>
  <ss:Cell>
    <ss:Data ss:Type="String">1987-11-23</ss:Data>
  </ss:Cell>
  <ss:Cell>
    <ss:Data ss:Type="Number">42</ss:Data>
  </ss:Cell>
</ss:Row>

</ss:Table>
</ss:Worksheet>
</ss:Workbook>

Однако я должен признать, что моя сильная наклонность состояла в том, чтобы сделать эту серверную сторону, если это возможно. Я использовал библиотеку Python openpyxl для этого в прошлом, и это довольно просто. Большинство серверных языков имеют библиотеку, которая генерирует файлы Excel, и они должны обеспечивать гораздо лучшие конструкции, чем конкатенацию строк.

В любом случае, см. этот статья StackOverflow для некоторых плюсов и минусов различных других опций.

Ответ 2

Чтобы Excel читал файл CSV Unicode, вы должны добавить Byte Order Mark как самую первую строку в csv. Это можно сделать с помощью JavaScript, добавив в код следующую строку:

line="\ufeff"+line