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

简介: 利用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

目录
相关文章
|
1月前
|
JSON 程序员 数据格式
深入探索 “JSON for Modern C++“:安装、构建与应用
深入探索 “JSON for Modern C++“:安装、构建与应用
40 0
|
22天前
|
JSON JavaScript 前端开发
解锁JSON的奇妙世界:从基础到高级应用,一文搞懂JSON的妙用(中)
解锁JSON的奇妙世界:从基础到高级应用,一文搞懂JSON的妙用(中)
|
2月前
|
Web App开发 JSON JavaScript
SAP UI5 应用程序小技巧 - 一键将 JSON 对象导出成本地 json 文件
SAP UI5 应用程序小技巧 - 一键将 JSON 对象导出成本地 json 文件
25 0
|
3月前
|
XML 存储 JSON
Python学习 -- 常用数据交换格式(CSV、XML、JSON)
Python学习 -- 常用数据交换格式(CSV、XML、JSON)
31 0
|
3月前
|
XML JSON 数据格式
xml与JSON的区别
xml与JSON的区别
30 1
|
3月前
|
存储 JSON JavaScript
Python 的其他应用: 如何使用 Python 处理 JSON 数据?
Python 的其他应用: 如何使用 Python 处理 JSON 数据?
|
2月前
|
XML 机器学习/深度学习 JSON
在火狐浏览器调ajax获取json数据时,控制台提示“XML 解析错误:格式不佳”。
在火狐浏览器调ajax获取json数据时,控制台提示“XML 解析错误:格式不佳”。
29 0
在火狐浏览器调ajax获取json数据时,控制台提示“XML 解析错误:格式不佳”。
|
17天前
|
XML JSON JavaScript
Java中XML和JSON的比较与应用指南
本文对比了Java中XML和JSON的使用,XML以自我描述性和可扩展性著称,适合结构复杂、需验证的场景,但语法冗长。JSON结构简洁,适用于轻量级数据交换,但不支持命名空间。在Java中,处理XML可使用DOM、SAX解析器或XPath,而JSON可借助GSON、Jackson库。根据需求选择合适格式,注意安全、性能和可读性。
26 0
|
22天前
|
XML JSON JavaScript
使用JSON和XML:数据交换格式在Java Web开发中的应用
【4月更文挑战第3天】本文比较了JSON和XML在Java Web开发中的应用。JSON是一种轻量级、易读的数据交换格式,适合快速解析和节省空间,常用于API和Web服务。XML则提供更强的灵活性和数据描述能力,适合复杂数据结构。Java有Jackson和Gson等库处理JSON,JAXB和DOM/SAX处理XML。选择格式需根据应用场景和需求。
|
1月前
|
XML JSON API
深入解析C++ JSON库:nlohmann::json:: parse的内部机制与应用
深入解析C++ JSON库:nlohmann::json:: parse的内部机制与应用
52 0