如何从字符串数组在 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 使用 dynamicExpandoObject 将字典转换为对象

其他代码很简单:你使用 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 字符串中创建层次结构?的主要内容,如果未能解决你的问题,请参考以下文章

在层次结构中创建类的指针数组

在 Swift 中创建 JSON 数组

快速从字典数组中创建字符串数组

如何在 Team Foundation Server 2018 中创建层次结构?

如何在json中声明两个数组?

如何在BigQuery中创建嵌套字段和数组的数组