如何用C#将JSON1转换为符合特定规则的JSON2?
C# JSON转换:修正代码实现指定转换规则
转换规则
- 若键对应的值为数组,仅保留索引0的元素;
- 若TYPE数组位于DEVICE嵌套节点内,需删除TYPE数组值中除第0个元素对应的键值对之外的所有相关键值对。
输入JSON(JSON1)
{ "VERSION": "VERSION 2.3.0", "COMPONENT": { "0": { "SUBID": 1, "TYPE": "TYPE 1", "OUTPUT TYPE": [ "OUTPUT1", "OUTPUT2", "OUTPUT3" ], "UNIT": [ "UNIT1", "UNIT2", "UNIT3" ], "DEVICE": { "SUBID": 2, "TYPE": [ "DEVICE TYPE 1", "DEVICE TYPE 2", "DEVICE TYPE 3" ], "DEVICE TYPE 1": { "SUBID": 3, "TYPE": [ "TYPE A", "TYPE B", "TYPE C", "TYPE D" ], "COLD": [ "TRUE", "FALSE" ], "EXTERNAL": [ "ON", "OFF" ] }, "DEVICE TYPE 2": { "SUBID": 4, "TYPE": [ "TYPE X", "TYPE Y", "TYPE Z" ], "VALUE": 0.0, "CO-EFFS": 0.0 }, "DEVICE TYPE 3": { "SUBID": 5, "EXTRACTION": [ "1", "2" ], "EXTRACTION VALUE": 1.0, "APPROXIMATION": [ "OFF", "ON" ] } }, "CALIBRATION OFFSET AND GAIN": [ "DISABLE", "ENABLE" ] } } }
预期输出JSON(JSON2)
{ "VERSION": "VERSION 2.3.0", "COMPONENT": { "0": { "SUBID": 1, "TYPE": "TYPE 1", "OUTPUT TYPE": "OUTPUT1", "UNIT": "UNIT1", "DEVICE": { "SUBID": 2, "TYPE": "DEVICE TYPE 1", "DEVICE TYPE 1": { "SUBID": 3, "TYPE": "TYPE A", "COLD": "TRUE", "EXTERNAL": "ON" } }, "CALIBRATION OFFSET AND GAIN": "DISABLE" } } }
当前输出JSON
{ "VERSION": "VERSION 2.3.0", "COMPONENT": { "0": { "SUBID": 1, "TYPE": "TYPE 1", "OUTPUT TYPE": "OUTPUT1", "UNIT": "UNIT1", "DEVICE": { "SUBID": 2, "TYPE": "DEVICE TYPE 1", "DEVICE TYPE 1": { "SUBID": 3, "TYPE": "TYPE A", "COLD": "TRUE", "EXTERNAL": "ON" }, "DEVICE TYPE 2": { "SUBID": 4, "TYPE": "TYPE X", "VALUE": 0.0, "CO-EFFS": 0.0 }, "DEVICE TYPE 3": { "SUBID": 5, "EXTRACTION": "1", "EXTRACTION VALUE": 1.0, "APPROXIMATION": "OFF" } }, "CALIBRATION OFFSET AND GAIN": "DISABLE" } } }
当前尝试的代码
public static void Main(String[] args) { // change the file path //var root = JObject.Parse(File.ReadAllText("C:/Users/path_to_input_json/input.json")); var root = JObject.Parse(@"{ ""VERSION"":""VERSION 2.3.0"",""COMPONENT"":{ ""0"":{ ""SUBID"":1,""TYPE"":""TYPE 1"",""OUTPUT TYPE"":[""OUTPUT1"",""OUTPUT2"",""OUTPUT3""],""UNIT"":[""UNIT1"",""UNIT2"",""UNIT3""],""DEVICE"":{""SUBID"":2,""TYPE"":[""DEVICE TYPE 1"",""DEVICE TYPE 2"",""DEVICE TYPE 3""],""DEVICE TYPE 1"":{""SUBID"":3,""TYPE"":[""TYPE A"",""TYPE B"",""TYPE C"",""TYPE D""],""COLD"":[""TRUE"",""FALSE""],""EXTERNAL"":[""ON"",""OFF""] },""DEVICE TYPE 2"":{""SUBID"":4,""TYPE"":[""TYPE X"",""TYPE Y"",""TYPE Z""],""VALUE"":0,""CO-EFFS"":0},""DEVICE TYPE 3"":{""SUBID"":5,""EXTRACTION"":[""1"",""2""],""EXTRACTION VALUE"":1,""APPROXIMATION"":[""OFF"",""ON""]}},""CALIBRATION OFFSET AND GAIN"":[""DISABLE"",""ENABLE""]}}}"); var descendants = root.DescendantsAndSelf().ToList(); List<string> sensor_subtype_list = new List<string>(); foreach (var d in descendants) { var jProp = d as JProperty; if (jProp != null) { if (jProp?.Value is JArray array) { if (jProp.Name == "TYPE") { var value = jProp.Value as JArray; sensor_subtype_list = value.ToObject<List<string>>(); jProp.Value = jProp.Value[0]; } else { if (sensor_subtype_list.Count != 0) { if (sensor_subtype_list.Contains(jProp.Name) && jProp.Name != sensor_subtype_list[0]) { jProp.Remove(); } else { jProp.Value = jProp.Value[0]; } } else { jProp.Value = jProp.Value[0]; } } } else { if (sensor_subtype_list.Count != 0) { if (sensor_subtype_list.Contains(jProp.Name) && jProp.Name != sensor_subtype_list[0]) { jProp.Remove(); } } } } } Console.WriteLine(root.ToString()); }
问题分析与修正代码
原代码的问题在于使用全局的sensor_subtype_list,处理DEVICE节点内的TYPE数组后未及时清理上下文,导致无法准确删除DEVICE下多余的子节点,且遍历逻辑未覆盖嵌套节点的处理优先级。
修正后的代码采用递归方式处理每个节点,确保上下文独立,严格遵循转换规则:
using Newtonsoft.Json.Linq; using System; using System.Collections.Generic; using System.Linq; class Program { public static void Main(String[] args) { var root = JObject.Parse(@"{ ""VERSION"":""VERSION 2.3.0"",""COMPONENT"":{ ""0"":{ ""SUBID"":1,""TYPE"":""TYPE 1"",""OUTPUT TYPE"":[""OUTPUT1"",""OUTPUT2"",""OUTPUT3""],""UNIT"":[""UNIT1"",""UNIT2"",""UNIT3""],""DEVICE"":{""SUBID"":2,""TYPE"":[""DEVICE TYPE 1"",""DEVICE TYPE 2"",""DEVICE TYPE 3""],""DEVICE TYPE 1"":{""SUBID"":3,""TYPE"":[""TYPE A"",""TYPE B"",""TYPE C"",""TYPE D""],""COLD"":[""TRUE"",""FALSE""],""EXTERNAL"":[""ON"",""OFF""] },""DEVICE TYPE 2"":{""SUBID"":4,""TYPE"":[""TYPE X"",""TYPE Y"",""TYPE Z""],""VALUE"":0,""CO-EFFS"":0},""DEVICE TYPE 3"":{""SUBID"":5,""EXTRACTION"":[""1"",""2""],""EXTRACTION VALUE"":1,""APPROXIMATION"":[""OFF"",""ON""]}},""CALIBRATION OFFSET AND GAIN"":[""DISABLE"",""ENABLE""]}}}"); ProcessNode(root); Console.WriteLine(root.ToString()); } private static void ProcessNode(JToken node) { if (node is JObject obj) { // 先递归处理所有子属性,保证嵌套结构先完成转换 var properties = obj.Properties().ToList(); foreach (var prop in properties) { ProcessNode(prop.Value); } // 处理当前节点的TYPE数组逻辑 var typeProp = obj.Property("TYPE"); if (typeProp != null && typeProp.Value is JArray typeArray) { // 将TYPE数组替换为第一个元素 string keepTypeName = typeArray[0].ToString(); typeProp.Value = keepTypeName; // 删除TYPE数组中除第一个元素外对应的所有属性 var typesToRemove = typeArray.Skip(1).Select(t => t.ToString()); foreach (var typeName in typesToRemove) { obj.Property(typeName)?.Remove(); } } } else if (node is JArray array) { // 数组仅保留第一个元素,若元素是复杂类型则继续递归处理 if (array.Count > 0) { var firstElement = array[0].DeepClone(); array.ReplaceAll(firstElement); ProcessNode(firstElement); } } } }
修正说明
- 递归处理节点:确保所有嵌套层级的JSON结构都能被遍历和转换;
- 先子后父的处理顺序:先完成子节点的数组转换和清理,再处理当前节点的TYPE数组逻辑,避免上下文混乱;
- 精准删除冗余属性:针对TYPE数组所在的父节点,直接删除数组后续元素对应的属性,确保只保留指定节点;
- 数组转换逻辑:将所有数组替换为第一个元素,若元素是对象或数组则继续递归处理,保证嵌套数组也符合规则。
内容的提问来源于stack exchange,提问作者DeLorean
相关产品推荐
相关产品推荐

