• 使用Antlr将json翻译成XML(转)


    本文代码来自《Antlr权威指南》

    现在我们传递数据一般都是要json,因为它短小精悍,占用空间小。

    但是在数年之前,XML还被用作万金油。

    如有你有一个客户,还停留在远古时代,他偏要你提供XML格式的数据接口,你该怎么办?

    谁也不想写两套接口吧?这对于一些古老的大型项目简直是个灾难。

    其实完全没必要,我们只需要写一个方法,将json转成XML即可。

    首先我们需要json的语法文件JSON.g4,来自原书的资源文件。

    // Derived from http://json.org
    
    grammar JSON;
    @header{package com.example.json;}
    json:   object
        |   array
        ;
    
    object
        :   '{' pair (',' pair)* '}' # AnObject
        |   '{' '}'                  # EmptyObject
        ;
    pair:   STRING ':' value ;
    
    array
        :   '[' value (',' value)* ']' # ArrayOfValues
        |   '[' ']'                    # EmptyArray
        ;
    
    value
        :   STRING  # String
        |   NUMBER  # Atom
        |   object  # ObjectValue
        |   array   # ArrayValue
        |   'true'  # Atom
        |   'false' # Atom
        |   'null'  # Atom
        ;
    
    STRING :  '"' (ESC | ~["\\])* '"' ;
    
    fragment ESC :   '\\' (["\\/bfnrt] | UNICODE) ;
    fragment UNICODE : 'u' HEX HEX HEX HEX ;
    fragment HEX : [0-9a-fA-F] ;
    
    NUMBER
        :   '-'? INT '.' [0-9]+ EXP? // 1.35, 1.35E-9, 0.3, -4.5
        |   '-'? INT EXP             // 1e10 -3e4
        |   '-'? INT                 // -3, 45
        ;
    fragment INT :   '0' | [1-9] [0-9]* ; // no leading zeros
    fragment EXP :   [Ee] [+\-]? INT ; // \- since - means "range" inside [...]
    
    WS  :   [ \t\n\r]+ -> skip ;

    剩下的工作就简单多了,根据语法文件生成词法分析和语法分析器。

    下面就需要我们自己的代码了。

    针对不同的json元素,我们需要进行不同的处理逻辑。

    然后将他们组装起来,成为一个XML格式的数据

    下面是一个原有的json数据

    {
        "description" : "An imaginary server config file",
        "logs" : {"level":"verbose", "dir":"/var/log"},
        "host" : "antlr.org",
        "admin": ["parrt", "tombu"],
        "aliases": []
    }

    我们的代码

    /***
     * 将json翻译成XML,非常经典和实用
     * 使用ParseTreeProperty暂存每个节点的内容,最后打印全部语法树
     ***/
    public class JSON2XML {
        public static class XMLEmitter extends JSONBaseListener {
            ParseTreeProperty<String> xml = new ParseTreeProperty<String>();
    
            String getXML(ParseTree ctx) {
                return xml.get(ctx);
            }
    
            void setXML(ParseTree ctx, String s) {
                xml.put(ctx, s);
            }
    
            public void exitJson(JSONParser.JsonContext ctx) {
                setXML(ctx, getXML(ctx.getChild(0)));
            }
    
            public void exitAnObject(JSONParser.AnObjectContext ctx) {
                StringBuilder buf = new StringBuilder();
                buf.append("\n");
                for (JSONParser.PairContext pctx : ctx.pair()) {
                    buf.append(getXML(pctx));
                }
                setXML(ctx, buf.toString());
            }
    
            public void exitEmptyObject(JSONParser.EmptyObjectContext ctx) {
                setXML(ctx, "");
            }
    
            public void exitArrayOfValues(JSONParser.ArrayOfValuesContext ctx) {
                StringBuilder buf = new StringBuilder();
                buf.append("\n");
                for (JSONParser.ValueContext vctx : ctx.value()) {
                    buf.append("<element>"); // conjure up element for valid XML
                    buf.append(getXML(vctx));
                    buf.append("</element>");
                    buf.append("\n");
                }
                setXML(ctx, buf.toString());
            }
    
            public void exitEmptyArray(JSONParser.EmptyArrayContext ctx) {
                setXML(ctx, "");
            }
    
            public void exitPair(JSONParser.PairContext ctx) {
    
                String tag = stripQuotes(ctx.STRING().getText());
                JSONParser.ValueContext vctx = ctx.value();
                String x = String.format("<%s>%s</%s>\n", tag, getXML(vctx), tag);
                setXML(ctx, x);
            }
    
            public void exitObjectValue(JSONParser.ObjectValueContext ctx) {
                // analogous to String value() {return object();}
                setXML(ctx, getXML(ctx.object()));
            }
    
            public void exitArrayValue(JSONParser.ArrayValueContext ctx) {
                setXML(ctx, getXML(ctx.array())); // String value() {return array();}
            }
    
            public void exitAtom(JSONParser.AtomContext ctx) {
                setXML(ctx, ctx.getText());
            }
    
            public void exitString(JSONParser.StringContext ctx) {
                setXML(ctx, stripQuotes(ctx.getText()));
            }
    
            //剥离json双引号
            public static String stripQuotes(String s) {
                if (s == null || s.charAt(0) != '"') return s;
                return s.substring(1, s.length() - 1);
            }
        }
    
        public static void main(String[] args) throws Exception {
            String fileName = "listener/json/t.json";
            URL url = Resources.getResource(fileName);
            String sdl = Resources.toString(url, Charsets.UTF_8);
            System.out.println(sdl);
            CodePointCharStream input = CharStreams.fromString(sdl);
            JSONLexer lexer = new JSONLexer(input);
            CommonTokenStream tokens = new CommonTokenStream(lexer);
            JSONParser parser = new JSONParser(tokens);
            parser.setBuildParseTree(true);
            ParseTree tree = parser.json();
            // show tree in text form
    //        System.out.println(tree.toStringTree(parser));
    
            ParseTreeWalker walker = new ParseTreeWalker();
            XMLEmitter converter = new XMLEmitter();
            walker.walk(converter, tree);
            System.out.println(converter.getXML(tree));
        }
    }

    我们应用ParseTreeProperty来暂存了各个节点的内容。

    然后这些节点最终会聚合成一个完整的XML数据。

    下面展示输出的结果

    <description>An imaginary server config file</description>
    <logs>
    <level>verbose</level>
    <dir>/var/log</dir>
    </logs>
    <host>antlr.org</host>
    <admin>
    <element>parrt</element>
    <element>tombu</element>
    </admin>
    <aliases></aliases>

    一个完美的json2XML翻译器就完成了!

  • 相关阅读:
    C#(99):串口编程 System.IO.Ports.SerialPort类
    FastReport.Net的使用
    MongoDB(07):查询文档
    MongoDB(06):文档操作
    HIVE metastore Duplicate key name 'PCS_STATS_IDX' (state=42000,code=1061)
    RSync实现文件备份同步
    env: /etc/init.d/redis: Permission denied
    Multiple MySQL running but PID file could not be found
    centos 6.5卸载Mysql
    web应用性能测试-Tomcat 7 连接数和线程数配置
  • 原文地址:https://www.cnblogs.com/wangbin2188/p/16673399.html
Copyright © 2020-2023  润新知