通过 ChoETL 在 C# 中将嵌套 JSON 转换为 CSV

Convert Nested JSON to CSV in C# via ChoETL

有谁知道如何通过 CHOETL(.NET 的 ETL 框架)将下面嵌套的 JSON 转换为 CSV?谢谢!

我正在使用此代码,但它只会 return 第一个设备记录。

代码:

                 {
                     using (var json = new ChoJSONReader("./test.json"))
                     {
                         csv.Write(json.Cast<dynamic>().Select(i => new
                         {
                             EquipmentId = i.GpsLocation.Equipment[0].EquipmentId,
                             InquiryValue = i.GpsLocation.Equipment[0].InquiryValue,
                             Timestamp = i.GpsLocation.Equipment[0].Timestamp

                         }));
                     }
                 }

JSON:

    "GpsLocation": {
        "Equipment": [
            {
                "EquipmentId": "EQ00001",
                "InquiryValue": [
                    "IV00001"
                ],
                "Timestamp": "2020-01-01 01:01:01.01",
            },
            {
                "EquipmentId": "EQ00002",
                "InquiryValue": [
                    "IV00002"
                ],
                "Timestamp": "2020-01-01 01:01:01.01"
            }
        ]
    }
}````

您的代码是正确的,但问题是您只是使用 i.GpsLocation.Equipment[0] 写入数组中的第一个变量。相反,尝试通过将所有内容放入 for 循环来遍历所有内容,并将 [0] 更改为所述循环内的迭代变量。

正如其他人所建议的,问题是您只查看了数组的第一个元素。

看来控制序列化为 CSV 的内容的最简单方法是从 JSON 正确定义源对象。 JSON Path expressions 派上用场。

我最后在这里做的是查询所有 JSON 到 return Equipment 个对象的数组 不管它们在层次结构中的位置(这意味着您可能需要根据完整 JSON 更好地过滤它)。 然后很容易根据JSON路径定义每个字段并将结果传递给CSVWriter

另请查看我在相应评论行中概述的一些问题。

void Main()
{
    var jsonString = "{\"GpsLocation\":{\"Equipment\":[{\"EquipmentId\":\"EQ00001\",\"InquiryValue\":[\"IV00001\"],\"Timestamp\":\"2020-01-01 01:01:01.01\"},{\"EquipmentId\":\"EQ00002\",\"InquiryValue\":[\"IV00002\"],\"Timestamp\":\"2020-01-01 01:01:01.01\"}]}}";
    var jsonReader = new StringReader(jsonString);
    var csvWriter = new StringWriter(); // outputs to string, comment out if you want file output
    //var csvWriter = new StreamWriter(".\your_output.csv"); // writes to a file of your choice
    using (var csv = new ChoCSVWriter(csvWriter))
    using (var json = new ChoJSONReader(jsonReader)
                        .WithJSONPath("$..Equipment[*]", true) // firstly you scope the reader to all Equipment objects. take note of the second parameter. Apparently you need to pass true here as otherwise it just won't return anythig
                        .WithField("EquipmentId", jsonPath: "$.EquipmentId", isArray: false) // then you scope each field in the array to what you want it to be. Since you want scalar values, pass `isArray: false` for better predictability
                        .WithField("InquiryValue", jsonPath: "$.InquiryValue[0]", isArray: false) // since your InquiryValue is actually an array, you want to obtain first element here. if you don't do this, fields names and values would go askew
                        .WithField("Timestamp", jsonPath: "$.Timestamp", fieldType: typeof(DateTime), isArray: false)) // you can also supply field type, otherwise it seems to default to `string`
    {   
        csv.WithFirstLineHeader().Write(json);
    }
    Console.WriteLine(csvWriter.GetStringBuilder().ToString()); // comment this out if writing to file - you won't need it
}

更新摘要:

  1. 转向更新代码以依赖 JSON 路径范围 - 这似乎允许以非常低的努力进行字段名称操作
  2. 看看你的评论,你可能会稍微简化你的文件编写器 - 使用 StreamWriter 而不是 StringWriter - 例如查看更新的代码

这是从您的 JSON

生成 CSV 的工作示例
string json = @"{
""GpsLocation"": {
        ""Equipment"": [
            {
                ""EquipmentId"": ""EQ00001"",
                ""InquiryValue"": [
                    ""IV00001""
                ],
                ""Timestamp"": ""2020-02-01 01:01:01.01"",
            },
            {
                ""EquipmentId"": ""EQ00002"",
                ""InquiryValue"": [
                    ""IV00002""
                ],
                ""Timestamp"": ""2020-01-01 01:01:01.01""
            }
        ]
    }
}";

StringBuilder csv = new StringBuilder();

using (var r = ChoJSONReader.LoadText(json)
    .WithJSONPath("$.GpsLocation.Equipment")
    .WithField("EquipmentId")
    .WithField("InquiryValue", jsonPath: "InquiryValue[0]", fieldType: typeof(string))
    .WithField("Timestamp", fieldType: typeof(DateTime))
    )
{
    using (var w = new ChoCSVWriter(csv)
        .WithFirstLineHeader())
        w.Write(r);
}
Console.WriteLine(csv.ToString());

输出:

EquipmentId,InquiryValue,Timestamp
EQ00001,IV00001,2/1/2020 1:01:01 AM
EQ00002,IV00002,1/1/2020 1:01:01 AM

样本fiddle:https://dotnetfiddle.net/hJWtqH