获取JSON字符串的抽象语法树

5

问题描述

我正在编写一个简单的JSON分析器,以实现对JSON字符串的语法分析。我收到的是随机结构的JSON字符串,并且想要导出语法结构。因此,我希望得到一棵树形结构,描述JSON字符串的格式(键、值、数组等)和每个元素的类型。我已经找到了JSON的语法定义(如下所述)。

object
    {}
    { members } 
members
    pair
    pair , members
pair
    string : value
array
    []
    [ elements ]
elements
    value
    value , elements
value
    string
    number
    object
    array
    true
    false
    null 

例子

JSON字符串:

{"widget": {
    "null": null,
    "window": {
         153: "This is string",
        "boolean": true,
        "int": 500,
        "float": 5.555
    }
}}    

我想要得到类似以下的内容:

{ KEY_STR : {
     KEY_STR : null
     KEY_ARRAY : {
        KEY_INT: VALUE_STR,
        KEY_STR: VALUE_BOOL,
        KEY_STR: VALUE_INT,
        KEY_STR: VALUE_FLOAT
     }
}}

我正在使用带有GSON库的JAVA。

我的想法

我想导出抽象树以便自动创建我的消息。

我的问题

我已经开始使用JsonParser来实现它。我正在解析JSON对象,然后为每个键和值定义类型。但是我想知道我是否走在了正确的道路上,或者我正在重新发明轮子。是否已经存在任何可以导出抽象语法树的东西,还是我应该自己实现?


有什么意义呢?根据示例输出,“自动创建自己的消息”似乎不太可行,因为“KEY_STR”感觉比“widget”更广泛,至少对我来说是这样。 - tevemadar
顺便问一下,你打算如何表示这棵树?那个KEY_STR等的例子不完全是Java。 - tevemadar
你好 @tevemadar,也许我没有描述清楚我的问题,因为我有点困惑。让我解释一下整个情况。我收到了一堆具有随机结构的JSON字符串。我的第一个目标是用通用格式表示JSON结构。我之所以这样做是因为我想迭代JSON值并使用我自己的不同输入值。我认为语法树是一种强大的表示方法,可以迭代JSON。 - Manos Kirtas
另外,我想更改JSON的名称/键,以便用自己的一组键替换它们。简单来说,我只想保留所有这些JSON的结构,并使用另一组值和键对它们进行迭代。也许更好的方法是每次从现有的JSON创建新的JSON,并替换我想要的任何内容。因此,我在这里寻找答案(https://dev59.com/xmIj5IYBdhLWcg3wRTL3),希望能有所帮助。 - Manos Kirtas
1个回答

3

我不知道JsonParser将导出什么。但是一般来说,解析某些内容,然后从AST数据结构中导出AST形式,读取AST,然后从读取的AST中提取值似乎只是为了构建和维护大量开销的过程。

你应该将JSON解析器构建到你的应用程序中,将JSON解析为AST数据结构,然后直接处理该AST结构。JSON足够简单,你可以编写自己的递归下降解析器来解析JSON并构建AST,这会让你回到第一个解决方案。请参见https://dev59.com/v3E95IYBdhLWcg3wlu6z#2336769

如果你非常坚持要导出它,你可以找到现成的工具来完成这个任务。我们的DMS软件重新工程工具包可以做到这一点,尽管对于这种应用程序来说可能有点笨重。

JSON的一个好处就是其简单的语法。以下是DMS使用的语法:

-- JSON.atg: JSON domain grammar for DMS 
-- Copyright (C) 2011-2018 Semantic Designs, Inc.; All Rights Reserved
--
-- Update history:
--   Date         Initials   Changes Made
--   2011/09/02   CW         Created
--
-- Note that dangling commas in lists are off-spec
-- but I (CW) hate dealing with them
--
-- I'm not sure if JSON is supposed to have more than one entity per file
-- but I'm allowing it for robustness
--
-- TODO: name/value pair lists should be associative-commutative


JSON_text = ;
JSON_text = JSON_text object ;
JSON_text = JSON_text array ;

-- unordered set of name/value pairs
-- should be able to use an associative-commutative property directive
object = '{' name_value_pair_list '}' ;

-- empty production is for empty list, but will also allow multiple commas
name_value_pair_list = ;
name_value_pair_list = name_value_pair_list ',' ;
name_value_pair_list = name_value_pair_list name_value_pair ;

name_value_pair = STRING ':' value ;

-- ordered collection of values
array = '[' value_list ']' ;
value_list = value ;
value_list = value_list ',' value ;
value_list = value_list ',' value ',' ;

value = STRING ;
value = NUMBER_INT ;
value = NUMBER_FLOAT ;
value = object ;
value = array ;
value = 'true' ;
value = 'false' ;
value = 'null' ;

是的,它几乎完全匹配OP提供的抽象语法。

现在,你可以使用以下命令要求DMS解析文件并导出其AST:

run ..\DomainParser +AST  ..\..\..\Examples\One.js

对于包含此文本的JSON文件One.js

{
"from": "http://json.org/example.html"
}

{
"glossary": {
    "title": "example glossary",
        "GlossDiv": {
    "title": "S",
            "GlossList": {
        "GlossEntry": {
        "ID": "SGML",
                    "SortAs": "SGML",
                    "GlossTerm": "Standard Generalized Markup Language",
                    "Acronym": "SGML",
                    "Abbrev": "ISO 8879:1986",
                    "GlossDef": {
            "para": "A meta-markup language, used to create markup languages such as DocBook.",
                        "GlossSeeAlso": ["GML", "XML"]
        },
                    "GlossSee": "markup"
        }
    }
    }
}
}
<rest of file snipped>

解析器生成一个S-表达式

(JSON_text@JSON=2#59406e0^0 Line 1 Column 1 File C:/DMS/Domains/JSON/Examples/One.js
 (JSON_text@JSON=2#2199f60^1#59406e0:1 Line 1 Column 1 File C:/DMS/Domains/JSON/Examples/One.js
  (JSON_text@JSON=2#21912a0^1#2199f60:1 Line 1 Column 1 File C:/DMS/Domains/JSON/Examples/One.js
   (JSON_text@JSON=2#593df00^1#21912a0:1 Line 1 Column 1 File C:/DMS/Domains/JSON/Examples/One.js
   |(JSON_text@JSON=2#593d420^1#593df00:1 Line 1 Column 1 File C:/DMS/Domains/JSON/Examples/One.js
   | (JSON_text@JSON=2#593c580^1#593d420:1 Line 1 Column 1 File C:/DMS/Domains/JSON/Examples/One.js
   |  (JSON_text@JSON=1#593bec0^1#593c580:1 Line 1 Column 1 File C:/DMS/Domains/JSON/Examples/One.js)JSON_text
   |  (object@JSON=4#593c560^1#593c580:2 Line 1 Column 1 File C:/DMS/Domains/JSON/Examples/One.js
   |   (name_value_pair_list@JSON=7#593c520^1#593c560:1 Line 2 Column 5 File C:/DMS/Domains/JSON/Examples/One.js
   |   |(name_value_pair_list@JSON=5#593c420^1#593c520:1 Line 2 Column 5 File C:/DMS/Domains/JSON/Examples/One.js)name_value_pair_list
   |   |(name_value_pair@JSON=8#593c4e0^1#593c520:2 Line 2 Column 5 File C:/DMS/Domains/JSON/Examples/One.js
   |   | (STRING@JSON=24#593c400^1#593c4e0:1[`from'] Line 2 Column 5 File C:/DMS/Domains/JSON/Examples/One.js)STRING
   |   | (STRING@JSON=24#593c480^1#593c4e0:2[`http://json.org/example.html'] Line 2 Column 13 File C:/DMS/Domains/JSON/Examples/One.js)STRING
   |   |)name_value_pair#593c4e0
   |   )name_value_pair_list#593c520
   |  )object#593c560
   | )JSON_text#593c580
   | (object@JSON=4#593d400^1#593d420:2 Line 5 Column 1 File C:/DMS/Domains/JSON/Examples/One.js
   |  (name_value_pair_list@JSON=7#593d3c0^1#593d400:1 Line 6 Column 5 File C:/DMS/Domains/JSON/Examples/One.js
   |   (name_value_pair_list@JSON=5#593c5c0^1#593d3c0:1 Line 6 Column 5 File C:/DMS/Domains/JSON/Examples/One.js)name_value_pair_list
   |   (name_value_pair@JSON=8#593d380^1#593d3c0:2 Line 6 Column 5 File C:/DMS/Domains/JSON/Examples/One.js
   |   |(STRING@JSON=24#593c5a0^1#593d380:1[`glossary'] Line 6 Column 5 File C:/DMS/Domains/JSON/Examples/One.js)STRING
   |   |(object@JSON=4#593d360^1#593d380:2 Line 6 Column 17 File C:/DMS/Domains/JSON/Examples/One.js
   |   | (name_value_pair_list@JSON=7#593d340^1#593d360:1 Line 7 Column 9 File C:/DMS/Domains/JSON/Examples/One.js
   |   |  (name_value_pair_list@JSON=6#593c720^1#593d340:1 Line 7 Column 9 File C:/DMS/Domains/JSON/Examples/One.js
   |   |   (name_value_pair_list@JSON=7#593c6c0^1#593c720:1 Line 7 Column 9 File C:/DMS/Domains/JSON/Examples/One.js
   |   |   |(name_value_pair_list@JSON=5#593c600^1#593c6c0:1 Line 7 Column 9 File C:/DMS/Domains/JSON/Examples/One.js)name_value_pair_list
   |   |   |(name_value_pair@JSON=8#593c640^1#593c6c0:2 Line 7 Column 9 File C:/DMS/Domains/JSON/Examples/One.js
   |   |   | (STRING@JSON=24#593c5e0^1#593c640:1[`title'] Line 7 Column 9 File C:/DMS/Domains/JSON/Examples/One.js)STRING
   |   |   | (STRING@JSON=24#593c620^1#593c640:2[`example glossary'] Line 7 Column 18 File C:/DMS/Domains/JSON/Examples/One.js)STRING
   |   |   |)name_value_pair#593c640
   |   |   )name_value_pair_list#593c6c0
   |   |  )name_value_pair_list#593c720
   |   |  (name_value_pair@JSON=8#593d320^1#593d340:2 Line 8 Column 17 File C:/DMS/Domains/JSON/Examples/One.js
   |   |   (STRING@JSON=24#593c700^1#593d320:1[`GlossDiv'] Line 8 Column 17 File C:/DMS/Domains/JSON/Examples/One.js)STRING
   |   |   (object@JSON=4#593d300^1#593d320:2 Line 8 Column 29 File C:/DMS/Domains/JSON/Examples/One.js
   |   |   |(name_value_pair_list@JSON=7#593d2e0^1#593d300:1 Line 9 Column 13 File C:/DMS/Domains/JSON/Examples/One.js
   |   |   | (name_value_pair_list@JSON=6#593c880^1#593d2e0:1 Line 9 Column 13 File C:/DMS/Domains/JSON/Examples/One.js
   |   |   |  (name_value_pair_list@JSON=7#593c820^1#593c880:1 Line 9 Column 13 File C:/DMS/Domains/JSON/Examples/One.js
   |   |   |   (name_value_pair_list@JSON=5#593c760^1#593c820:1 Line 9 Column 13 File C:/DMS/Domains/JSON/Examples/One.js)name_value_pair_list
   |   |   |   (name_value_pair@JSON=8#593c7e0^1#593c820:2 Line 9 Column 13 File C:/DMS/Domains/JSON/Examples/One.js
   |   |   |   |(STRING@JSON=24#593c740^1#593c7e0:1[`title'] Line 9 Column 13 File C:/DMS/Domains/JSON/Examples/One.js)STRING
   |   |   |   |(STRING@JSON=24#593c780^1#593c7e0:2[`S'] Line 9 Column 22 File C:/DMS/Domains/JSON/Examples/One.js)STRING
   |   |   |   )name_value_pair#593c7e0
   |   |   |  )name_value_pair_list#593c820
   |   |   | )name_value_pair_list#593c880
   |   |   | (name_value_pair@JSON=8#593d2c0^1#593d2e0:2 Line 10 Column 25 File C:/DMS/Domains/JSON/Examples/One.js
   |   |   |  (STRING@JSON=24#593c860^1#593d2c0:1[`GlossList'] Line 10 Column 25 File C:/DMS/Domains/JSON/Examples/One.js)STRING
   |   |   |  (object@JSON=4#593d2a0^1#593d2c0:2 Line 10 Column 38 File C:/DMS/Domains/JSON/Examples/One.js
   |   |   |   (name_value_pair_list@JSON=7#593d280^1#593d2a0:1 Line 11 Column 17 File C:/DMS/Domains/JSON/Examples/One.js
   |   |   |   |(name_value_pair_list@JSON=5#593c8c0^1#593d280:1 Line 11 Column 17 File C:/DMS/Domains/JSON/Examples/One.js)name_value_pair_list
   |   |   |   |(name_value_pair@JSON=8#593d260^1#593d280:2 Line 11 Column 17 File C:/DMS/Domains/JSON/Examples/One.js
   |   |   |   | (STRING@JSON=24#593c8a0^1#593d260:1[`GlossEntry'] Line 11 Column 17 File C:/DMS/Domains/JSON/Examples/One.js)STRING
   |   |   |   | (object@JSON=4#593d240^1#593d260:2 Line 11 Column 31 File C:/DMS/Domains/JSON/Examples/One.js
   |   |   |   |  (name_value_pair_list@JSON=7#593d200^1#593d240:1 Line 12 Column 21 File C:/DMS/Domains/JSON/Examples/One.js
   |   |   |   |   (name_value_pair_list@JSON=6#593d160^1#593d200:1 Line 12 Column 21 File C:/DMS/Domains/JSON/Examples/One.js
   |   |   |   |   |(name_value_pair_list@JSON=7#593d120^1#593d160:1 Line 12 Column 21 File C:/DMS/Domains/JSON/Examples/One.js
   |   |   |   |   | (name_value_pair_list@JSON=6#593cde0^1#593d120:1 Line 12 Column 21 File C:/DMS/Domains/JSON/Examples/One.js
   |   |   |   |   |  (name_value_pair_list@JSON=7#593cd60^1#593cde0:1 Line 12 Column 21 File C:/DMS/Domains/JSON/Examples/One.js
   |   |   |   |   |   (name_value_pair_list@JSON=6#593cca0^1#593cd60:1 Line 12 Column 21 File C:/DMS/Domains/JSON/Examples/One.js
   |   |   |   |   |   |(name_value_pair_list@JSON=7#593cc60^1#593cca0:1 Line 12 Column 21 File C:/DMS/Domains/JSON/Examples/One.js
   |   |   |   |   |   | (name_value_pair_list@JSON=6#593cc00^1#593cc60:1 Line 12 Column 21 File C:/DMS/Domains/JSON/Examples/One.js
   |   |   |   |   |   |  (name_value_pair_list@JSON=7#593cb80^1#593cc00:1 Line 12 Column 21 File C:/DMS/Domains/JSON/Examples/One.js
   |   |   |   |   |   |   (name_value_pair_list@JSON=6#593cb00^1#593cb80:1 Line 12 Column 21 File C:/DMS/Domains/JSON/Examples/One.js
   |   |   |   |   |   |   |(name_value_pair_list@JSON=7#593cac0^1#593cb00:1 Line 12 Column 21 File C:/DMS/Domains/JSON/Examples/One.js
   |   |   |   |   |   |   | (name_value_pair_list@JSON=6#593ca60^1#593cac0:1 Line 12 Column 21 File C:/DMS/Domains/JSON/Examples/One.js
   |   |   |   |   |   |   |  (name_value_pair_list@JSON=7#593ca00^1#593ca60:1 Line 12 Column 21 File C:/DMS/Domains/JSON/Examples/One.js
   |   |   |   |   |   |   |   (name_value_pair_list@JSON=5#593c900^1#593ca00:1 Line 12 Column 21 File C:/DMS/Domains/JSON/Examples/One.js)name_value_pair_list
   |   |   |   |   |   |   |   (name_value_pair@JSON=8#593c9c0^1#593ca00:2 Line 12 Column 21 File C:/DMS/Domains/JSON/Examples/One.js
   |   |   |   |   |   |   |   |(STRING@JSON=24#593c8e0^1#593c9c0:1[`ID'] Line 12 Column 21 File C:/DMS/Domains/JSON/Examples/One.js)STRING
   |   |   |   |   |   |   |   |(STRING@JSON=24#593c920^1#593c9c0:2[`SGML'] Line 12 Column 27 File C:/DMS/Domains/JSON/Examples/One.js)STRING
   |   |   |   |   |   |   |   )name_value_pair#593c9c0
   |   |   |   |   |   |   |  )name_value_pair_list#593ca00
   |   |   |   |   |   |   | )name_value_pair_list#593ca60
   |   |   |   |   |   |   | (name_value_pair@JSON=8#593caa0^1#593cac0:2 Line 13 Column 41 File C:/DMS/Domains/JSON/Examples/One.js
   |   |   |   |   |   |   |  (STRING@JSON=24#593ca40^1#593caa0:1[`SortAs'] Line 13 Column 41 File C:/DMS/Domains/JSON/Examples/One.js)STRING
   |   |   |   |   |   |   |  (STRING@JSON=24#593ca80^1#593caa0:2[`SGML'] Line 13 Column 51 File C:/DMS/Domains/JSON/Examples/One.js)STRING
   |   |   |   |   |   |   | )name_value_pair#593caa0
   |   |   |   |   |   |   |)name_value_pair_list#593cac0

我已经截取了输出,因为没有人真正想要“看到”这棵树。现在,树中有很多“额外”的内容,如节点位置、源行号,这些都可以轻松地消除或忽略。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接