簡體   English   中英

使用 / header 分隔符將 CSV 轉換為嵌套 JSON

[英]Convert CSV to Nested JSON using / header delimiter

我的 CSV 標頭看起來像

來自/電子郵件 到/0/電子郵件 個性化/0/電子郵件/ 個性化/0/data/first_name 個性化/0/數據/公司名稱 個性化/0/data/job_title 模板編號

Output 應該是:

[
 {
   "from": {
      "email": "me@x.com",
      "name": "Me"
   },
   "to": [
      {
         "email": "mike@x.com"
      }
   ],
   "personalization": [
      {
         "email": "mike@x.com",
         "data": {
            "first_name": "Mike",
            "company_name": "X.com",
            "job_title": "Chef"
         }
      }
   ],
   "template_id": "123456"
},

我試過了

csvjson input.csv output.csv
csvtojson input.csv output.csv
csv2json input.csv output.csv
python3 app.py

import csv 
import json 

def csv_to_json(csvFilePath, jsonFilePath):
    jsonArray = []
      
    #read csv file
    with open(csvFilePath, encoding='utf-8') as csvf: 
        #load csv file data using csv library's dictionary reader
        csvReader = csv.DictReader(csvf) 

        #convert each csv row into python dict
        for row in csvReader: 
            #add this python dict to json array
            jsonArray.append(row)
  
    #convert python jsonArray to JSON String and write to file
    with open(jsonFilePath, 'w', encoding='utf-8') as jsonf: 
        jsonString = json.dumps(jsonArray, indent=4)
        jsonf.write(jsonString)
          
csvFilePath = r'outputt1.csv'
jsonFilePath = r'outputt1.json'
csv_to_json(csvFilePath, jsonFilePath)
node app.js

const CSVToJSON = require('csvtojson');

// convert users.csv file to JSON array
CSVToJSON().fromFile('outputt1.csv')
    .then(from => {

        // from is a JSON array
        // log the JSON array
        console.log(from);
    }).catch(err => {
        // log error if any
        console.log(err);
    });

所有 output 單行 JSON 的一些變體,沒有嵌套。

唯一可行的是將其上傳到https://www.convertcsv.com/csv-to-json.htm並手動轉換每個文件,但這顯然不是解決方案。

我看到一個帖子推薦 Choetl.Json 用於這個確切的目的,但無法在 mac 上安裝它

您的問題應該分為兩部分:解析 CSV 數據以轉換為 JSON,並按照類似路徑的說明構建 JSON 結構。

對於第一部分,有必要澄清 CSV 輸入的格式,因為 CSV 沒有通用標准,只是RFC 4180 提案中的基本描述以及針對特定用例或數據類型量身定制的大量采用。 為了簡單起見,我們假設記錄由換行符分隔,字段由逗號分隔,並且沒有字段分隔符,因為數據本身從不包含任何這些分隔符。 讓我們進一步假設恰好有一個(第一個)記錄表示標題,並且所有記錄都具有完全相同數量的字段。 您可能希望將這些假設調整為您的實際 CSV 數據。

然后,要讀入 CSV 數據,請使用-R選項將輸入視為以換行符分隔的原始文本行,並使用/運算符拆分行:

cat input.csv
from/email,to/0/email,personalization/0/email,personalization/0/data/first_name,personalization/0/data/company_name,personalization/0/data/job_title,template_id
me@x.com,mike@x.com,mike@x.com,Mike,X.com,Chef,123456
jq -R '. / ","' input.csv
[
  "from/email",
  "to/0/email",
  "personalization/0/email",
  "personalization/0/data/first_name",
  "personalization/0/data/company_name",
  "personalization/0/data/job_title",
  "template_id"
]
[
  "me@x.com",
  "mike@x.com",
  "mike@x.com",
  "Mike",
  "X.com",
  "Chef",
  "123456"
]

演示

As for the second part, you can make use of functions like setpath which interpret arrays as object structure paths, then split your header names into an array using / again, and build up your JSON objects by iterating through the fields using a reduce statement. 我還假設 header 路徑中的數字始終表示數組 inices(並且從不具有看起來像數字的字符串名稱的字段名稱)。 我使用tonumber將它們轉換,並使用transpose將 header 字段與數據字段對齊:

… | jq -s '
  (.[0] | map(. / "/" | map(tonumber? // .))) as $headers
  | .[1:] | map(
    reduce ([$headers, .] | transpose[]) as [$path, $value] (
      {}; setpath($path; $value)
    )
  )
'
[
  {
    "from": {
      "email": "me@x.com"
    },
    "to": [
      {
        "email": "mike@x.com"
      }
    ],
    "personalization": [
      {
        "email": "mike@x.com",
        "data": {
          "first_name": "Mike",
          "company_name": "X.com",
          "job_title": "Chef"
        }
      }
    ],
    "template_id": "123456"
  }
]

演示

你可能想試試米勒 它以static 二進制文件的形式提供,因此您只需將mlr可執行文件放在某處(最好在您的 PATH 中)即可完成安裝。

mlr --icsv --ojson --jflatsep / cat file.csv

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM