【问题标题】:How to convert a dynamic JSON like file to a CSV file如何将动态 JSON 文件转换为 CSV 文件
【发布时间】:2017-01-31 20:21:23
【问题描述】:

我有一个如下所示的文件。

{"eventid" : "12345" ,"name":"test1","age":"18"}
{"eventid" : "12346" ,"age":"65"}
{"eventid" : "12336" ,"name":"test3","age":"22","gender":"Male"}

把上面的文件想象成 event.json

数据对象的数量可能因行而异。 我想要以下 csv 输出。它将是 output.csv

eventid,name,age,gender
12345,test1,18
12346,,65
12336,test3,22,Male

有人可以帮助我吗?我可以接受任何脚本语言(Javascript、Python 等)的答案。

【问题讨论】:

    标签: json csv parsing data-conversion format-conversion


    【解决方案1】:

    此代码将动态收集所有标题并将文件写入 CSV。

    详情请阅读代码中的cmets:

    import json
    
    # Load data from file
    data = '''{"eventid" : "12345" ,"name":"test1","age":"18"}
    {"eventid" : "12346" ,"age":"65"}
    {"eventid" : "12336" ,"name":"test3","age":"22","gender":"Male"}'''
    
    # Store records for later use
    records = [];
    
    # Keep track of headers in a set
    headers = set([]);
    
    for line in data.split("\n"):
        line = line.strip();
    
        # Parse each line as JSON
        parsedJson = json.loads(line)
    
        records.append(parsedJson)
    
        # Make sure all found headers are kept in the headers set
        for header in parsedJson.keys():
            headers.add(header)
    
    # You only know what headers were there once you have read all the JSON once.
    
    #Now we have all the information we need, like what all possible headers are.
    
    outfile = open('output_json_to_csv.csv','w')
    
    # write headers to the file in order
    outfile.write(",".join(sorted(headers)) + '\n')
    
    for record in records:
        # write each record based on available fields
        curLine = []
        # For each header in alphabetical order
        for header in sorted(headers):
            # If that record has the field
            if record.has_key(header):
                # Then write that value to the line
                curLine.append(record[header])
            else:
                # Otherwise put an empty value as a placeholder
                curLine.append('')
        # Write the line to file
        outfile.write(",".join(curLine) + '\n')
    
    outfile.close()
    

    【讨论】:

    • 我可能会选择这个解决方案,因为您已经向其中添加了对未知标头的处理。如果能提前知道这个细节就好了。
    • {"eventid" : "12345" ,"name":"test1","age":18} {"eventid" : "12346" ,"age":65} {"eventid" : "12336" ,"name":"test3","age":22,"gender":"Male"} - 如果我通过年龄有整数它不起作用并引发错误。
    • @mmenschig 错误说 outfile.write(",".join(curLine) + '\n') 类型错误:序列项 0:预期字符串,找到 int。您应该能够从该消息中确定其失败的原因。请试一下,你认为这个错误是什么意思?
    【解决方案2】:

    这是使用jq 的解决方案。

    如果filter.jq 包含以下过滤器

      (reduce (.[]|keys_unsorted[]) as $k ({};.[$k]="")) as $o   # object with all keys
    | ($o  | keys_unsorted), (.[] | $o * . | [.[]])              # generate header and data
    | join(",")                                                  # convert to csv
    

    然后data.json 包含样本数据

    $ jq -Mrs -f filter.jq data.json
    

    生产

    eventid,name,age,gender
    12345,test1,18,
    12346,,65,
    12336,test3,22,Male
    

    【讨论】:

      【解决方案3】:

      这是一个 Python 解决方案(应该适用于 Python 2 和 3)。 我对代码并不感到自豪,因为可能有更好的方法来做到这一点(使用 csv 模块),但这会给你想要的输出。

      我冒昧地将您的 JSON 数据命名为 data.json,并将输出 csv 文件命名为 output.csv

      import json
      
      header = ['eventid', 'name', 'age', 'gender']
      
      with open('data.json', 'r') as infile, \
           open('outfile.csv', 'w+') as outfile:
      
          # Writes header row
          outfile.write(','.join(header))
          outfile.write('\n')
      
          for row in infile:
              line = ['', '', '', ''] # I'm sure there's a better way
              datarow = json.loads(row)
      
              for key in datarow:
                  line[header.index(key)] = datarow[key]
      
              outfile.write(','.join(line))
              outfile.write('\n')
      

      希望这会有所帮助。

      【讨论】:

      • 嗨,这对一个大问题来说很棒(我可能不太清楚)。如果我不知道可能的标题怎么办?假设我的 data.json 文件的下一行现在有“地址”。有没有办法解决这个问题?
      • 哈,这改变了这个练习的整个性质。所以你是说你不知道实际的标题行是什么,以及它是否是一个新条目以将其附加到末尾?
      【解决方案4】:

      使用 Angularjs 和 ngCsv 插件,我们可以从所需的带有动态标题的 json 生成 csv 文件。

      Run in plunkr

      // Code goes here
      
       var myapp = angular.module('myapp', ["ngSanitize", "ngCsv"]);
      
       myapp.controller('myctrl', function($scope) {
         $scope.filename = "test";
         $scope.getArray = [{
           label: 'Apple',
           value: 2,
           x:1,
         }, {
           label: 'Pear',
           value: 4,
           x:38
         }, {
           label: 'Watermelon',
           value: 4,
           x:38
         }];
      
      
         $scope.getHeader = function() {
          var vals = [];
          for( var key in $scope.getArray ) {
          for(var k in $scope.getArray[key]){
            vals.push(k);
           }
           break;
          }
          return vals;
          
         };
      
       });
      <!DOCTYPE html>
      <html>
        <head>
          <link href="https://netdna.bootstrapcdn.com/bootstrap/3.0.0/css/bootstrap.min.css" rel="stylesheet">
      
          <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular.min.js"></script>
      
         <script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.4.7/angular-sanitize.min.js"></script>
         
      	<script src="https://cdnjs.cloudflare.com/ajax/libs/ng-csv/0.3.6/ng-csv.min.js"></script>
         
      
        </head>
      
      
        <body>
      
          <div ng-app="myapp">
      
            <div class="container" ng-controller="myctrl">
      
              <div class="page-header">
      
                <h1>ngCsv <small>example</small></h1>
      
              </div>
             
              
      
              <button class="btn btn-default" ng-csv="getArray" csv-header="getHeader()" filename="{{ filename }}.csv" field-separator="," decimal-separator=".">Export to CSV with header</button>
      
             
            </div>
          </div>
        </body>
      </html>

      【讨论】:

        【解决方案5】:
        var arr = $.map(obj, function(el) { return el });
        var content = "";
        for(var element in arr){
            content += element + ",";
        }
        
        var filePath = "someFile.csv";
        var fso = new ActiveXObject("Scripting.FileSystemObject");
        var fh = fso.OpenTextFile(filePath, 8, false, 0);
        fh.WriteLine(content);
        fh.Close();
        

        【讨论】:

        • 对不起,我不确定你的意思。我想动态捕获列标题。
        • 初始文件类似于 events.json,输出将在 output.csv 中。你跟吗?我会在哪里传递这个脚本上的 event.json 文件的位置?
        猜你喜欢
        • 2019-02-23
        • 2021-01-31
        • 1970-01-01
        • 2020-10-07
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多