【问题标题】:Parse XLSX with Node and create json使用 Node 解析 XLSX 并创建 json
【发布时间】:2015-08-31 19:38:23
【问题描述】:

好的,所以我发现 node_module 被称为 js-xlsx 的文档记录得很好

问题:如何解析 xlsx 以输出 json

Excel 工作表如下所示:

最终json应该是这样的:

[
   {
   "id": 1,
   "Headline": "Team: Sally Pearson",
   "Location": "Austrailia",
   "BodyText": "...",
   "Media: "..."
   },
   {
   "id": 2,
   "Headline": "Team: Rebeca Andrade",
   "Location": "Brazil",
   "BodyText": "...",
   "Media: "..."
   }
]

index.js:

if(typeof require !== 'undefined') {
    console.log('hey');
    XLSX = require('xlsx');
}
var workbook = XLSX.readFile('./assets/visa.xlsx');
var sheet_name_list = workbook.SheetNames;
sheet_name_list.forEach(function(y) { /* iterate through sheets */
  var worksheet = workbook.Sheets[y];
  for (z in worksheet) {
    /* all keys that do not begin with "!" correspond to cell addresses */
    if(z[0] === '!') continue;
    // console.log(y + "!" + z + "=" + JSON.stringify(worksheet[z].v));

  }

});
XLSX.writeFile(workbook, 'out.xlsx');

【问题讨论】:

  • 你想达到什么目的?如果您只想以 json 结构共享 Excel 工作表,或者只是将 Excel 工作表基于云以方便共享,那么有很多产品可以做这样的事情。例如ipushpull.com
  • 花钱。而且我知道这个库会完成手头的简单任务
  • 也有试用版,但如果你想使用比原始库更用户友好的东西,基本上你需要付费。从您的问题来看,您并不清楚您要达到什么目标或问题是什么。您是否想将第一行添加到最终的 json 中?
  • 更新了问题的可读性
  • 您不能将文档另存为 CSV 吗?这将使解析更加简单,文档似乎也不包含任何丰富的格式。

标签: javascript json node.js excel xlsx


【解决方案1】:

我认为这段代码会做你想做的事。它将第一行存储为一组标头,然后将其余行存储在一个数据对象中,您可以将其作为 JSON 写入磁盘。

var XLSX = require('xlsx');
var workbook = XLSX.readFile('test.xlsx');
var sheet_name_list = workbook.SheetNames;
sheet_name_list.forEach(function(y) {
    var worksheet = workbook.Sheets[y];
    var headers = {};
    var data = [];
    for(z in worksheet) {
        if(z[0] === '!') continue;
        //parse out the column, row, and value
        var col = z.substring(0,1);
        var row = parseInt(z.substring(1));
        var value = worksheet[z].v;

        //store header names
        if(row == 1) {
            headers[col] = value;
            continue;
        }

        if(!data[row]) data[row]={};
        data[row][headers[col]] = value;
    }
    //drop those first two rows which are empty
    data.shift();
    data.shift();
    console.log(data);
});

打印出来

[ { id: 1,
    headline: 'team: sally pearson',
    location: 'Australia',
    'body text': 'majority have…',
    media: 'http://www.youtube.com/foo' },
  { id: 2,
    headline: 'Team: rebecca',
    location: 'Brazil',
    'body text': 'it is a long established…',
    media: 'http://s2.image.foo/' } ]

【讨论】:

  • 你就是乔希!我对保存文件进行了一些编辑。享受你的赏金
  • 我想读取一个 xlsx 文件并将该数据转换为 JSON。这有可能吗?还有其他建议吗??
  • 非常非常好!只发现一件事:当列名以AAAB 开头时,代码会丢失宽表的列...因为这些行var col = z.substring(0,1);var row = parseInt(z.substring(1));。将其更改为const column = z.replace(/[0-9]/g, '')const row = parseInt(z.replace(/\D/g,'')),现在它可以完全正常工作了。
  • 很好,但是它跳过了工作表中的空白单元格,这些单元格对我来说应该是 null 或 '',例如:K 列的标题是重量,k1 的值为 72,所以它返回因为重量:'72',k3 值为 65,所以重量:'65',但 k2 单元格留空,所以它没有返回任何东西,我想要重量:''或重量:null,如果我有任何解决方案,它将是给我很大的安慰,请帮我解决这个问题,非常感谢
【解决方案2】:

“Josh Marinacci”答案的改进版本,它将超出 Z 列(即 AA1)。

var XLSX = require('xlsx');
var workbook = XLSX.readFile('test.xlsx');
var sheet_name_list = workbook.SheetNames;
sheet_name_list.forEach(function(y) {
    var worksheet = workbook.Sheets[y];
    var headers = {};
    var data = [];
    for(z in worksheet) {
        if(z[0] === '!') continue;
        //parse out the column, row, and value
        var tt = 0;
        for (var i = 0; i < z.length; i++) {
            if (!isNaN(z[i])) {
                tt = i;
                break;
            }
        };
        var col = z.substring(0,tt);
        var row = parseInt(z.substring(tt));
        var value = worksheet[z].v;

        //store header names
        if(row == 1 && value) {
            headers[col] = value;
            continue;
        }

        if(!data[row]) data[row]={};
        data[row][headers[col]] = value;
    }
    //drop those first two rows which are empty
    data.shift();
    data.shift();
    console.log(data);
});

【讨论】:

  • 伙计,我希望两年后你不要再调用变量yztt,更新你的代码是一个巨大的痛苦
  • 这里到底发生了什么?什么是z? tt是什么?
  • @StormMuller 看到我的回答它有角度解决方案,变量的正常命名
  • 它有效,但如何?查看变量的命名,如果需要更改某些内容,则必须对过程进行逆向工程。下面的答案具有相同的代码,但命名更好。
【解决方案3】:

你也可以使用

var XLSX = require('xlsx');
var workbook = XLSX.readFile('Master.xlsx');
var sheet_name_list = workbook.SheetNames;
console.log(XLSX.utils.sheet_to_json(workbook.Sheets[sheet_name_list[0]]))

【讨论】:

  • 它不返回空值,这意味着如果值为空,它不会添加到json中
  • 是的,默认情况下它不处理空白单元格,但通过将可选参数传递给 XLSX.readFile 函数是一种解决方法。 var workbook = XLSX.readFile('Master.xlsx', {sheetStubs: true});可选对象中的 sheetStubs 参数允许库列出默认情况下被库的数据处理实用程序忽略的单元格。
  • 请注意它应该是XLSX.utils.sheet_to_json(sheet, {defval: ""}) 而不是XLSX.utils.sheet_to_json(sheet, {defVal=""})
【解决方案4】:

这里是 Angular 5 方法版本,对于那些在接受的答案中与 yztt 苦苦挣扎的人来说,它的语法没有缩小。用法:parseXlsx().subscribe((data)=&gt; {...})

parseXlsx() {
    let self = this;
    return Observable.create(observer => {
        this.http.get('./assets/input.xlsx', { responseType: 'arraybuffer' }).subscribe((data: ArrayBuffer) => {
            const XLSX = require('xlsx');
            let file = new Uint8Array(data);
            let workbook = XLSX.read(file, { type: 'array' });
            let sheetNamesList = workbook.SheetNames;

            let allLists = {};
            sheetNamesList.forEach(function (sheetName) {
                let worksheet = workbook.Sheets[sheetName];
                let currentWorksheetHeaders: object = {};
                let data: Array<any> = [];
                for (let cellName in worksheet) {//cellNames example: !ref,!margins,A1,B1,C1

                    //skipping serviceCells !margins,!ref
                    if (cellName[0] === '!') {
                        continue
                    };

                    //parse colName, rowNumber, and getting cellValue
                    let numberPosition = self.getCellNumberPosition(cellName);
                    let colName = cellName.substring(0, numberPosition);
                    let rowNumber = parseInt(cellName.substring(numberPosition));
                    let cellValue = worksheet[cellName].w;// .w is XLSX property of parsed worksheet

                    //treating '-' cells as empty on Spot Indices worksheet
                    if (cellValue.trim() == "-") {
                        continue;
                    }

                    //storing header column names
                    if (rowNumber == 1 && cellValue) {
                        currentWorksheetHeaders[colName] = typeof (cellValue) == "string" ? cellValue.toCamelCase() : cellValue;
                        continue;
                    }

                    //creating empty object placeholder to store current row
                    if (!data[rowNumber]) {
                        data[rowNumber] = {}
                    };

                    //if header is date - for spot indices headers are dates
                    data[rowNumber][currentWorksheetHeaders[colName]] = cellValue;

                }

                //dropping first two empty rows
                data.shift();
                data.shift();
                allLists[sheetName.toCamelCase()] = data;
            });

            this.parsed = allLists;

            observer.next(allLists);
            observer.complete();
        })
    });
}

【讨论】:

    【解决方案5】:

    我找到了更好的方法

      function genrateJSONEngine() {
        var XLSX = require('xlsx');
        var workbook = XLSX.readFile('test.xlsx');
        var sheet_name_list = workbook.SheetNames;
        sheet_name_list.forEach(function (y) {
          var array = workbook.Sheets[y];
    
          var first = array[0].join()
          var headers = first.split(',');
    
          var jsonData = [];
          for (var i = 1, length = array.length; i < length; i++) {
    
            var myRow = array[i].join();
            var row = myRow.split(',');
    
            var data = {};
            for (var x = 0; x < row.length; x++) {
              data[headers[x]] = row[x];
            }
            jsonData.push(data);
    
          }
    

    【讨论】:

      【解决方案6】:
      **podria ser algo asi en react y electron**
      
       xslToJson = workbook => {
              //var data = [];
              var sheet_name_list = workbook.SheetNames[0];
              return XLSX.utils.sheet_to_json(workbook.Sheets[sheet_name_list], {
                  raw: false,
                  dateNF: "DD-MMM-YYYY",
                  header:1,
                  defval: ""
              });
          };
      
          handleFile = (file /*:File*/) => {
              /* Boilerplate to set up FileReader */
              const reader = new FileReader();
              const rABS = !!reader.readAsBinaryString;
      
              reader.onload = e => {
                  /* Parse data */
                  const bstr = e.target.result;
                  const wb = XLSX.read(bstr, { type: rABS ? "binary" : "array" });
                  /* Get first worksheet */
                  let arr = this.xslToJson(wb);
      
                  console.log("arr ", arr)
                  var dataNueva = []
      
                  arr.forEach(data => {
                      console.log("data renaes ", data)
                  })
                  // this.setState({ DataEESSsend: dataNueva })
                  console.log("dataNueva ", dataNueva)
      
              };
      
      
              if (rABS) reader.readAsBinaryString(file);
              else reader.readAsArrayBuffer(file);
          };
      
          handleChange = e => {
              const files = e.target.files;
              if (files && files[0]) {
                  this.handleFile(files[0]);
              }
          };
      

      【讨论】:

      • 欢迎来到 Stackoverflow! :D 如果你评论你的代码或在你的正文中添加一些内容来澄清你的答案,这将使你的答案更好、更容易理解。
      • @AN German 你救了我的命,今天进行产品部署,我用这段代码修复了它,非常感谢
      【解决方案7】:

      这是我使用一些 ramdas 助手的解决方案(在打字稿中)。它支持多个工作表,并返回一个以 key 作为工作表名称的对象。

      const parseXLSX = (file: File, cb: callback) => {
        const reader = new FileReader()
        const rABS = !!reader.readAsBinaryString
      
        reader.onload = (e) => {
          const bstr = e?.target?.result
          const wb = XLSX.read(bstr, { type: rABS ? 'binary' : 'array' })
          const sheetNames = wb.SheetNames
          const sheetsData = sheetNames.reduce((acc, sheetName) => {
            const worksheet = wb.Sheets[sheetName]
            const headers: Record<string, string> = {}
            const data: Record<string, unknown>[] = []
      
            keys(worksheet).forEach((key) => {
              // removes !ref column
              if (String(key)?.[0] !== '!') {
                // supports wide tables ex: AA1
                const column = String(key).replace(/[0-9]/g, '')
                const row = parseInt(String(key).replace(/\D/g, ''), 10)
                const value = worksheet[key].v
      
                if (row === 1) {
                  headers[column] = value
                }
      
                // this solution does not support when header is not first row
                if (headers[column] !== undefined) {
                  if (!data[row]) {
                    data[row] = {}
                  }
      
                  data[row][headers[column]] = value
                }
              }
            })
      
            return {
              ...acc,
              [sheetName]: drop(1, data.filter(Boolean)),
            }
          }, {})
      
          cb(sheetsData)
        }
        if (rABS) reader.readAsBinaryString(file)
        else reader.readAsArrayBuffer(file)
      }
      
      

      【讨论】:

        【解决方案8】:

        只是稍微改进了@parijat 的答案。

        var XLSX = require('xlsx');
            var workbook = XLSX.readFile('test.xlsx');
            var sheet_name_list = workbook.SheetNames;
            sheet_name_list.forEach(function(y) {
                var worksheet = workbook.Sheets[y];
                var headers = {};
                var data = [];
                for(z in worksheet) {
                    if(z[0] === '!') continue;
                    //parse out the column, row, and value
                    var tt = 0;
                    for (var i = 0; i < z.length; i++) {
                        if (!isNaN(z[i])) {
                            tt = i;
                            break;
                        }
                    };
                    var col = z.substring(0,tt);
                    var row = parseInt(z.substring(tt));
                    var value = worksheet[z].v;
            
                    //store header names
                    if(row == 1 && value) {
                        headers[col] = value;
                        continue;
                    }
            
                    if(!data[row-2]) data[row-2]={};
                    data[row-2][headers[col]] = value;
                }
                //Now no need to drop the data element
                console.log(data);
            });
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 2014-04-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-11-13
          • 1970-01-01
          相关资源
          最近更新 更多