json2Dart工具

Posted 人生如梦91

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了json2Dart工具相关的知识,希望对你有一定的参考价值。

最近公司在推动跨平台开发,大佬们有意向使用Flutter编写App中的部分页面,于是自学了一波Flutter,但是在Flutter的学习过程中发现结合json_annotation库时,发现要写一个json解析文件实在太麻烦了,在使用过程中,发现网站json转dart,但是感觉使用起来还是比较麻烦,于是自己动手使用python编写了一个json转dart实体的脚本。并用工具解析编写了公司项目json解析。

文章目录

效果演示

运行之后的效果如下图所示:

执行之后,会根据json的内容,生成两个文件,一个.dart文件和一个.g.dart文件,这样就完成了一个json解析文件的生成。

从main开始

main的代码如下所示:

if __name__ == '__main__':
    parser = ArgParser();
    param = parser.parserArgument();

    os.chdir(param.getTarget());
    
    if(param.getOnlyBuild() == True):
        (BuildRunnerProcess()).run();
    else:
        (JsonParser()).parse()

main的代码很简单,首先是解析参数,然后切换到指定的工作目录,如果只做生成操作,则直接执行命令,生成文件,否则解析json。

参数解析


可以看到,脚本的参数列表如上图所示,解析如下;

  • -h:显示帮助列表
  • -b:仅编译生成解析文件
  • -u:根据给定的url,请求json数据
  • -f:从文件读取json数据
  • -j:从json字符串读取数据
  • -d:指定Flutter项目目录
  • -c:指定model的类名
  • -p:指定类名的前缀,如果类名已经名含前缀,则不再取前缀

Json数据解析

整个json解析类,包括数据请求,json解析两步操作,代码如下所示:

class JsonParser(object):
    def __init__(self):
        self.__param = param;
        self.__jsonObj = '';

    def __requestJsonFromURL(self, url):
        response = requests.get(url);
        self.__jsonObj = response.text;

    def __readJsonFromFile(self, path):
        filePath = os.path.expanduser(path);

        if filePath != None:
            try:
                with open(filePath, mode='r') as f:
                    jsonstr = f.readline();
                    if jsonstr != None:
                        self.__jsonObj += jsonstr;
            finally:
                f.close();

    def __readJsonFromString(self):
        jsonstr = raw_input(prompt='press ENTER to exit.');
        while(len(jsonstr) > 0):
            self.__jsonObj += jsonstr;
            jsonstr = raw_input(prompt='press ENTER to exit.');
    
    def parse(self):
        if(self.__param.getMethod() == 1):
            self.__requestJsonFromURL(self.__param.getArgument());
        elif(self.__param.getMethod() == 2):
            self.__readJsonFromFile(self.__param.getArgument());
        elif(self.__param.getMethod() == 3):
            self.__readJsonFromString();
        else:
            exit();

        print('Json Contentes like this below:');
        print('');
        print('\\033[31m' + self.__jsonObj + '\\033[0m');

        self.__parse();

    def __parse(self):
        print('');
        print('Parsing Json URL, Please Wait...');
        self.__jsonObj = json.loads(self.__jsonObj);
        if(self.__jsonObj != None):
            generator = DartGenerator();
            generator.generate(self.__jsonObj);
        else:
            print('');
            print('Incorrect Json String, Program Will be Exit...');
            exit();

可以看到,支持3种方式读取json数据,从url请求,从文件读取,从字符串读取,从url请求使用了reqeusts库。其实这个类的作用就是读取json数据,然后将json数据传递给DartGenerator类生成dart文件。

文件操作

文件操作的代码如下所示:

class FileOperator:
    def __init__(self):
        global filePath;

        target = os.path.join(param.getTarget(), 'lib');
        if(os.path.exists(target) == False or os.path.isdir(target) == False):
            raise Exception, 'Where is the lib Directory?';
        target = os.path.join(target, 'Models');
        if(os.path.exists(target) == False or os.path.isdir(target) == False):
            os.mkdir(target);
        
        if param.getName() == None:
            if param.getPrefix() == None:
                target = os.path.join(target, 'AutoGenerated.dart');
            else:
                target = os.path.join(target, param.getPrefix() + 'AutoGenerated.dart');
        else:
            if param.getPrefix() == None:
                target = os.path.join(target, param.getName() + '.dart');
            else:
                target = os.path.join(target, param.getPrefix() + param.getName() + '.dart');

        filePath = target;

        # 清空文件
        with open(filePath, 'w') as f:
            f.truncate(0);

    def write(self, content):
        with open(filePath, 'a+') as f:
            f.write(content);

该类首先检查指定目录是否为一个正确的Flutter项目目录,目前这里只是通过检查目录下是否有lib目录,如果没有的话,就当做指定目录不合格。最后如果没有指定文件,则使用AutoGenerated.dart作为默认文件名。

写入dart代码

主要代码在DartGenerator类中,解析后的json数据是一个dict,其实就是一个n叉树,DartGenerator的作用就是递归遍历n叉树,生成.dart文件,代码如下所示:

class DartGenerator:
    def __init__(self):
        self.__fileOperator = FileOperator();

    def __getStandardizedObjName(self, name):
        prefix = param.getPrefix();

        if(prefix == None or name.startswith(prefix)):
            return self.__myCapitalize(name);
        return prefix + self.__myCapitalize(name);

    def __Encoding(self, key, value):
        if(type(value) == bool):
            return 'bool';
        elif(type(value) == int):
            return 'int';
        elif(type(value) == float):
            return 'double';
        elif(type(value) == str or type(value) == unicode):
            return 'String';
        elif(type(value) == list):
            if(len(value) == 0):
                return 'List<dynamic>';
            fObj = value[0];
            if(type(fObj) == dict):
                return 'List<' + self.__getStandardizedObjName(key) + '>';
            return 'List<' + self.__Encoding(key, fObj) + '>';
        elif(type(value) == dict):
            return self.__getStandardizedObjName(key);
        else:
            return 'dynamic';

    def generate(self, jsonObj):
        #生成dart文件
        fileContent = '/// This File is Generated by ' + os.path.basename(sys.argv[0]) + ' and you SHOULD NOT MODIFY this file' + os.linesep + \\
            '/// UNLESS the property we not recognized named property(number) and mark on the top.' + os.linesep + os.linesep;
        fileContent += self.__writeHeaderImport();
        
        clsName = param.getName();
        if(clsName == None):
            clsName = 'AutoGenerated';
        fileContent += self.__writePartAnnouncement(clsName)
        self.__fileOperator.write(fileContent);

        self.__generateRecursive(jsonObj, self.__getClassName(clsName));

        #生成json解析文件
        (BuildRunnerProcess()).run();

    def __myCapitalize(self, name):
        if(len(name) <= 0):
            return name;
        elif(len(name) == 1):
            return name.capitalize();
        return name[0:1].upper() + name[1:len(name)];

    def __is_contain_chinese(self, check_str):
        for ch in check_str:
            if u'\\u4e00' <= ch <= u'\\u9fff':
                return True
            return False

    def __getClassName(self, name):
        if(param.getPrefix() == None or name.startswith(param.getPrefix())):
            return self.__myCapitalize(name);
        return param.getPrefix() + self.__myCapitalize(name);

    def __generateRecursive(self, jsonObj, clsName):
        if(type(jsonObj) != dict and type(jsonObj) != list):
            print('');
            print('\\033[31m Json Parse Error. Exiting...');
            print('');
            exit();

        fileContent = self.__writeClassHeader(clsName);
        props = []; 

        for (key, value) in jsonObj.items():
            if self.__is_contain_chinese(key): 
                fileContent += os.linesep + '    /// This property we not recognized' + os.linesep + \\
                    '    /// You MUST Modify it BY YOURSELF.' + os.linesep;

                name = 'property' + str((len(props) + 1));
                props.append(name);
                fileContent += self.__writeProperty('dynamic', name);
            else:
                props.append(key);
                fileContent += self.__writeProperty(self.__Encoding(key, value), key);

            if(type(value) == dict and len(value.keys()) > 0):
                self.__generateRecursive(value, self.__getClassName(key));
            elif(type(value) == list and len(value) > 0):
                #取最长的元素为参照对象
                obj = None;
                for i in range(0, len(value)):
                    dic = value[i];
                    if type(dic) == dict:
                        if obj == None:
                            obj = dic;
                        else:
                            if len(dic.keys()) > len(obj.keys()):
                                obj = dic;

                if(type(obj) == dict):
                    self.__generateRecursive(obj, self.__getClassName(key));

        fileContent += self.__writeConstruct(clsName, props);

        fileContent += self.__writeFromJsonMethod(clsName);
        fileContent += self.__writeToJsonMethod(clsName);
        fileContent += self.__writeEnding();
        self.__fileOperator.write(fileContent);

    def __writePartAnnouncement(self, clsName):
        fileContent = 'part \\'' + self.__getClassName(clsName) + '.g.dart\\';' + os.linesep + os.linesep;
        return fileContent;

    def __writeHeaderImport(self):
        fileContent = 'import \\'package:json_annotation/json_annotation.dart\\';' + os.linesep + os.linesep;
        return fileContent;

    def __writeClassHeader(self, clsName):
        fileContent = '@JsonSerializable(nullable: true)';
        fileContent += os.linesep;
        fileContent += 'class ' + clsName + ' ' + os.linesep;
        return fileContent;

    def __writeProperty(self, typeName, name):
        fileContent = '    ' + typeName + ' ' + name + ';' + os.linesep;
        return fileContent;

    def __writeEnding(self):
        fileContent = '' + os.linesep + os.linesep;
        return fileContent;
    
    def __writeConstruct(self, clsName, props):
        fileContent = os.linesep + '    ' + clsName + '(';

        isFirst = True;

        count = 0;
        for (idx, p) in enumerate(props):
            count = count + 1;
            if isFirst:
                fileContent += 'this.' + p;
                isFirst = False;
            else:
                fileContent += ', this.' + p;

            if count % 4 == 0 and idx != len(props):
                fileContent += os.linesep + '        ';
        
        fileContent += ');' + os.linesep + os.linesep;
        return fileContent;

    def __writeFromJsonMethod(self, clsName):
        fileContent = '    factory ' + clsName + '.fromJson(Map<String, dynamic> json) => _$' + clsName + 'FromJson(json);';
        fileContent += os.linesep;
        return fileContent;
    
    def __writeToJsonMethod(self, clsName):
        fileContent = '    Map<String, dynamic> toJson() => _$' + clsName + 'ToJson(this);';
        fileContent += os.linesep + os.linesep;
        return fileContent;

class JsonParser(object):
    def __init__(self):
        self.__param = param;
        self.__jsonObj = '';

    def __requestJsonFromURL(self, url):
        response = requests.get(url);
        self.__jsonObj = response.text;

    def __readJsonFromFile(self, path):
        filePath = os.path.expanduser(path);

        if filePath != None:
            try:
                with open(filePath, modesubstr函数

hdu 1297 递推难题

js清空数组

PHP 字符串部分隐藏

go语言如何书写测试模块

再次爆肝熬夜整理Python编程工具面试题库学习资料总集,结尾自取免费分享