其他分享
首页 > 其他分享> > 使用Antlr将json翻译成XML(转)

使用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翻译器就完成了!

标签:XML,String,Antlr,void,ctx,JSONParser,json,public
来源: https://www.cnblogs.com/wangbin2188/p/16673399.html