Skip to content

Commit 00d15bf

Browse files
committed
Added API to directly parse a json string containg an array
1 parent 7a9bb20 commit 00d15bf

11 files changed

+320
-88
lines changed

CHANGELOG

+18-10
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,18 @@
1-
v0.1.0:
2-
date: 2014-04-26
3-
changes:
4-
- Added support for DATE types.
5-
- Added support for JSONP.
6-
7-
v0.0.1:
8-
date: 2013-09-24
9-
changes:
10-
- Initial release of plsql_json.
1+
v0.2.0 - June 19, 2014
2+
3+
* 0.2.0 (Dieter Oberkofler)
4+
* Now using 3 individual parse methods in json_parser allowing to parse an object, an array or any of the two. (Dieter Oberkofler)
5+
* Added a new constructor to json_array allowing to parse a JSON string representing an array. Proposed by matthias-oe. (Dieter Oberkofler)
6+
* Added a new constructor to json_value allowing to parse a JSON string representing an object or an array. (Dieter Oberkofler)
7+
* Added unit tests for the new functionality. (Dieter Oberkofler)
8+
9+
v0.1.0 - April 26, 2014
10+
11+
* 0.1.0 (Dieter Oberkofler)
12+
* Added support for DATE types.
13+
* Added support for JSONP.
14+
15+
v0.0.1 - September 24, 2013
16+
17+
* 0.0.1 (Dieter Oberkofler)
18+
* Initial release of plsql_json.

install.sql

+7-7
Original file line numberDiff line numberDiff line change
@@ -16,21 +16,15 @@
1616
@@uninstall.sql
1717

1818

19-
-- install the types
19+
-- install the headers
2020
@@json_keys.tps
2121
show errors
2222
@@json_node.tps
2323
show errors
24-
@@json_node.tpb
25-
show errors
2624
@@json_nodes.tps
2725
show errors
2826
@@json_value.tps
2927
show errors
30-
@@json_value.tpb
31-
show errors
32-
33-
-- install the packages
3428
@@json_object.tps
3529
show errors
3630
@@json_array.tps
@@ -41,6 +35,12 @@ show errors
4135
show errors
4236
@@json_debug.pks
4337
show errors
38+
39+
-- install the bodies
40+
@@json_node.tpb
41+
show errors
42+
@@json_value.tpb
43+
show errors
4444
@@json_object.tpb
4545
show errors
4646
@@json_array.tpb

json_array.tpb

+11
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,17 @@ BEGIN
2828
RETURN;
2929
END json_array;
3030

31+
----------------------------------------------------------
32+
-- json_array
33+
--
34+
CONSTRUCTOR FUNCTION json_array(SELF IN OUT NOCOPY json_array, theJSONString IN CLOB) RETURN SELF AS result
35+
IS
36+
BEGIN
37+
SELF.nodes := json_parser.parse_array(theJSONString);
38+
SELF.lastID := NULL;
39+
RETURN;
40+
END json_array;
41+
3142
----------------------------------------------------------
3243
-- append
3344
--

json_array.tps

+1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ TYPE json_array IS OBJECT
77
-- Constructors
88
CONSTRUCTOR FUNCTION json_array(self IN OUT NOCOPY json_array) RETURN self AS result,
99
CONSTRUCTOR FUNCTION json_array(SELF IN OUT NOCOPY json_array, theData IN json_value) RETURN SELF AS result,
10+
CONSTRUCTOR FUNCTION json_array(SELF IN OUT NOCOPY json_array, theJSONString IN CLOB) RETURN SELF AS result,
1011

1112
-- Member setter methods
1213
MEMBER PROCEDURE append(self IN OUT NOCOPY json_array),

json_object.tpb

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ END json_object;
3434
CONSTRUCTOR FUNCTION json_object(SELF IN OUT NOCOPY json_object, theJSONString IN CLOB) RETURN SELF AS result
3535
IS
3636
BEGIN
37-
SELF.nodes := json_parser.parser(theJSONString);
37+
SELF.nodes := json_parser.parse_object(theJSONString);
3838
SELF.lastID := NULL;
3939
RETURN;
4040
END json_object;

json_parser.pkb

+79-61
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ FUNCTION lexer(jsrc IN OUT NOCOPY json_src) RETURN lTokens;
3232

3333
PROCEDURE parseMem(tokens lTokens, indx IN OUT PLS_INTEGER, mem_name VARCHAR2, mem_indx NUMBER, theParentID IN OUT BINARY_INTEGER, theLastID IN OUT BINARY_INTEGER, theNodes IN OUT NOCOPY json_nodes);
3434

35+
FUNCTION parse(tokens IN lTokens, firstToken IN VARCHAR2) RETURN json_nodes;
36+
3537
----------------------------------------------------------
3638
-- GLOBAL MODULES
3739
----------------------------------------------------------
@@ -630,7 +632,7 @@ BEGIN
630632
RETURN;
631633

632634
ELSE
633-
p_error('Expected string or }', tok);
635+
p_error('Expected string or } but found '||tok.type_name, tok);
634636

635637
END CASE;
636638

@@ -788,7 +790,7 @@ BEGIN
788790
p_error('Premature exit in array', tok);
789791
END IF;
790792
ELSIF (tok.type_name != ']') THEN --error
791-
p_error('Expected , or ]', tok);
793+
p_error('Expected , or ] but found '||tok.type_name, tok);
792794
END IF;
793795

794796
END LOOP;
@@ -929,52 +931,17 @@ BEGIN
929931
END parseMem;
930932

931933
----------------------------------------------------------
932-
-- parse_list
934+
-- parse
933935
--
934-
FUNCTION parse_list(str CLOB) RETURN json_nodes
936+
FUNCTION parse(tokens IN lTokens, firstToken IN VARCHAR2) RETURN json_nodes
935937
IS
936-
tokens lTokens;
937-
--yyy obj json_list;
938-
obj json_nodes := json_nodes();
939-
indx PLS_INTEGER := 1;
940-
jsrc json_src;
941-
BEGIN
942-
debug('parse_list');
943-
updateDecimalPoint();
944-
jsrc := prepareClob(str);
945-
tokens := lexer(jsrc);
946-
IF (tokens(indx).type_name = '[') THEN
947-
indx := indx + 1;
948-
--yyy obj := parseArr(tokens, indx);
949-
ELSE
950-
raise_application_error(-20101, 'JSON List Parser exception - no [ start found');
951-
END IF;
952-
IF (tokens.count != indx) THEN
953-
p_error('] should end the JSON List object', tokens(indx));
954-
END IF;
955-
956-
RETURN obj;
957-
END parse_list;
958-
959-
----------------------------------------------------------
960-
-- parser
961-
--
962-
FUNCTION parser(str CLOB) RETURN json_nodes
963-
IS
964-
tokens lTokens;
965-
obj json_nodes := json_nodes();
966-
967-
indx PLS_INTEGER := 1;
968-
jsrc json_src;
969-
i BINARY_INTEGER;
938+
lastToken VARCHAR2(1) := NULL;
939+
nodes json_nodes := json_nodes();
940+
indx PLS_INTEGER := 1;
941+
--i BINARY_INTEGER := NULL;
970942
aParentID BINARY_INTEGER := NULL;
971943
aLastID BINARY_INTEGER := NULL;
972944
BEGIN
973-
updateDecimalPoint();
974-
jsrc := prepareClob(str);
975-
976-
tokens := lexer(jsrc);
977-
978945
-- dump tokens
979946
/*
980947
dbms_output.put_line('----------LEXER-S----------');
@@ -986,42 +953,93 @@ BEGIN
986953
dbms_output.put_line('----------LEXER-E----------');
987954
*/
988955

956+
IF (tokens(indx).type_name != firstToken) THEN
957+
raise_application_error(-20101, 'JSON Parser exception - invalid first token. Expected:'||firstToken||' bit found:'||tokens(indx).type_name);
958+
END IF;
959+
989960
IF (tokens(indx).type_name = '{') THEN
961+
lastToken := '}';
962+
indx := indx + 1;
963+
parseObj(tokens, indx, aParentID, aLastID, nodes);
964+
ELSIF (tokens(indx).type_name = '[') THEN
965+
lastToken := ']';
990966
indx := indx + 1;
991-
--yyy obj := parseObj(tokens, indx);
992-
parseObj(tokens, indx, aParentID, aLastID, obj);
967+
parseArr(tokens, indx, aParentID, aLastID, nodes);
993968
ELSE
994-
raise_application_error(-20101, 'JSON Parser exception - no { start found');
969+
raise_application_error(-20101, 'JSON Parser exception - no '||firstToken||' start found');
995970
END IF;
996971
IF (tokens.count != indx) THEN
997-
p_error('} should end the JSON object', tokens(indx));
972+
p_error(lastToken||' should end the last token in the JSON string', tokens(indx));
998973
END IF;
999974

1000-
RETURN obj;
1001-
END parser;
975+
RETURN nodes;
976+
END parse;
1002977

1003978
----------------------------------------------------------
1004-
-- parse_any
979+
-- parse_object
1005980
--
1006-
FUNCTION parse_any(str CLOB) RETURN /*yyy json_value*/json_nodes
981+
FUNCTION parse_object(str CLOB) RETURN json_nodes
1007982
IS
983+
jsrc json_src;
1008984
tokens lTokens;
1009-
--yyy obj json_list;
1010-
obj json_array := json_array();
1011-
indx PLS_INTEGER := 1;
985+
BEGIN
986+
updateDecimalPoint();
987+
jsrc := prepareClob(str);
988+
tokens := lexer(jsrc);
989+
990+
IF (tokens(1).type_name != '{') THEN
991+
raise_application_error(-20101, 'JSON Parser exception - invalid first token = '||tokens(1).type_name);
992+
END IF;
993+
994+
RETURN parse(tokens=>tokens, firstToken=>'{');
995+
END parse_object;
996+
997+
----------------------------------------------------------
998+
-- parse_array
999+
--
1000+
FUNCTION parse_array(str CLOB) RETURN json_nodes
1001+
IS
10121002
jsrc json_src;
1003+
tokens lTokens;
10131004
BEGIN
1014-
debug('parse_any');
1005+
updateDecimalPoint();
10151006
jsrc := prepareClob(str);
10161007
tokens := lexer(jsrc);
1017-
tokens(tokens.count+1).type_name := ']';
1018-
--yyy obj := parseArr(tokens, indx);
1019-
IF (tokens.count != indx) THEN
1020-
p_error('] should end the JSON List object', tokens(indx));
1008+
1009+
IF (tokens(1).type_name != '[') THEN
1010+
raise_application_error(-20101, 'JSON Parser exception - invalid first token = '||tokens(1).type_name);
1011+
END IF;
1012+
1013+
RETURN parse(tokens=>tokens, firstToken=>'[');
1014+
END parse_array;
1015+
1016+
----------------------------------------------------------
1017+
-- parse_any
1018+
--
1019+
FUNCTION parse_any(str CLOB) RETURN json_value
1020+
IS
1021+
firstToken VARCHAR2(1);
1022+
jsrc json_src;
1023+
tokens lTokens;
1024+
value json_value := json_value();
1025+
BEGIN
1026+
updateDecimalPoint();
1027+
jsrc := prepareClob(str);
1028+
tokens := lexer(jsrc);
1029+
1030+
IF (tokens(1).type_name = '{') THEN
1031+
firstToken := tokens(1).type_name;
1032+
value.typ := 'O';
1033+
ELSIF (tokens(1).type_name = '[') THEN
1034+
firstToken := tokens(1).type_name;
1035+
value.typ := 'A';
1036+
ELSE
1037+
raise_application_error(-20101, 'JSON Parser exception - invalid first token = '||tokens(1).type_name);
10211038
END IF;
10221039

1023-
--yyy return obj.head();
1024-
RETURN NULL;
1040+
value.nodes := parse(tokens=>tokens, firstToken=>firstToken);
1041+
1042+
RETURN value;
10251043
END parse_any;
10261044

10271045
END json_parser;

json_parser.pks

+3-3
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,9 @@ json_strict BOOLEAN NOT NULL := FALSE;
4949
-- GLOBAL PUBLIC MODULES
5050
----------------------------------------------------------
5151

52-
FUNCTION parser(str CLOB) RETURN json_nodes;
53-
FUNCTION parse_list(str CLOB) RETURN json_nodes;
54-
FUNCTION parse_any(str CLOB) RETURN json_nodes;
52+
FUNCTION parse_object(str CLOB) RETURN json_nodes;
53+
FUNCTION parse_array(str CLOB) RETURN json_nodes;
54+
FUNCTION parse_any(str CLOB) RETURN json_value;
5555

5656
END json_parser;
5757
/

json_value.tpb

+13
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,19 @@ BEGIN
1414
RETURN;
1515
END json_value;
1616

17+
----------------------------------------------------------
18+
-- json_value
19+
--
20+
CONSTRUCTOR FUNCTION json_value(SELF IN OUT NOCOPY json_value, theJSONString IN CLOB) RETURN SELF AS RESULT
21+
IS
22+
value json_value := json_value();
23+
BEGIN
24+
value := json_parser.parse_any(theJSONString);
25+
SELF.typ := value.typ;
26+
SELF.nodes := value.nodes;
27+
RETURN;
28+
END json_value;
29+
1730
----------------------------------------------------------
1831
-- get_type
1932
--

json_value.tps

+1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ TYPE json_value IS OBJECT
66

77
-- Default constructor
88
CONSTRUCTOR FUNCTION json_value(SELF IN OUT NOCOPY json_value) RETURN SELF AS RESULT,
9+
CONSTRUCTOR FUNCTION json_value(SELF IN OUT NOCOPY json_value, theJSONString IN CLOB) RETURN SELF AS RESULT,
910

1011
-- Member getter methods
1112
MEMBER FUNCTION get_type RETURN VARCHAR2,

0 commit comments

Comments
 (0)