首页 > 解决方案 > 获取 JSON 字符串的抽象语法树

问题描述

问题描述

我正在编写一个简单的 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 对象,然后为每个键和值定义类型。但我想知道我是否走在了一条好路上,或者我正在发现轮子。是否已经有任何东西可以导出抽象语法树,或者我应该自己实现它?

标签: javajsongsonabstract-syntax-treecode-analysis

解决方案


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

您应该做的是将 JSON 解析器构建到您的应用程序中,将 JSON 解析为 AST 数据结构,然后直接处理该 AST 结构。坦率地说,JSON 非常简单,因此您可以编写自己的递归下降解析器来解析 JSON 并构建 AST,从而使您回到第一个解决方案。见https://stackoverflow.com/a/2336769/120163

如果您绝对坚持要导出它,您可以找到现成的工具。我们的 DMS Software Reengineering Toolkit 将做到这一点,尽管它对于此类应用程序可能有点重量级。

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

我已经截断了输出,因为没有人真的想看到树。现在,树中有很多“额外”的东西,例如节点位置、源代码行号,这些都可以很容易地消除或忽略。


推荐阅读