词法与语法分析——在XML2JSON中应用

本文涉及的产品
云解析 DNS,旗舰版 1个月
全局流量管理 GTM,标准版 1个月
公共DNS(含HTTPDNS解析),每月1000万次HTTP解析
简介: 利用Antlr4进行词法树和语法树的解析。

一、问题背景

近期在处理数据的过程之中遇到了两个棘手的问题,由于在线系统的数据范式不固定,导致大量处理逻辑交由离线系统处理。诚然,最本质的原因来源于Amazon提供的API标准数据结构为异构数据,数据源会发生动态变化,数据定义十分复杂,变量数量总计达到数千个,且存在结构化不完整的问题。

具体说来,则是

1、ODPS库中JsonArray和JsonObject无法区分,在每一层展开时存在大量模糊匹配,增加了算法复杂度,让数据处理变成了面向extend_info的编程。

2、数据落库的形式不固定,存在大量的特殊情况。需要进行枚举,并在程序运行报错时单独检测错误原因,以覆盖错误用例。

3、由于Amazon许诺的返回值可能未返回,对于检验告警的DQC的校验规则实现困难,需要遍历所有字段进行全文匹配。

针对上述三类问题,虽然交给离线系统处理都能解决,但解析过程中上下游代码复用程度很高,就离线的视角来看待问题。三类问题显然交给在线的抓取系统更加合适,一步到位解决业务需求。

既然谈到数据处理,我们不妨来看看在线采集系统是如何处理Amazon返回的XML字段的:

@Override
    protected <T> List<T> parseResult(String result, Class<T> clazz) throws Exception {
        org.json.JSONObject xmlJSONObj = XML.toJSONObject(result);
        JSONObject jsonObject = JSONObject.parseObject(xmlJSONObj.toString());
        String jsonString = JSON.toJSONString(JSONPath.eval(jsonObject,
                SELLER_PERFORMANCE_REPORT_PATH));
        Object json = new JSONTokener(jsonString).nextValue();
        if(json instanceof org.json.JSONObject){
            T t = CreditBizUtils.convertJsonResponseToObject(jsonString, clazz, CreditBizConstants.EXTEND_INFO_FIELD);
            return Lists.newArrayList(t);
        }else{
            JSONArray jsonArray = JSON.parseArray(jsonString);
            List<T> list = Lists.newArrayListWithCapacity(jsonArray.size());
            for (Object obj : jsonArray) {
                T t = CreditBizUtils.convertJsonResponseToObject(JSON.toJSONString(obj), clazz,
                        CreditBizConstants.EXTEND_INFO_FIELD);
                list.add(t);
            }
            return list;
        }
    }

在上述方法的头两行,就确定了xml在转化为Json时采用的是模糊推断机制。我们深入到org.json的源代码中可以发现这一段,下述代码的具体含义则是有重复的Key则自动转化为JSONArray。我们也不难看出,早在在线系统的处理中,作者就是采用尝试机制取处理Object和Array的,到了离线系统分离字段的时候,这样的操作又要来一遍。

二、解决方案:

2.1 解决方案一:修改XML解析源码

优点:改动代码量少。

缺点:需要完全理解解析流程。

下述代码描述了XML在解析到相同的tagName时的处理过程,对于新key,如果不存在,则默认为JsonObj,如果已经存在则将原JsonObj和新的Value一起转化为JsonArray。正是这种模糊推断式的方式而非指定格式,导致上游系统和下游系统都需要推断一遍。

public JSONObject accumulate(
        String key,
        Object value
    ) throws JSONException {
        testValidity(value);
        Object object = this.opt(key);
        if (object == null) {
            this.put(key, value instanceof JSONArray
                    ? new JSONArray().put(value)
                    : value);
        } else if (object instanceof JSONArray) {
            ((JSONArray)object).put(value);
        } else {
            this.put(key, new JSONArray().put(object).put(value));
        }
        return this;
    }

对于源码最小的改动,在于在其JsonObj的基础上再重载一个新的方法,可以对你所要求的key,在第一步就指定为JsonArray.这样,我们只需要在转化开始时,初始化添加必须要转为JsonArray的对象到规则forcearray中即可。

public class JsonAcuumulate extends JSONObject{
    public JSONObject accumulate(
            String key,
            Object value,
            ArrayList<String> forcearray
    ) throws JSONException {
        testValidity(value);
        Object object = this.opt(key);
        //特殊处理情况:指定初始化array
        if(object == null && forcearray.contains(key)){
            this.put(key, new JSONArray().put(value));
        } else if (object == null) {
            this.put(key, value instanceof JSONArray
                    ? new JSONArray().put(value)
                    : value);
        } else if (object instanceof JSONArray) {
            ((JSONArray)object).put(value);
        } else {
            this.put(key, new JSONArray().put(object).put(value));
        }
        return this;
    }
}

2.2 解决方案二:Antlr4 语法树/词法树解析

优点:对于代码有着全局性的把控。

缺点:测试案例覆盖有待完善。

采用更加复杂的解决方式解决并不是为了炫技。只有更加基础的复杂才能应对复杂。此处从文本的语法树着手,从字符串层层面自定义解析规则,以便应对后续更加复杂的xml、json、csv文件的解析,让解析层的带面变得更加复杂通用。应用层的代码才会相对变得更加简单。

Antlr4(Another Tool for Language Recognition)是一款基于Java开发的开源的语法分析器生成工具,能够根据语法规则文件生成对应的递归向下的语法分析器,广泛应用于DSL构建,语言词法语法解析等领域。在show code前,我们先介绍一组基本概念:

2.2.1 基本概念

基本概念

释义

语法分析

是指约束语言中的各个组成部分之间的关系的规则。

词法分析

将字符汇聚为单词或者符号的过程。

语法分析树

树的非叶子节点代表着规则(语法),而叶子结点代表了词法符号。

字符流数据解析成为语法树的过程如下所示:

 

image.png

在idle中也有对应的插件antlr4,在安装完成插件的对应功能后,我们可以使用它来检查我们编写的语法规则。对于antlr4的语法规则编写方法小明在此处不做过多的介绍,有兴趣的小伙伴可以参阅《antlr4权威指南》

image.png

2.2.2 语法树的遍历

对于数据处理而言,词组->行为的集合构成了我们的语言类应用程序。在antlr4中,我们在编写完语法和词法的自定义代码之后,可以根据其自动生成的监听器(listener)对特定的规则进入和退出事件做出响应。此外,Antlr自动生成的还包括广为人知的访问者(Visitor)模式,从而在监听器的基础上更近一步,允许程序控制语法分析树的遍历过程。

接下来将展示一段在项目中真实用到的代码,在原始的xml解析的语法树上作如下修改:

1、添加规则:<'lzmmarktag'>' content '<''/'lzmmarktag'> 在所有解析规则前,由于语法树编写的间接左递归特性,使得在符合多个语法规则时,优先匹配第一个,此处我们对于自定义要生成JsonObj的tag单独拎出来处理。

2、定义句法:lzmmarktag  :   UserDefinedWords;  后者为正则表达式形式,此处我们可以简单进行全文匹配。

element     :   '<'lzmmarktag'>' content '<''/'lzmmarktag'>'
            |   '<' Name attribute* '>' content '<' '/' Name '>'
            |   '<' Name attribute* '/>'
            ;

image.png

3、定义遍历规则:对于XML-JSON的解析程序逻辑如下:


image.pngimage.png

三、写在最后

上述讨论的两种方式均是来源于小明站在离线ODPS的owner视角给出的技术解决方案。对于文章中一开头提到的放在上游系统解析的过程,小明的觉得大家可以很好的参考这篇文章领域模型vs数据模型。借用文章UP主的原话在具体落地的时候,我们可以采用COLA的架构思想,使用gateway作为数据对象(Data Object)和领域对象(Entity)之间的转义网关,其中,gateway除了转义的作用,还起到了防腐解耦的作用,解除了业务代码对底层数据(DO、DTO等)的直接依赖,从而提升系统的可维护性。

image.png

目录
相关文章
|
5月前
|
XML JSON 前端开发
基于若依的ruoyi-nbcio流程管理系统仿钉钉流程json转bpmn的flowable的xml格式(简单支持发起人与审批人的流程)
基于若依的ruoyi-nbcio流程管理系统仿钉钉流程json转bpmn的flowable的xml格式(简单支持发起人与审批人的流程)
297 2
基于若依的ruoyi-nbcio流程管理系统仿钉钉流程json转bpmn的flowable的xml格式(简单支持发起人与审批人的流程)
|
5月前
|
XML JSON 前端开发
基于若依的ruoyi-nbcio流程管理系统仿钉钉流程json转bpmn的flowable的xml格式(支持并行网关)
基于若依的ruoyi-nbcio流程管理系统仿钉钉流程json转bpmn的flowable的xml格式(支持并行网关)
254 3
|
2月前
|
存储 SQL JSON
【Azure Logic App】微软云逻辑应用连接到数据库,执行存储过程并转换执行结果为JSON数据
【Azure Logic App】微软云逻辑应用连接到数据库,执行存储过程并转换执行结果为JSON数据
【Azure Logic App】微软云逻辑应用连接到数据库,执行存储过程并转换执行结果为JSON数据
|
2月前
|
JSON Java Android开发
Android 开发者必备秘籍:轻松攻克 JSON 格式数据解析难题,让你的应用更出色!
【8月更文挑战第18天】在Android开发中,解析JSON数据至关重要。JSON以其简洁和易读成为首选的数据交换格式。开发者可通过多种途径解析JSON,如使用内置的`JSONObject`和`JSONArray`类直接操作数据,或借助Google提供的Gson库将JSON自动映射为Java对象。无论哪种方法,正确解析JSON都是实现高效应用的关键,能帮助开发者处理网络请求返回的数据,并将其展示给用户,从而提升应用的功能性和用户体验。
50 1
|
2月前
|
XML JSON Java
使用IDEA+Maven搭建整合一个Struts2+Spring4+Hibernate4项目,混合使用传统Xml与@注解,返回JSP视图或JSON数据,快来给你的SSH老项目翻新一下吧
本文介绍了如何使用IntelliJ IDEA和Maven搭建一个整合了Struts2、Spring4、Hibernate4的J2EE项目,并配置了项目目录结构、web.xml、welcome.jsp以及多个JSP页面,用于刷新和学习传统的SSH框架。
36 0
使用IDEA+Maven搭建整合一个Struts2+Spring4+Hibernate4项目,混合使用传统Xml与@注解,返回JSP视图或JSON数据,快来给你的SSH老项目翻新一下吧
|
2月前
|
Java Spring 容器
彻底改变你的编程人生!揭秘 Spring 框架依赖注入的神奇魔力,让你的代码瞬间焕然一新!
【8月更文挑战第31天】本文介绍 Spring 框架中的依赖注入(DI),一种降低代码耦合度的设计模式。通过 Spring 的 DI 容器,开发者可专注业务逻辑而非依赖管理。文中详细解释了 DI 的基本概念及其实现方式,如构造器注入、字段注入与 setter 方法注入,并提供示例说明如何在实际项目中应用这些技术。通过 Spring 的 @Configuration 和 @Bean 注解,可轻松定义与管理应用中的组件及其依赖关系,实现更简洁、易维护的代码结构。
35 0
|
2月前
|
JSON 数据格式 Java
化繁为简的魔法:Struts 2 与 JSON 联手打造超流畅数据交换体验,让应用飞起来!
【8月更文挑战第31天】在现代 Web 开发中,JSON 成为数据交换的主流格式,以其轻量、易读和易解析的特点受到青睐。Struts 2 内置对 JSON 的支持,结合 Jackson 库可便捷实现数据传输。本文通过具体示例展示了如何在 Struts 2 中进行 JSON 数据的序列化与反序列化,并结合 AJAX 技术提升 Web 应用的响应速度和用户体验。
76 0
|
5月前
|
XML JSON 前端开发
基于若依的ruoyi-nbcio流程管理系统仿钉钉流程json转bpmn的flowable的xml格式(排它条件网关)
基于若依的ruoyi-nbcio流程管理系统仿钉钉流程json转bpmn的flowable的xml格式(排它条件网关)
87 3
基于若依的ruoyi-nbcio流程管理系统仿钉钉流程json转bpmn的flowable的xml格式(排它条件网关)
|
4月前
|
XML JSON 开发框架
一篇文章讲明白JSON格式转换成XML格式
一篇文章讲明白JSON格式转换成XML格式
22 0
|
4月前
|
XML JSON 开发框架
一篇文章讲明白JSON格式转换成XML格式
一篇文章讲明白JSON格式转换成XML格式
30 0