summaryrefslogtreecommitdiff
path: root/examples/jsonParser.py
blob: 0ea4aa1a3eb97cae627e2573c0d08c1b18f1a3e0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
# jsonParser.py
#
# Implementation of a simple JSON parser, returning a hierarchical
# ParseResults object support both list- and dict-style data access.
#
# Copyright 2006, by Paul McGuire
#
# Updated 8 Jan 2007 - fixed dict grouping bug, and made elements and
#   members optional in array and object collections
#
# Updated 9 Aug 2016 - use more current pyparsing constructs/idioms
#
json_bnf = """
object
    { members }
    {}
members
    string : value
    members , string : value
array
    [ elements ]
    []
elements
    value
    elements , value
value
    string
    number
    object
    array
    true
    false
    null
"""

import pyparsing as pp
from pyparsing import pyparsing_common as ppc


def make_keyword(kwd_str, kwd_value):
    return pp.Keyword(kwd_str).setParseAction(pp.replaceWith(kwd_value))


# set to False to return ParseResults
RETURN_PYTHON_COLLECTIONS = True

TRUE = make_keyword("true", True)
FALSE = make_keyword("false", False)
NULL = make_keyword("null", None)

LBRACK, RBRACK, LBRACE, RBRACE, COLON = map(pp.Suppress, "[]{}:")

jsonString = pp.dblQuotedString().setParseAction(pp.removeQuotes)
jsonNumber = ppc.number().setName("jsonNumber")

jsonObject = pp.Forward().setName("jsonObject")
jsonValue = pp.Forward().setName("jsonValue")

jsonElements = pp.delimitedList(jsonValue).setName(None)
# jsonArray = pp.Group(LBRACK + pp.Optional(jsonElements, []) + RBRACK)
# jsonValue << (
#     jsonString | jsonNumber | pp.Group(jsonObject) | jsonArray | TRUE | FALSE | NULL
# )
# memberDef = pp.Group(jsonString + COLON + jsonValue).setName("jsonMember")

jsonArray = pp.Group(
    LBRACK + pp.Optional(jsonElements) + RBRACK, aslist=RETURN_PYTHON_COLLECTIONS
).setName("jsonArray")

jsonValue << (jsonString | jsonNumber | jsonObject | jsonArray | TRUE | FALSE | NULL)

memberDef = pp.Group(
    jsonString + COLON + jsonValue, aslist=RETURN_PYTHON_COLLECTIONS
).setName("jsonMember")

jsonMembers = pp.delimitedList(memberDef).setName(None)
# jsonObject << pp.Dict(LBRACE + pp.Optional(jsonMembers) + RBRACE)
jsonObject << pp.Dict(
    LBRACE + pp.Optional(jsonMembers) + RBRACE, asdict=RETURN_PYTHON_COLLECTIONS
)

jsonComment = pp.cppStyleComment
jsonObject.ignore(jsonComment)


if __name__ == "__main__":
    testdata = """
    {
        "glossary": {
            "title": "example glossary",
            "GlossDiv": {
                "title": "S",
                "GlossList": [
                    {
                    "ID": "SGML",
                    "SortAs": "SGML",
                    "GlossTerm": "Standard Generalized Markup Language",
                    "TrueValue": true,
                    "FalseValue": false,
                    "Gravity": -9.8,
                    "LargestPrimeLessThan100": 97,
                    "AvogadroNumber": 6.02E23,
                    "EvenPrimesGreaterThan2": null,
                    "PrimesLessThan10" : [2,3,5,7],
                    "Acronym": "SGML",
                    "Abbrev": "ISO 8879:1986",
                    "GlossDef": "A meta-markup language, used to create markup languages such as DocBook.",
                    "GlossSeeAlso": ["GML", "XML", "markup"],
                    "EmptyDict" : {},
                    "EmptyList" : []
                    }
                ]
            }
        }
    }
    """

    results = jsonObject.parseString(testdata)

    results.pprint()
    if RETURN_PYTHON_COLLECTIONS:
        from pprint import pprint

        pprint(results)
    else:
        results.pprint()
    print()

    def testPrint(x):
        print(type(x), repr(x))

    if RETURN_PYTHON_COLLECTIONS:
        results = results[0]
        print(list(results["glossary"]["GlossDiv"]["GlossList"][0].keys()))
        testPrint(results["glossary"]["title"])
        testPrint(results["glossary"]["GlossDiv"]["GlossList"][0]["ID"])
        testPrint(results["glossary"]["GlossDiv"]["GlossList"][0]["FalseValue"])
        testPrint(results["glossary"]["GlossDiv"]["GlossList"][0]["Acronym"])
        testPrint(
            results["glossary"]["GlossDiv"]["GlossList"][0]["EvenPrimesGreaterThan2"]
        )
        testPrint(results["glossary"]["GlossDiv"]["GlossList"][0]["PrimesLessThan10"])
    else:
        print(list(results.glossary.GlossDiv.GlossList.keys()))
        testPrint(results.glossary.title)
        testPrint(results.glossary.GlossDiv.GlossList.ID)
        testPrint(results.glossary.GlossDiv.GlossList.FalseValue)
        testPrint(results.glossary.GlossDiv.GlossList.Acronym)
        testPrint(results.glossary.GlossDiv.GlossList.EvenPrimesGreaterThan2)
        testPrint(results.glossary.GlossDiv.GlossList.PrimesLessThan10)