对平面列表进行分组并输出分层JSON

时间:2014-01-17 22:57:20

标签: json linq kendo-ui kendo-treeview

我的结果集如下所示:

enter image description here

需要使用嵌套组格式化为hierarchal json:

     [
        {
            areaName: "Latam",
            subsidaries: [
                { areaName: "Ecuador", id: 1 },
                { areaName: "Peru", id: 3 },
                { areaName: "Jamaica", id: 4 },
                { areaName: "Venezuela", id: 5 },
                { areaName: "BCBB", id: 6 }
            ]
        },
        {
            areaName: "APAC",
            subsidaries: [
                { areaName: "Brunei", id: 1 },
                { areaName: "Sri Lanka", id: 31 },
                { areaName: "(APAC Sub Not Specified)", id: 1 },
                { areaName: "Korea", id: 231 },
                { areaName: "Malaysia", id: 61 },
                { areaName: "Indonesia", id: 61 },
                { areaName: "Philippines", id: 31 },
                { areaName: "Singapore", id: 3231 },
                { areaName: "Australia", id: 621 },
                { areaName: "New Zealand", id: 231 },
                { areaName: "Vietnam", id: 431 },
                { areaName: "Thailand", id: 99 }
            ]
        }],

我最初的想法是使用linq查询对数据进行分组:

    public ActionResult Index()
    {
        var model = Repository.GetGeoSubsidiaryHierarchy();

        foreach (var line in GroupedItems(model)
           .Select(group => new
           {
               AreaName = group.Key,
               Count = group.Count()
           }).OrderBy(x => x.AreaName))
        {
            Response.Write( String.Format( "{0} {1}", line.AreaName, line.Count) );
        }

        return View("Index", model);
    }

    private static IEnumerable<IGrouping<string, GeoSubsidiary>> GroupedItems(List<GeoSubsidiary> model)
    {
        var ret = model.ToList().GroupBy(area => area.AreaName);


        return ret;
    }

但我不清楚如何在分组后序列化此列表。此外,我对我的分组技能没有信心,因为我对子选择有点模糊,以便迭代每个分组的行(此代码:.Select(group =&gt; new)...)。

我考虑的其他选项是使用DataAnnotations / DataContracts和自定义注释类,利用Newtonsoft JSON.NET的一些高级功能,或使用字典并将其与分组行一起加载。

如果有人可以推荐处理分组数据和JSON的最佳实践并帮助我开始输出这个分组层次结构的代码(我手工构建的样本JSON数据,但确切需要),我将非常感激。输出)。

为了完整起见,我应该提一下,我的最终目标是成为一个很棒的剑道分层数据源javascript对象:http://docs.kendoui.com/api/framework/hierarchicaldatasource

2 个答案:

答案 0 :(得分:1)

如果您只需要显示数据,您可以随时获取服务中的所有记录,并在javascript中进行分组,然后将分层数据源绑定到该数据。

示例http://jsbin.com/uQuLUwE/2/edit(我刚将其绑定到树视图以便于显示)

如果没有,您始终可以创建两个dataSource,一个用于根项目,另一个用于childItems。根项需要拉出不同的AreaNames,然后需要针对正确的AreaName过滤childItems数据源。

答案 1 :(得分:0)

感谢您的建议 - 我最终选择了一个可能过于复杂的c#方法

public class HierarchalDataController : BaseController
{

    internal class ChildNode
    {
        public string areaName { get; set; }
        public int id { get; set; }
    }

    internal class Area
    {
        public string areaName { get; set; }
        public List<ChildNode> subsidaries { get; set; }
    }

    public ContentResult GetAreaContent()
    {
        var areas = Repository.GetGeoSubsidiaryHierarchy();
        var groupedAreas = areas.GroupBy(area => area.AreaName);
        var subareas = new List<Area>();

        foreach (var parentArea in groupedAreas)
        {
            var subsidiaries = new List<ChildNode>();
            var subs = areas.Where(x => x.AreaName == parentArea.Key).ToList();
            subsidiaries.AddRange(subs.Select(sub => new ChildNode { id = sub.SubsidiaryId, areaName = sub.SubsidiaryName }));
            var area = new Area { areaName = parentArea.Key, subsidaries = subsidiaries };
            subareas.Add(area);
        }

        var retval = JsonConvert.SerializeObject(subareas, Formatting.Indented);
        return Content(retval, "application/json");
    }

    public ContentResult GetScenarioContent()
    {
        var areas = Repository.GetScenarioHierarchy();
        var groupedAreas = areas.GroupBy(area => area.FunctionalAreaID);
        var subareas = new List<Area>();

        foreach (IGrouping<int, Scenario> parentArea in groupedAreas)
        {
            var subsidiaries = new List<ChildNode>();
            var subs = areas.Where(x => x.FunctionalAreaID== parentArea.Key).ToList();
            subsidiaries.AddRange(subs.Select(sub => new ChildNode { id = sub.FunctionalAreaID, areaName = sub.ScenarioName}));
            var scenario = parentArea.FirstOrDefault();

            if (scenario != null)
            {
                var area = new Area { areaName = scenario.FunctionalAreaName, subsidaries = subsidiaries }; // hack
                subareas.Add(area);
            }
        }

        var retval = JsonConvert.SerializeObject(subareas, Formatting.Indented);
        return Content(retval, "application/json");
    }

    /// <summary>
    /// Simply a flat-list of products. 
    /// </summary>
    /// <returns></returns>
    public ContentResult GetProductContent()
    {
        var subareas = new List<Area>();
        foreach (var product in Repository.GetProductList())
        {
            subareas.Add(new Area
            {
                areaName = product.ProductName,
                subsidaries = new List<ChildNode>()
            });
        }

        var retval = JsonConvert.SerializeObject(subareas, Formatting.Indented);
        return Content(retval, "application/json");
    }


}