【工作中问题解决实践 四】动态解析Json结构最佳实践(上)

本文涉及的产品
全局流量管理 GTM,标准版 1个月
云解析 DNS,旗舰版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 【工作中问题解决实践 四】动态解析Json结构最佳实践(上)

前段时间武哥安排了个任务:把结构动态的Json数据结构解析出来。所以要求无论嵌套了多少层,都要拿到最终节点,并且给特定的节点赋予规则,让这一类json数据对应节点进行对比时,遵循节点的规则。这个任务其实可以拆解为三个任务:

  1. 拿到这类json的标准结构描述,并且在节点上标记规则
  2. 将json数据层层解构拿到所有节点,然后拿着数据节点去标准结构json里找到对应的节点,然后读取规则
  3. 将节点和规则存储为字典,key要独一无二

这样就将整个json数据转为了一个无序的规则字典。而这个规则字典不仅key唯一,还要在value里存储值和规则。这个任务不能说太难,也不能说太简单。首先我采用了一个看似合理的方案,即对json数据进行反序列化,心里想着反序列化为字典后就好搞多了,**但问题是面对复杂的json结构,你得层层反序字典,最关键的是你根本不知道有多少层。**最后武哥说可以参照下java里的JNode,于是乎在网上搜了很多,终于让我找到一种解决方案,就是用JToken,也就是Java里的JNode。然后翻遍全网,发现没有说的特别仔细点 ,于是基本JToken所有的方法我都实现了一遍,这里详细记录下,希望对大家有帮助。当然,从这篇博客开始,我准备采用解决方案和日常学习分离的策略,所以解决方案或者最佳实践不会掺杂原理性的介绍,直接上实战,为什么这样做,文末会有答案.

依照上边三个抛出的问题,制定了这样一套解决方案:

  1. json的标准结构使用JsonSchema来搞定,通过在Shema这个json数据的结构标准化描述上添加规则,因为Schema是此类数据的最标准描述,无论结构如何嵌套,Schema都可以搞定
  2. json层层结构拿到所有节点需要使用递归加循环的算法,这样才能走到每一个节点
  3. 唯一的key可以使用JToken里的JPath来限定,限定好后,就可以生成规则字典,value使用两个属性的类,一个为规则,一个为值,通过key可以拿到节点一切相关信息。

准备工作

在真正的代码实现前,先对要用到的知识来个实战,这样实现代码的时候很方便,再强调一下,每一个方法都要有单元测试!单元测试很重要!可以节约大量的找bug时间

JsonSchema简单使用

简单来说就是描述Json数据的一种数据结构,本身也是Json结构。什么是JsonSchema,以及基本原理,我在自己的另一篇博客里有对类似的XML Schema的详细记录,如果想详细了解,传送门送上:

【XML学习 三】XML Schema原理及使用 https://blog.csdn.net/sinat_33087001/article/details/80890714

如果想了解的更加深入,这里有标准制定的文档,一并奉上:

Json Schema文档说明 http://json-schema.org/latest/json-schema-validation.html#rfc.section.3.2.1

还是那句话,这里只讲实战:

  1. 首先要生成Json Schema就要拿到标准的Json数据,设计方案前期,由于考虑到xml也有解析的需求,所以通过xml转json来使两种数据结构公用一套代码,那么乱序的json和xml首先就要格式化一下,直接用在线格式化:

xml转Json以及json格式标准化网址: https://www.json.cn/

  1. 其次就要对拿到的标准json数据进行Schema生成,这个也可以使用在线生成工具:

Json Schema自动生成工具: https://jsonschema.net/

  1. 最后可以校验生成的Schema是否标准(其实第二步生成的应该是标准的,这一步无需做):

Json Schema在线验证工具 https://jsonschemalint.com/#/version/draft-06/markup/json

做完了这些,一份Json Schema就生成成功了**(注意我会在Schema的description里添加Description属性,并且在里边写上自己的对比规则)**,我自己的项目里是存储到了数据库里面,为了方便说明和讲解,这里我放到txt里说明,并且为此写了一个txt的读取方法。

#region 文件读取类
        /// <summary>
        /// 读取Schema文件
        /// </summary>
        /// <param name="filePath"></param>
        /// <returns></returns>
        public string ReadFile(string filePath)
        {
            StreamReader sr = null;
            string json = "";
            try
            {
             `这里写代码片`  //一定要注意这里要用Encoding.Default限定编码格式,否则你的数据可能会乱码哦。
                sr = new StreamReader(@filePath, Encoding.Default); 
                string nextLine;
                while ((nextLine = sr.ReadLine()) != null)
                {
                    json = json + nextLine.ToString();
                }
            }
            catch (Exception ex)
            {
                logger.Error(ex + "文件读取失败");
            }
            finally
            {
                sr.Close();
            }
            return json;
        }
        #endregion 文件读取类

JToken的简单使用

这里展示JToken的常用方法,我认为解构一个Json解构这些操作基本就够了。

首先给出一个Json数据的样本格式

{
  "checked": false,
  "dimensions": {
    "width": 5,
    "height": 10
  },
  "variables": [
    {
      "code": "id",
      "name": "TML",
      "dataType": "String",
      "defaultValue": "",
      "showFlag": "0",
      "showValue": ""
    },
    {
      "code": "metaObjName",
      "name": "beijing",
      "defaultValue": "",
      "showValue": "",
      "dataType": "String",
      "showFlag": "0"
    },
    {
      "code": "detailViewName",
      "name": "shagnhai ",
      "defaultValue": "",
      "showValue": "",
      "dataType": "String",
      "showFlag": "0"
    }
  ],
  "id": 1,
  "name": "A green door",
  "price": 12.5,
  "tags": [
    "home",
    "green"
  ]
}

然后给出Jtoken对该数据的解析操作:

#region Jtoken数据使用测试
        [TestMethod]
        public void JsonTokenTest()
        {
            //一切的一切开始之前,需要把Json数据转换为JTken格式的数据
            JToken jsonValueToken = JToken.Parse(jsr.ReadFile(filePath));//将json数据转换为JToken
            JToken first = jsonValueToken.First; //first为:{"checked": false},也就是第一个子节点
            JToken last = jsonValueToken.Last;//last为:{"tags": ["home","green"]},也就是最后一个子节点
            var jsonHaveChild = jsonValueToken.HasValues;//为true,表名当前节点并非叶子节点
            JToken itemTages = jsonValueToken.SelectToken("tags");//{"tags": ["home","green"]},该方法的作用是依据传入的路径来获取节点的值,这个方法非常重要!!!,就是依靠它和唯一的路径我才能拿到值
            var itemTagesType = itemTages.Type;//当前节点类型,目前已知有Array.object,int ,string,bool
            var itemTagesHaveChild = itemTages.HasValues;
            JToken items = jsonValueToken.SelectToken("variables");
            var itemType = items.Type;
            var itemHaveChild = items.HasValues;
            var jpath = "variables[0].code";  //如果遇到数组,路径会加索引标记哦,这就是为什么虽然数组结构统一,我依然能有唯一的路径!!
            var enumNode = jsonValueToken.SelectToken(jpath);//通过路径获取一个实体
            var enumType = enumNode.Type;
            var enumHaveChild = enumNode.HasValues;
            foreach (var item in items)
            {
                var path = item.Path;   //路径为从根节点root开始一直到当前节点
                var next = item.Next;    //当前节点的兄弟节点,同级的
                var parent = item.Parent;  //当前节点的父节点
                var lasts = item.Last;
                var root = item.Root; //当前节点的根节点
                var type = item.Type; //当前节点的类型
                var haveChild = item.HasValues;
            }
            var childs = jsonValueToken.Children();
            foreach (var item in jsonValueToken)
            {
                var path = item.Path;
                var next = item.Next;
                var parent = item.Parent;
                var lasts = item.Last;
                var root = item.Root;
                var type = item.Type;
                var haveChild = item.HasValues;
            }
        }
        #endregion Jtoken数据使用测试

开始实战

掌握了上边两个利器,就可以开始实战了(以下过程都是基于json数据和jsonSchema数据都已经搞定并存储在txt): 最初的想法开始的想法是将Json Schema读取出来,然后生成一个key为路径,value为规则的字典,然后拿着路径到json数据中找到数据,最后达到生成<path,(rule,value)>d字典的目标

初始化Json Schema字典

代码清单如下:

#region 递归schema树获取所有规则和路径
        public void SchemalevelTraverse(JToken json, ref Dictionary<string, string> jsonDic)
        {
            //如果没有属性节点了,说明已经是叶子节点了
            if (json.SelectToken("properties") == null)
            {
                if (json.SelectToken("items") == null)
                {
                    if (json.SelectToken("description") != null)  //这里是我用于填充规则的
                    {
                        string rule = json.Value<string>("description");//从Json里取出规则值
                        if (!jsonDic.ContainsKey(json.Path))
                        {
                            jsonDic.Add(json.Path, rule);
                        }
                    }
                }
                else {
                    var itemProperties = json.SelectToken("items").SelectToken("properties");
                    if (itemProperties != null)
                    {
                        foreach (var item in itemProperties)
                        {
                            if (item.First != null)
                            {
                                SchemalevelTraverse(item.First, ref jsonDic);
                            }
                        }
                    }
                }
                return;
            }
            foreach (var item in json.SelectToken("properties"))    //循环所有子节点
            {
                if (item.First != null)
                {
                    SchemalevelTraverse(item.First, ref jsonDic);   //递归调用
                }
            }
        }
        #endregion 递归schema树获取所有规则和路径


相关文章
|
28天前
|
存储 缓存 安全
Java内存模型深度解析:从理论到实践####
【10月更文挑战第21天】 本文深入探讨了Java内存模型(JMM)的核心概念与底层机制,通过剖析其设计原理、内存可见性问题及其解决方案,结合具体代码示例,帮助读者构建对JMM的全面理解。不同于传统的摘要概述,我们将直接以故事化手法引入,让读者在轻松的情境中领略JMM的精髓。 ####
34 6
|
25天前
|
运维 持续交付 云计算
深入解析云计算中的微服务架构:原理、优势与实践
深入解析云计算中的微服务架构:原理、优势与实践
56 1
|
1月前
|
消息中间件 存储 缓存
十万订单每秒热点数据架构优化实践深度解析
【11月更文挑战第20天】随着互联网技术的飞速发展,电子商务平台在高峰时段需要处理海量订单,这对系统的性能、稳定性和扩展性提出了极高的要求。尤其是在“双十一”、“618”等大型促销活动中,每秒需要处理数万甚至数十万笔订单,这对系统的热点数据处理能力构成了严峻挑战。本文将深入探讨如何优化架构以应对每秒十万订单级别的热点数据处理,从历史背景、功能点、业务场景、底层原理以及使用Java模拟示例等多个维度进行剖析。
55 8
|
18天前
|
机器学习/深度学习 人工智能 算法
深入解析图神经网络:Graph Transformer的算法基础与工程实践
Graph Transformer是一种结合了Transformer自注意力机制与图神经网络(GNNs)特点的神经网络模型,专为处理图结构数据而设计。它通过改进的数据表示方法、自注意力机制、拉普拉斯位置编码、消息传递与聚合机制等核心技术,实现了对图中节点间关系信息的高效处理及长程依赖关系的捕捉,显著提升了图相关任务的性能。本文详细解析了Graph Transformer的技术原理、实现细节及应用场景,并通过图书推荐系统的实例,展示了其在实际问题解决中的强大能力。
113 30
|
18天前
|
存储 网络协议 编译器
【C语言】深入解析C语言结构体:定义、声明与高级应用实践
通过根据需求合理选择结构体定义和声明的放置位置,并灵活结合动态内存分配、内存优化和数据结构设计,可以显著提高代码的可维护性和运行效率。在实际开发中,建议遵循以下原则: - **模块化设计**:尽可能封装实现细节,减少模块间的耦合。 - **内存管理**:明确动态分配与释放的责任,防止资源泄漏。 - **优化顺序**:合理排列结构体成员以减少内存占用。
90 14
|
22天前
|
存储 算法
深入解析PID控制算法:从理论到实践的完整指南
前言 大家好,今天我们介绍一下经典控制理论中的PID控制算法,并着重讲解该算法的编码实现,为实现后续的倒立摆样例内容做准备。 众所周知,掌握了 PID ,就相当于进入了控制工程的大门,也能为更高阶的控制理论学习打下基础。 在很多的自动化控制领域。都会遇到PID控制算法,这种算法具有很好的控制模式,可以让系统具有很好的鲁棒性。 基本介绍 PID 深入理解 (1)闭环控制系统:讲解 PID 之前,我们先解释什么是闭环控制系统。简单说就是一个有输入有输出的系统,输入能影响输出。一般情况下,人们也称输出为反馈,因此也叫闭环反馈控制系统。比如恒温水池,输入就是加热功率,输出就是水温度;比如冷库,
163 15
|
24天前
|
弹性计算 持续交付 API
构建高效后端服务:微服务架构的深度解析与实践
在当今快速发展的软件行业中,构建高效、可扩展且易于维护的后端服务是每个技术团队的追求。本文将深入探讨微服务架构的核心概念、设计原则及其在实际项目中的应用,通过具体案例分析,展示如何利用微服务架构解决传统单体应用面临的挑战,提升系统的灵活性和响应速度。我们将从微服务的拆分策略、通信机制、服务发现、配置管理、以及持续集成/持续部署(CI/CD)等方面进行全面剖析,旨在为读者提供一套实用的微服务实施指南。
|
18天前
|
存储 缓存 Python
Python中的装饰器深度解析与实践
在Python的世界里,装饰器如同一位神秘的魔法师,它拥有改变函数行为的能力。本文将揭开装饰器的神秘面纱,通过直观的代码示例,引导你理解其工作原理,并掌握如何在实际项目中灵活运用这一强大的工具。从基础到进阶,我们将一起探索装饰器的魅力所在。
|
24天前
|
存储 缓存 监控
后端开发中的缓存机制:深度解析与最佳实践####
本文深入探讨了后端开发中不可或缺的一环——缓存机制,旨在为读者提供一份详尽的指南,涵盖缓存的基本原理、常见类型(如内存缓存、磁盘缓存、分布式缓存等)、主流技术选型(Redis、Memcached、Ehcache等),以及在实际项目中如何根据业务需求设计并实施高效的缓存策略。不同于常规摘要的概述性质,本摘要直接点明文章将围绕“深度解析”与“最佳实践”两大核心展开,既适合初学者构建基础认知框架,也为有经验的开发者提供优化建议与实战技巧。 ####
|
19天前
|
机器学习/深度学习 搜索推荐 API
淘宝/天猫按图搜索(拍立淘)API的深度解析与应用实践
在数字化时代,电商行业迅速发展,个性化、便捷性和高效性成为消费者新需求。淘宝/天猫推出的拍立淘API,利用图像识别技术,提供精准的购物搜索体验。本文深入探讨其原理、优势、应用场景及实现方法,助力电商技术和用户体验提升。

推荐镜像

更多