繁体   English   中英

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

[英]Convert Nested JSON to CSV in C# via ChoETL

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

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

代码:

                 {
                     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"
            }
        ]
    }
}````

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

似乎控制序列化到 CSV 的最简单方法是从 JSON 正确定义源对象。 JSON 路径表达式非常方便。

我最终在这里做的是查询所有 JSON 以返回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());

Output:

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

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM