XML及其相關的應用,曾經是很多人的回憶(痛?),
最近還被SOAP資料交換(XML)整到,
尤其是WSDL有些很舊的版本,沒辦法自動產生JAVA代碼。
因為XML太艱深,所以另一個極端(簡單)的網路資料交換的格式(JSON)就興起,
且行之有年。雖然開放數據(OPEN DATA),還是很多政府機關喜歡用EXCEL, 文字檔,
CSV檔來資料交換,但是XML的應用逐漸變少。
本練習是轉換JSON到XML。
JSON示例:
{
"description" : "An imaginary server config file",
"logs" : {"level":"verbose", "dir":"/var/log"},
"host" : "antlr.org",
"admin": ["parrt", "tombu"],
"aliases": []
}
轉換成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>
有了之前的經驗,做程式碼轉換的工作,Antlr的預設LISTNER模式,就很好用。
先抄一下別人寫的JSON文法檔
// Derived from http://json.org
grammar JSON;
json: object
| array
;
object
: '{' pair (',' pair)* '}' # AnObject
| '{' '}' # EmptyObject
;
array
: '[' value (',' value)* ']' # ArrayOfValues
| '[' ']' # EmptyArray
;
pair: STRING ':' value ;
value
: STRING # String
| NUMBER # Atom
| object # ObjectValue
| array # ArrayValue
| 'true' # Atom
| 'false' # Atom
| 'null' # Atom
;
LCURLY : '{' ;
LBRACK : '[' ;
STRING : '"' (ESC | ~["\\])* '"' ;
fragment ESC : '\\' (["\\/bfnrt] | UNICODE) ;
fragment UNICODE : 'u' HEX HEX HEX HEX ;
fragment HEX : [0-9a-fA-F] ;
NUMBER
: '-'? INT '.' INT 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 ;
其中 ,
'-'? :要嘛不出現,最多只能出現一次。
fragment : 文法中有很多重覆出現的元素時,可以給他一個簡單一點的別名,如文法裏的INT,它在NUMBER文法裏出現多次,就用INT代替,然後在下面的fragment INT :,把其內容詳述一次。
而# 是LABEL的註記,不是註解,註解是// ,不要搞混了。
本來,設計(E)BNF文法是一個高難度的工作,因為前人的無私分享,很多時候拿來用即可。
public class JSON2XML {
public static class XMLEmitter extends JSONBaseListener {
....................................................
public static void main(String[] args) throws Exception {
String inputFile = null;
if ( args.length>0 ) inputFile = args[0];
InputStream is = System.in;
if ( inputFile!=null ) {
is = new FileInputStream(inputFile);
}
ANTLRInputStream input = new ANTLRInputStream(is);
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));
}
}
主程式標準的寫法,大概都是這樣。