如何从字符串数组在 json 字符串中创建层次结构?
Posted
技术标签:
【中文标题】如何从字符串数组在 json 字符串中创建层次结构?【英文标题】:How to create hierarchy in json string from string array? 【发布时间】:2018-02-10 11:50:34 【问题描述】:我正在尝试为如下层次结构生成 json 字符串:
Company(select * from Company)
Department(select * from Department)
Employee(select * from Employee)
上述每个查询都将返回如下字段:
Company Fields - (Id,Name,Location)
Department Fields - (Id,Name,CompanyId)
Employee Fields - (Id,Name,DepartmentId)
现在我正在尝试为上述实体生成 JSON 字符串,如下所示:
预期输出:
"Id": "",
"Name": "",
"Location": "",
"Department":
"Id": "",
"Name": "",
"CompanyId": "",
"Employee" :
"Id": "",
"Name": "",
"DepartmentId": "",
代码:
public string GetData(Child model,List<Parent> parents)
var fields = new List<string[]>();
if (parents != null)
foreach (var parent in parents)
var columns = GetColumns(parent); //returns string[] of columns
fields.Add(columns);
fields.Add(GetColumns(model));
string json = JsonConvert.SerializeObject(fields.ToDictionary(key => key, v => string.Empty),
Formatting.Indented);
return json;
现在,当我没有任何父母并且想为唯一的孩子生成 json 字符串时,下面的代码可以正常工作:
string json = JsonConvert.SerializeObject(fields.ToDictionary(key => key, v => string.Empty),Formatting.Indented)
输出:
"Id": "",
"Name": "",
"Location": "",
但现在我想用任何这种内置方式为我的层次结构生成 JSON。
我知道我可以循环、追加和创建 json 字符串,但我想以更好的方式做到这一点,就像我为我的孩子所做的那样。
更新:
public class Child
public string Name get; set; // Contains Employee
//Other properties and info related to process sql query and connection string
public class Parent
public string Name get; set; // Contains Company,Department.
public string SqlQuery get; set; // query related to Company and Department.
//Other properties and info related to connection string
【问题讨论】:
你也可以分享你的孩子和家长课程吗? @lancew我没有任何问题可以共享子类和父类,但是我对这两个类有不同的结构,因此我正在做一些操作,然后我的 GetColumns 方法基于这些操作返回列。因此我没有共享 Child 和 Parent 类的代码,因为我认为它在这里不相关 好吧,也许他们不是。据我所知,您的 GetData 函数似乎具有向后的参数。不应该有一个父母有很多孩子吗?另外,我不确定是否有任何简单的方法可以序列化字符串 List 以获得所需的输出。您必须将列及其值添加到嵌套字典或其他内容中。 @lancew 我只希望我的所有值都为空,您能否为您所说的内容添加更多详细信息,例如嵌套字典 【参考方案1】:我创建了一个类,该类在子父结构中保存与您建议的信息类似的信息。我还添加了一个自定义的小解析器,它可以递归地工作。也许这就是您所需要的和/或为您提供解决问题所需的想法。
我还通过添加尖括号 ("[ ]" ) 稍微改变了输出。我认为这就是您对多个孩子所需要的。至少这是我在下面发布的 JSON 验证器告诉我的。如果您不需要/不想要它们,只需在解析器中删除它们即可。
我不认为你可以使用你在你的例子中使用的解析器,而没有像我在之前的答案中展示的某种形式的额外字段,因为这些解析器通常将属性名称作为字段,我猜你没有想要在运行时动态创建类。
我也不认为您可以创建与列表、数组或字典的父-子-子-子...关系的动态深度,因为这些结构很快就有了深度正如他们所声明的那样。
类:
public class MyJsonObject
public List<string> Columns = new List<string>();
public string ChildName;
public List<MyJsonObject> Children = new List<MyJsonObject>();
解析器:
class JsonParser
public static string Parse(MyJsonObject jsonObject)
string parse = "";
parse += string.Join(",", jsonObject.Columns.Select(column => $"\"column\": \"\""));
if (!string.IsNullOrEmpty(jsonObject.ChildName))
parse += $",\"jsonObject.ChildName\":";
parse += $"[string.Join(",", jsonObject.Children.Select(Parse))]";
parse += "";
return parse;
用法:
class Program
static void Main(string[] args)
MyJsonObject company = new MyJsonObject();
company.ChildName = "Department";
company.Columns.Add("Id");
company.Columns.Add("Name");
company.Columns.Add("Location");
MyJsonObject department = new MyJsonObject();
department.ChildName = "Employee";
department.Columns.Add("Id");
department.Columns.Add("Name");
department.Columns.Add("CompanyId");
MyJsonObject employee1 = new MyJsonObject();
employee1.Columns.Add("Id");
employee1.Columns.Add("Name");
employee1.Columns.Add("DepartmentId");
MyJsonObject employee2 = new MyJsonObject();
employee2.Columns.Add("Id");
employee2.Columns.Add("Name");
employee2.Columns.Add("DepartmentId");
company.Children.Add(department);
department.Children.Add(employee1);
department.Children.Add(employee2);
var json = JsonParser.Parse(company);
输出和链接到 JSON 验证器:
https://jsonformatter.curiousconcept.com/
"Id":"",
"Name":"",
"Location":"",
"Department":[
"Id":"",
"Name":"",
"CompanyId":"",
"Employee":[
"Id":"",
"Name":"",
"DepartmentId":""
,
"Id":"",
"Name":"",
"DepartmentId":""
]
]
【讨论】:
我已经在我的回答中写了我的最终预期输出 json 字符串。我还指定我只对每个父母和孩子进行 sql 查询,在执行这些查询后我得到列数组(字符串 [])。您的输出 json 与我预期的输出 json 不匹配。我没有每个列的值。我只有列的名称 赞成您为帮助我所做的努力,但部门 json 和员工 json 仍然存在问题,我只想要一个对象而不是数组。请参阅我预期的 json 输出中的 Employee 和 Department 属性 那么你基本上想要的是每个公司只有一个部门,每个部门只有一个员工? 看这里我不关心每个公司只有一个部门和员工的记录。现在即使 1 家公司将有超过 1 个部门并且 1 个部门将有超过 1 名员工,我仍然应该得到我在预期输出中显示的 json 结构。因此我不关心公司、员工和部门之间的一对多关系。 对不起,如果我在这里看起来有点慢,但它与您提出的预期输出究竟有什么不同?我在这里看到的唯一区别是孩子的数量和尖括号“[]”。到底有什么不合适的?【参考方案2】:也许我错过了什么。如果你在 heirachy 中创建你需要的类,用数据实例化它们,然后序列化它们,就会为你创建结构。
using System.Web.Script.Serialization;
public class Employee
public int Id get; set;
public string Name get; set;
public int DepartmentId get; set;
public class Department
public int Id get; set;
public string Name get; set;
public string CompanyId get; set;
public List<Employee> get; set;
public class Company
public int Id get; set;
public string Name get; set;
public string Location get; set;
public List<Department> get; set;
var myCompany = new Company();
// add departments and employees
var json = new javascriptSerializer().Serialize(myCompany);
【讨论】:
很抱歉,但问题是我没有固定的表格。这只是我在问题中展示的一个示例(公司、部门、员工)。所以我不能预定义类【参考方案3】:您可以使用动态:
//here your database
dynamic[] company = new object[] new Name = "Company1", DepartmentId = 1 , new Name = "Company2", DepartmentId = 2 ;
dynamic[] department = new object[] new DepartmentId = 1, Name = "Department1" , new DepartmentId = 2, Name = "Department2" ;
//select from database
var data = from c in company
join d in department on c.DepartmentId equals d.DepartmentId
select new Name = c.Name, Department = d;
var serialized = JsonConvert.SerializeObject(data);
结果:
[
"Name": "Company1",
"Department":
"DepartmentId": 1,
"Name": "Department1"
,
"Name": "Company2",
"Department":
"DepartmentId": 2,
"Name": "Department2"
]
【讨论】:
很抱歉,您在这里提前修复了属性,但我没有任何固定的表。所以基本上我正在接收一个查询并使用连接字符串信息执行它。这就是我使用字符串的原因数组,因为我没有关于字段的任何信息。这取决于查询。查询也会有连接 所以你执行查询并得到什么?无论如何你可以创建一个动态对象然后序列化它 我执行了一个查询,我得到了列的字符串 []。GetColumns 执行该方法并返回我有列名称的字符串 [] 数组。 @Learning 也许 Timur 正在做一些动态的事情。您可以使用 ExpandObject 并动态创建您的字段,然后尝试按照 Timur 的建议对它们进行序列化(请参阅***.com/questions/6196022/…)【参考方案4】:好的,让我们试试这样。首先,我理解你的难题:你有父母和孩子的属性数组,你需要将它转换为 json 对象。 重点在这里:
public static ExpandoObject DicTobj(Dictionary<string, object> properties)
var eo = new ExpandoObject();
var eoColl = (ICollection<KeyValuePair<string, object>>)eo;
foreach (var childColumn in properties)
eoColl.Add(childColumn);
return eo;
U 使用 dynamic 和 ExpandoObject 将字典转换为对象
其他代码很简单:你使用 dynamic 类型将所有对象放在一个 并将其序列化。
完整代码:
public static Child Child1 get; set; = new Child
Name = "Child1"
;
public static Parent Parent1 get; set; = new Parent
Name = "Parent1"
;
public static Parent Parent2 get; set; = new Parent
Name = "Parent2"
;
private static void Main(string[] args)
var result = GetData(Child1, new List<Parent> Parent1, Parent2);
Console.WriteLine(result);
/// <summary>
/// This is the magic: convert dictionary of properties to object with preperties
/// </summary>
public static ExpandoObject DicTobj(Dictionary<string, object> properties)
var eo = new ExpandoObject();
var eoColl = (ICollection<KeyValuePair<string, object>>) eo;
foreach (var childColumn in properties)
eoColl.Add(childColumn);
return eo;
public static string GetData(Child model, List<Parent> parents)
var childColumns = GetColumns(model);
dynamic child = DicTobj(childColumns);
var parentsList = new List<object>();
foreach (var parent in parents)
var parentColumns = GetColumns(parent);
var parentObj = DicTobj(parentColumns);
parentsList.Add(parentObj);
child.Parents = parentsList;
return JsonConvert.SerializeObject(child);
/// <summary>
/// this is STUB method for example
/// I change return type from string[] to Dictionary[columnName,ColumnValue], becouse u need not only column names, but
/// with it values, i gues. If not, look commented example at the end of this method
/// </summary>
public static Dictionary<string, object> GetColumns(object model)
var result = new Dictionary<string, object>();
if (model == Child1)
result.Add("Id", "1");
result.Add("Name", "Child1");
result.Add("Location", "SomeLocation");
if (model == Parent1)
result.Add("Id", "2");
result.Add("Name", "Parent1");
result.Add("SomeProperty1", "SomeValue1");
if (model == Parent2)
result.Add("Id", "3");
result.Add("Name", "Parent1");
result.Add("SomeProperty3", "SomeValue2");
//if u have only columNames and dont need values u can do like this
//var columns = new[] "Id", "Name", "SomeProperty1";//this u get from DB
//return columns.ToDictionary(c => c, c => new object());
return result;
public class Child
public string Name get; set; // Contains Employee
//Other properties and info related to process sql query and connection string
public class Parent
public string Name get; set; // Contains Company,Department.
public string SqlQuery get; set; // query related to Company and Department.
//Other properties and info related to connection string
结果输出:
"Id": "1",
"Name": "Child1",
"Location": "SomeLocation",
"Parents": [
"Id": "2",
"Name": "Parent1",
"SomeProperty1": "SomeValue1"
,
"Id": "3",
"Name": "Parent1",
"SomeProperty3": "SomeValue2"
]
【讨论】:
感谢您的回答,但您的 json 字符串与我预期的输出 json 字符串不匹配。所以基本上 Parent2 应该在 Parent1 内(应该嵌套而不是数组)。注意 Employee 如何在我的部门内和我不想要值。我只有列的名称【参考方案5】:即使你没有固定的结构,你也可以传递任何类型的对象:
Newtonsoft.Json.JsonConvert.SerializeObject(new yourCustomObject)
通过使用这个。
【讨论】:
这里的问题是生成该结构,如我预期的输出所示。如何在不循环的情况下有效地生成该结构。 以字符串为例,它仍然接受通过字符串构造的json 可以动态构建字符串【参考方案6】:获得此结果的最佳方法 - 您必须创建一个具有所有类关系的新类。然后使用 Newtonsoft.Json.JsonConvert.SerializeObject(新组织) 让我们创建一个名为 organization 的新类。在 Json 中添加您想要查看的关系。然后使用 JsonConvert 转换成 JSON。 或者你可以使用下面的动态循环
//here your database<br/>
dynamic[] company = new object[] new Name = "Company1", DepartmentId = 1 , new Name = "Company2", DepartmentId = 2 ;
动态[] 部门 = 新对象 [] 新 部门 ID = 1,名称 = “部门 1”,新 部门 ID = 2,名称 = “部门 2” ;
//select from database<br/>
var data = from c in company
join d in department on c.DepartmentId equals d.DepartmentId
select new Name = c.Name, Department = d;
var serialized = JsonConvert.SerializeObject(data);
【讨论】:
以上是关于如何从字符串数组在 json 字符串中创建层次结构?的主要内容,如果未能解决你的问题,请参考以下文章