Fixed various issue with parsing string (such as \t and related),

Implemented escaping of slash '/' only in case of '</' to avoid potential issue with javascript and </script>
Many feature renaming to match Eiffel style and naming convention, kept previous feature as obsolete.
Restructured the library to make easy extraction of "converter" classes if needed in the future.
Updated part of the code to use new feature names.
This commit is contained in:
2014-09-24 20:08:12 +02:00
parent de282948e6
commit 19dbbf89e7
40 changed files with 1121 additions and 788 deletions

1
.gitattributes vendored
View File

@@ -7,3 +7,4 @@
*.ecf text *.ecf text
*.bat text *.bat text
*.json text *.json text
*.txt text

2
.gitignore vendored
View File

@@ -1,2 +1,2 @@
*.swp *.swp
EIFGENs EIFGENs/

View File

@@ -1,4 +1,4 @@
History file for EJSON History file for EJSON
====================== ======================
team: "" team: ""

View File

@@ -1,4 +1,4 @@
Copyright (c) 2010 Javier Velilla and others, http://ejson.origo.ethz.ch Copyright (c) 2010 Javier Velilla and others, http://ejson.origo.ethz.ch
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy

View File

@@ -52,27 +52,27 @@ feature -- Conversion
to_json (o: like object): detachable JSON_OBJECT to_json (o: like object): detachable JSON_OBJECT
local local
c: HASH_TABLE_ITERATION_CURSOR [ANY, HASHABLE]
js: JSON_STRING js: JSON_STRING
failed: BOOLEAN failed: BOOLEAN
do do
create Result.make create Result.make
from across
c := o.new_cursor o as c
until
c.after
loop loop
if attached {JSON_STRING} json.value (c.key) as l_key then if attached {JSON_STRING} json.value (c.key) as l_key then
js := l_key js := l_key
else else
create js.make_json (c.key.out) if attached {READABLE_STRING_GENERAL} c.key as s_key then
create js.make_from_string_general (s_key)
else
create js.make_from_string (c.key.out)
end
end end
if attached json.value (c.item) as jv then if attached json.value (c.item) as jv then
Result.put (jv, js) Result.put (jv, js)
else else
failed := True failed := True
end end
c.forth
end end
if failed then if failed then
Result := Void Result := Void

View File

@@ -51,17 +51,15 @@ feature -- Conversion
to_json (o: like object): detachable JSON_ARRAY to_json (o: like object): detachable JSON_ARRAY
local local
c: ITERATION_CURSOR [detachable ANY] c: ITERATION_CURSOR [detachable ANY]
jv: detachable JSON_VALUE
failed: BOOLEAN failed: BOOLEAN
do do
create Result.make_array create Result.make (o.count)
from from
c := o.new_cursor c := o.new_cursor
until until
c.after c.after
loop loop
jv := json.value (c.item) if attached json.value (c.item) as jv then
if jv /= Void then
Result.add (jv) Result.add (jv)
else else
failed := True failed := True

View File

@@ -27,7 +27,7 @@ feature -- Access
if an_object = Void then if an_object = Void then
create {JSON_NULL} Result create {JSON_NULL} Result
elseif attached {BOOLEAN} an_object as b then elseif attached {BOOLEAN} an_object as b then
create {JSON_BOOLEAN} Result.make_boolean (b) create {JSON_BOOLEAN} Result.make (b)
elseif attached {INTEGER_8} an_object as i8 then elseif attached {INTEGER_8} an_object as i8 then
create {JSON_NUMBER} Result.make_integer (i8) create {JSON_NUMBER} Result.make_integer (i8)
elseif attached {INTEGER_16} an_object as i16 then elseif attached {INTEGER_16} an_object as i16 then
@@ -49,7 +49,7 @@ feature -- Access
elseif attached {REAL_64} an_object as r64 then elseif attached {REAL_64} an_object as r64 then
create {JSON_NUMBER} Result.make_real (r64) create {JSON_NUMBER} Result.make_real (r64)
elseif attached {ARRAY [detachable ANY]} an_object as a then elseif attached {ARRAY [detachable ANY]} an_object as a then
create ja.make_array create ja.make (a.count)
from from
i := a.lower i := a.lower
until until
@@ -66,13 +66,13 @@ feature -- Access
end end
Result := ja Result := ja
elseif attached {CHARACTER_8} an_object as c8 then elseif attached {CHARACTER_8} an_object as c8 then
create {JSON_STRING} Result.make_json (c8.out) create {JSON_STRING} Result.make_from_string (c8.out)
elseif attached {CHARACTER_32} an_object as c32 then elseif attached {CHARACTER_32} an_object as c32 then
create {JSON_STRING} Result.make_json (c32.out) create {JSON_STRING} Result.make_from_string_32 (create {STRING_32}.make_filled (c32, 1))
elseif attached {STRING_8} an_object as s8 then elseif attached {STRING_8} an_object as s8 then
create {JSON_STRING} Result.make_json (s8) create {JSON_STRING} Result.make_from_string (s8)
elseif attached {STRING_32} an_object as s32 then elseif attached {STRING_32} an_object as s32 then
create {JSON_STRING} Result.make_json_from_string_32 (s32) create {JSON_STRING} Result.make_from_string_32 (s32)
end end
if Result = Void then if Result = Void then
-- Now check the converters -- Now check the converters
@@ -162,12 +162,10 @@ feature -- Access
-- "eJSON exception" if unable to convert value. -- "eJSON exception" if unable to convert value.
require require
json_not_void: json /= Void json_not_void: json /= Void
local
jv: detachable JSON_VALUE
do do
json_parser.set_representation (json) json_parser.set_representation (json)
jv := json_parser.parse json_parser.parse_content
if jv /= Void then if json_parser.is_valid and then attached json_parser.parsed_json_value as jv then
Result := object (jv, base_class) Result := object (jv, base_class)
end end
end end
@@ -192,8 +190,8 @@ feature -- Access
js_key, js_value: JSON_STRING js_key, js_value: JSON_STRING
do do
create Result.make create Result.make
create js_key.make_json ("$ref") create js_key.make_from_string ("$ref")
create js_value.make_json (s) create js_value.make_from_string (s)
Result.put (js_value, js_key) Result.put (js_value, js_key)
end end
@@ -207,7 +205,7 @@ feature -- Access
local local
c: ITERATION_CURSOR [STRING] c: ITERATION_CURSOR [STRING]
do do
create Result.make_array create Result.make (l.count)
from from
c := l.new_cursor c := l.new_cursor
until until
@@ -264,7 +262,7 @@ feature {NONE} -- Implementation (JSON parser)
json_parser: JSON_PARSER json_parser: JSON_PARSER
once once
create Result.make_parser ("") create Result.make_with_string ("{}")
end end
end -- class EJSON end -- class EJSON

View File

@@ -14,7 +14,7 @@ note
class class
SHARED_EJSON SHARED_EJSON
feature feature -- Access
json: EJSON json: EJSON
-- A shared EJSON instance with default converters for -- A shared EJSON instance with default converters for

View File

@@ -1,39 +0,0 @@
note
description: "Objects that ..."
date: "$Date$"
revision: "$Revision$"
class
JSON_FILE_READER
feature -- Access
read_json_from (a_path: STRING): detachable STRING
local
l_file: PLAIN_TEXT_FILE
template_content: STRING
l_last_string: detachable STRING
do
create l_file.make_with_name (a_path)
-- We perform several checks until we make a real attempt to open the file.
if not l_file.exists then
print ("error: '" + a_path + "' does not exist%N")
else
if not l_file.is_readable then
print ("error: '" + a_path + "' is not readable.%N")
else
l_file.open_read
create template_content.make_empty
l_file.read_stream (l_file.count)
l_last_string := l_file.last_string
check
l_last_string /= Void
end -- implied by postcondition of `l_file.read_stream'
template_content.append (l_last_string.string)
Result := template_content
l_file.close
end
end
end
end

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="ISO-8859-1"?> <?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-13-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-13-0 http://www.eiffel.com/developers/xml/configuration-1-13-0.xsd" name="json" uuid="4E21C3BD-7951-4C6E-A673-431E762D7414" library_target="json"> <system xmlns="http://www.eiffel.com/developers/xml/configuration-1-8-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-8-0 http://www.eiffel.com/developers/xml/configuration-1-8-0.xsd" name="json" uuid="4E21C3BD-7951-4C6E-A673-431E762D7414" library_target="json">
<target name="json"> <target name="json">
<root all_classes="true"/> <root all_classes="true"/>
<file_rule> <file_rule>
@@ -9,20 +9,13 @@
</file_rule> </file_rule>
<option trace="false" profile="false" debug="false" warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all" syntax="standard" namespace="EJSON.Library"> <option trace="false" profile="false" debug="false" warning="true" full_class_checking="true" is_attached_by_default="true" void_safety="all" syntax="standard" namespace="EJSON.Library">
<assertions/> <assertions/>
<warning name="export_class_missing" enabled="false"/>
<warning name="old_verbatim_strings" enabled="false"/>
<warning name="syntax" enabled="false"/>
<warning name="vjrv" enabled="false"/>
</option> </option>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf" readonly="true"/> <library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf" readonly="true"/>
<cluster name="json" location=".\" recursive="true"> <cluster name="json" location=".\" >
<file_rule> <cluster name="json_kernel" location=".\kernel" recursive="true"/>
<exclude>^/gobo$</exclude> <cluster name="json_parser" location=".\parser" recursive="true"/>
<exclude>^/kernel$</exclude> <cluster name="json_utility" location=".\utility" recursive="true"/>
<exclude>^/extras$</exclude>
</file_rule>
<cluster name="kernel" location=".\kernel\" recursive="true"/>
<cluster name="extras" location=".\extras\" recursive="true"/>
</cluster> </cluster>
<cluster name="json_converter" location=".\converter" recursive="true"/>
</target> </target>
</system> </system>

View File

@@ -9,20 +9,13 @@
</file_rule> </file_rule>
<option trace="false" profile="false" debug="false" warning="true" full_class_checking="true" void_safety="none" syntax="standard" namespace="EJSON.Library"> <option trace="false" profile="false" debug="false" warning="true" full_class_checking="true" void_safety="none" syntax="standard" namespace="EJSON.Library">
<assertions/> <assertions/>
<warning name="export_class_missing" enabled="false"/>
<warning name="old_verbatim_strings" enabled="false"/>
<warning name="syntax" enabled="false"/>
<warning name="vjrv" enabled="false"/>
</option> </option>
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf" readonly="true"/> <library name="base" location="$ISE_LIBRARY\library\base\base.ecf" readonly="true"/>
<cluster name="json" location=".\" recursive="true"> <cluster name="json" location=".\" >
<file_rule> <cluster name="json_kernel" location=".\kernel" recursive="true"/>
<exclude>^/gobo$</exclude> <cluster name="json_parser" location=".\parser" recursive="true"/>
<exclude>^/kernel$</exclude> <cluster name="json_utility" location=".\utility" recursive="true"/>
<exclude>^/extras$</exclude>
</file_rule>
<cluster name="kernel" location=".\kernel\" recursive="true"/>
<cluster name="extras" location=".\extras\" recursive="true"/>
</cluster> </cluster>
<cluster name="json_converter" location=".\converter" recursive="true"/>
</target> </target>
</system> </system>

View File

@@ -12,6 +12,6 @@
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf" readonly="true"/> <library name="base" location="$ISE_LIBRARY\library\base\base.ecf" readonly="true"/>
<library name="json" location="json.ecf" readonly="true"/> <library name="json" location="json.ecf" readonly="true"/>
<library name="gobo_structure" location="$ISE_LIBRARY\library\gobo\gobo_structure.ecf"/> <library name="gobo_structure" location="$ISE_LIBRARY\library\gobo\gobo_structure.ecf"/>
<cluster name="json_gobo" location=".\gobo" recursive="true" /> <cluster name="json_gobo_converter" location=".\gobo_converter" recursive="true" />
</target> </target>
</system> </system>

View File

@@ -7,9 +7,9 @@ note
[] []
[elements] [elements]
]" ]"
author: "Javier Velilla" author: "$Author$"
date: "2008/08/24" date: "$date$"
revision: "Revision 0.1" revision: "$Revision$"
class class
JSON_ARRAY JSON_ARRAY
@@ -23,14 +23,29 @@ inherit
DEBUG_OUTPUT DEBUG_OUTPUT
create create
make, make_empty,
make_array make_array
feature {NONE} -- Initialization feature {NONE} -- Initialization
make (nb: INTEGER)
-- Initialize JSON array with capacity of `nb' items.
do
create items.make (nb)
end
make_empty
-- Initialize empty JSON array.
do
make (0)
end
make_array make_array
-- Initialize JSON Array -- Initialize JSON Array
obsolete
"Use `make' Sept/2014"
do do
create values.make (10) make (10)
end end
feature -- Access feature -- Access
@@ -40,24 +55,19 @@ feature -- Access
require require
is_valid_index: valid_index (i) is_valid_index: valid_index (i)
do do
Result := values.i_th (i) Result := items.i_th (i)
end end
representation: STRING representation: STRING
local
i: INTEGER
do do
Result := "[" Result := "["
from across
i := 1 items as ic
until
i > count
loop loop
Result.append (i_th (i).representation) if Result.count > 1 then
i := i + 1
if i <= count then
Result.append_character (',') Result.append_character (',')
end end
Result.append (ic.item.representation)
end end
Result.append_character (']') Result.append_character (']')
end end
@@ -76,7 +86,7 @@ feature -- Access
new_cursor: ITERATION_CURSOR [JSON_VALUE] new_cursor: ITERATION_CURSOR [JSON_VALUE]
-- Fresh cursor associated with current structure -- Fresh cursor associated with current structure
do do
Result := values.new_cursor Result := items.new_cursor
end end
feature -- Mesurement feature -- Mesurement
@@ -84,7 +94,7 @@ feature -- Mesurement
count: INTEGER count: INTEGER
-- Number of items. -- Number of items.
do do
Result := values.count Result := items.count
end end
feature -- Status report feature -- Status report
@@ -101,18 +111,18 @@ feature -- Change Element
require require
v_not_void: v /= Void v_not_void: v /= Void
do do
values.put_front (v) items.put_front (v)
ensure ensure
has_new_value: old values.count + 1 = values.count and values.first = v has_new_value: old items.count + 1 = items.count and items.first = v
end end
add, extend (v: JSON_VALUE) add, extend (v: JSON_VALUE)
require require
v_not_void: v /= Void v_not_void: v /= Void
do do
values.extend (v) items.extend (v)
ensure ensure
has_new_value: old values.count + 1 = values.count and values.has (v) has_new_value: old items.count + 1 = items.count and items.has (v)
end end
prune_all (v: JSON_VALUE) prune_all (v: JSON_VALUE)
@@ -120,41 +130,44 @@ feature -- Change Element
require require
v_not_void: v /= Void v_not_void: v /= Void
do do
values.prune_all (v) items.prune_all (v)
ensure ensure
not_has_new_value: not values.has (v) not_has_new_value: not items.has (v)
end end
wipe_out wipe_out
-- Remove all items. -- Remove all items.
do do
values.wipe_out items.wipe_out
end end
feature -- Report feature -- Report
hash_code: INTEGER hash_code: INTEGER
-- Hash code value -- Hash code value
local
l_started: BOOLEAN
do do
from across
values.start items as ic
Result := values.item.hash_code
until
values.off
loop loop
Result := ((Result \\ 8388593) |<< 8) + values.item.hash_code if l_started then
values.forth Result := ((Result \\ 8388593) |<< 8) + ic.item.hash_code
else
Result := ic.item.hash_code
l_started := True
end end
Result := Result \\ values.count end
Result := Result \\ items.count
end end
feature -- Conversion feature -- Conversion
array_representation: ARRAYED_LIST [JSON_VALUE] array_representation: ARRAYED_LIST [JSON_VALUE]
-- Representation as a sequences of values -- Representation as a sequences of values.
-- be careful, modifying the return object may have impact on the original JSON_ARRAY object -- be careful, modifying the return object may have impact on the original JSON_ARRAY object.
do do
Result := values Result := items
end end
feature -- Status report feature -- Status report
@@ -167,10 +180,10 @@ feature -- Status report
feature {NONE} -- Implementation feature {NONE} -- Implementation
values: ARRAYED_LIST [JSON_VALUE] items: ARRAYED_LIST [JSON_VALUE]
-- Value container -- Value container
invariant invariant
value_not_void: values /= Void items_not_void: items /= Void
end end

View File

@@ -1,8 +1,8 @@
note note
description: "JSON Truth values" description: "JSON Boolean values"
author: "Javier Velilla" author: "$Author$"
date: "2008/08/24" date: "$Date$"
revision: "Revision 0.1" revision: "$Revision$"
class class
JSON_BOOLEAN JSON_BOOLEAN
@@ -12,14 +12,36 @@ inherit
JSON_VALUE JSON_VALUE
create create
make,
make_true, make_false,
make_boolean make_boolean
feature {NONE} -- Initialization feature {NONE} -- Initialization
make_boolean (an_item: BOOLEAN) make (a_value: BOOLEAN)
--Initialize. -- Initialize Current JSON boolean with `a_boolean'.
do do
item := an_item item := a_value
end
make_true
-- Initialize Current JSON boolean with True.
do
make (True)
end
make_false
-- Initialize Current JSON boolean with False.
do
make (False)
end
make_boolean (a_item: BOOLEAN)
-- Initialize.
obsolete
"Use `make' Sept/2014"
do
make (a_item)
end end
feature -- Access feature -- Access

View File

@@ -1,8 +1,8 @@
note note
description: "JSON Numbers, octal and hexadecimal formats are not used." description: "JSON Numbers, octal and hexadecimal formats are not used."
author: "Javier Velilla" author: "$Author$"
date: "2008/08/24" date: "$Date$"
revision: "Revision 0.1" revision: "$Revision$"
license: "MIT (see http://www.opensource.org/licenses/mit-license.php)" license: "MIT (see http://www.opensource.org/licenses/mit-license.php)"
class class
@@ -24,21 +24,21 @@ feature {NONE} -- initialization
-- Initialize an instance of JSON_NUMBER from the integer value of `an_argument'. -- Initialize an instance of JSON_NUMBER from the integer value of `an_argument'.
do do
item := an_argument.out item := an_argument.out
numeric_type := INTEGER_TYPE numeric_type := integer_type
end end
make_natural (an_argument: NATURAL_64) make_natural (an_argument: NATURAL_64)
-- Initialize an instance of JSON_NUMBER from the unsigned integer value of `an_argument'. -- Initialize an instance of JSON_NUMBER from the unsigned integer value of `an_argument'.
do do
item := an_argument.out item := an_argument.out
numeric_type := NATURAL_TYPE numeric_type := natural_type
end end
make_real (an_argument: DOUBLE) make_real (an_argument: REAL_64)
-- Initialize an instance of JSON_NUMBER from the floating point value of `an_argument'. -- Initialize an instance of JSON_NUMBER from the floating point value of `an_argument'.
do do
item := an_argument.out item := an_argument.out
numeric_type := DOUBLE_TYPE numeric_type := double_type
end end
feature -- Access feature -- Access
@@ -46,6 +46,9 @@ feature -- Access
item: STRING item: STRING
-- Content -- Content
numeric_type: INTEGER
-- Type of number (integer, natural or real).
hash_code: INTEGER hash_code: INTEGER
--Hash code value --Hash code value
do do
@@ -57,6 +60,52 @@ feature -- Access
Result := item Result := item
end end
feature -- Conversion
integer_64_item: INTEGER_64
-- Associated integer value.
require
is_integer: is_integer
do
Result := item.to_integer_64
end
natural_64_item: NATURAL_64
-- Associated natural value.
require
is_natural: is_natural
do
Result := item.to_natural_64
end
double_item, real_64_item: REAL_64
-- Associated real value.
require
is_real: is_real
do
Result := item.to_real_64
end
feature -- Status report
is_integer: BOOLEAN
-- Is Current an integer number?
do
Result := numeric_type = integer_type
end
is_natural: BOOLEAN
-- Is Current a natural number?
do
Result := numeric_type = natural_type
end
is_double, is_real: BOOLEAN
-- Is Current a real number?
do
Result := numeric_type = real_type
end
feature -- Visitor pattern feature -- Visitor pattern
accept (a_visitor: JSON_VISITOR) accept (a_visitor: JSON_VISITOR)
@@ -85,13 +134,11 @@ feature -- Status report
feature -- Implementation feature -- Implementation
INTEGER_TYPE: INTEGER = 1 integer_type: INTEGER = 1
DOUBLE_TYPE: INTEGER = 2 double_type, real_type: INTEGER = 2
NATURAL_TYPE: INTEGER = 3 natural_type: INTEGER = 3
numeric_type: INTEGER
invariant invariant
item_not_void: item /= Void item_not_void: item /= Void

View File

@@ -4,14 +4,14 @@ note
An object is an unordered set of name/value pairs An object is an unordered set of name/value pairs
Examples: Examples:
object object
{} {}
{"key": value}
{"key": "value"} {"key": "value"}
]" ]"
author: "Javier Velilla" author: "$Author$"
date: "2008/08/24" date: "$Date$"
revision: "Revision 0.1" revision: "$Revision$"
license: "MIT (see http://www.opensource.org/licenses/mit-license.php)" license: "MIT (see http://www.opensource.org/licenses/mit-license.php)"
class class
@@ -26,213 +26,226 @@ inherit
DEBUG_OUTPUT DEBUG_OUTPUT
create create
make make_empty, make_with_capacity, make
feature {NONE} -- Initialization feature {NONE} -- Initialization
make make_with_capacity (nb: INTEGER)
-- Initialize -- Initialize with a capacity of `nb' items.
do do
create object.make (10) create items.make (nb)
end
make_empty
-- Initialize as empty object.
do
make_with_capacity (0)
end
make
-- Initialize with default capacity.
do
make_with_capacity (3)
end end
feature -- Change Element feature -- Change Element
put (value: detachable JSON_VALUE; key: JSON_STRING) put (a_value: detachable JSON_VALUE; a_key: JSON_STRING)
-- Assuming there is no item of key `key', -- Assuming there is no item of key `a_key',
-- insert `value' with `key'. -- insert `a_value' with `a_key'.
require require
key_not_present: not has_key (key) a_key_not_present: not has_key (a_key)
local
l_value: like value
do do
l_value := value if a_value = Void then
if l_value = Void then items.extend (create {JSON_NULL}, a_key)
create {JSON_NULL} l_value else
items.extend (a_value, a_key)
end end
object.extend (l_value, key)
end end
put_string (value: READABLE_STRING_GENERAL; key: JSON_STRING) put_string (a_value: READABLE_STRING_GENERAL; a_key: JSON_STRING)
-- Assuming there is no item of key `key', -- Assuming there is no item of key `a_key',
-- insert `value' with `key'. -- insert `a_value' with `a_key'.
require require
key_not_present: not has_key (key) key_not_present: not has_key (a_key)
local local
l_value: JSON_STRING l_value: JSON_STRING
do do
create l_value.make_json_from_string_32 (value.as_string_32) if attached {READABLE_STRING_8} a_value as s then
put (l_value, key) create l_value.make_from_string (s)
else
create l_value.make_from_string_32 (a_value.as_string_32)
end
put (l_value, a_key)
end end
put_integer (value: INTEGER_64; key: JSON_STRING) put_integer (a_value: INTEGER_64; a_key: JSON_STRING)
-- Assuming there is no item of key `key', -- Assuming there is no item of key `a_key',
-- insert `value' with `key'. -- insert `a_value' with `a_key'.
require require
key_not_present: not has_key (key) key_not_present: not has_key (a_key)
local local
l_value: JSON_NUMBER l_value: JSON_NUMBER
do do
create l_value.make_integer (value) create l_value.make_integer (a_value)
put (l_value, key) put (l_value, a_key)
end end
put_natural (value: NATURAL_64; key: JSON_STRING) put_natural (a_value: NATURAL_64; a_key: JSON_STRING)
-- Assuming there is no item of key `key', -- Assuming there is no item of key `a_key',
-- insert `value' with `key'. -- insert `a_value' with `a_key'.
require require
key_not_present: not has_key (key) key_not_present: not has_key (a_key)
local local
l_value: JSON_NUMBER l_value: JSON_NUMBER
do do
create l_value.make_natural (value) create l_value.make_natural (a_value)
put (l_value, key) put (l_value, a_key)
end end
put_real (value: DOUBLE; key: JSON_STRING) put_real (a_value: DOUBLE; a_key: JSON_STRING)
-- Assuming there is no item of key `key', -- Assuming there is no item of key `a_key',
-- insert `value' with `key'. -- insert `a_value' with `a_key'.
require require
key_not_present: not has_key (key) key_not_present: not has_key (a_key)
local local
l_value: JSON_NUMBER l_value: JSON_NUMBER
do do
create l_value.make_real (value) create l_value.make_real (a_value)
put (l_value, key) put (l_value, a_key)
end end
put_boolean (value: BOOLEAN; key: JSON_STRING) put_boolean (a_value: BOOLEAN; a_key: JSON_STRING)
-- Assuming there is no item of key `key', -- Assuming there is no item of key `a_key',
-- insert `value' with `key'. -- insert `a_value' with `a_key'.
require require
key_not_present: not has_key (key) key_not_present: not has_key (a_key)
local local
l_value: JSON_BOOLEAN l_value: JSON_BOOLEAN
do do
create l_value.make_boolean (value) create l_value.make (a_value)
put (l_value, key) put (l_value, a_key)
end end
replace (value: detachable JSON_VALUE; key: JSON_STRING) replace (a_value: detachable JSON_VALUE; a_key: JSON_STRING)
-- Assuming there is no item of key `key', -- Assuming there is no item of key `a_key',
-- insert `value' with `key'. -- insert `a_value' with `a_key'.
local
l_value: like value
do do
l_value := value if a_value = Void then
if l_value = Void then items.force (create {JSON_NULL}, a_key)
create {JSON_NULL} l_value else
items.force (a_value, a_key)
end end
object.force (l_value, key)
end end
replace_with_string (value: READABLE_STRING_GENERAL; key: JSON_STRING) replace_with_string (a_value: READABLE_STRING_GENERAL; a_key: JSON_STRING)
-- Assuming there is no item of key `key', -- Assuming there is no item of key `a_key',
-- insert `value' with `key'. -- insert `a_value' with `a_key'.
local local
l_value: JSON_STRING l_value: JSON_STRING
do do
create l_value.make_json_from_string_32 (value.as_string_32) if attached {READABLE_STRING_8} a_value as s then
replace (l_value, key) create l_value.make_from_string (s)
else
create l_value.make_from_string_32 (a_value.as_string_32)
end
replace (l_value, a_key)
end end
replace_with_integer (value: INTEGER_64; key: JSON_STRING) replace_with_integer (a_value: INTEGER_64; a_key: JSON_STRING)
-- Assuming there is no item of key `key', -- Assuming there is no item of key `a_key',
-- insert `value' with `key'. -- insert `a_value' with `a_key'.
local local
l_value: JSON_NUMBER l_value: JSON_NUMBER
do do
create l_value.make_integer (value) create l_value.make_integer (a_value)
replace (l_value, key) replace (l_value, a_key)
end end
replace_with_with_natural (value: NATURAL_64; key: JSON_STRING) replace_with_with_natural (a_value: NATURAL_64; a_key: JSON_STRING)
-- Assuming there is no item of key `key', -- Assuming there is no item of key `a_key',
-- insert `value' with `key'. -- insert `a_value' with `a_key'.
local local
l_value: JSON_NUMBER l_value: JSON_NUMBER
do do
create l_value.make_natural (value) create l_value.make_natural (a_value)
replace (l_value, key) replace (l_value, a_key)
end end
replace_with_real (value: DOUBLE; key: JSON_STRING) replace_with_real (a_value: DOUBLE; a_key: JSON_STRING)
-- Assuming there is no item of key `key', -- Assuming there is no item of key `a_key',
-- insert `value' with `key'. -- insert `a_value' with `a_key'.
local local
l_value: JSON_NUMBER l_value: JSON_NUMBER
do do
create l_value.make_real (value) create l_value.make_real (a_value)
replace (l_value, key) replace (l_value, a_key)
end end
replace_with_boolean (value: BOOLEAN; key: JSON_STRING) replace_with_boolean (a_value: BOOLEAN; a_key: JSON_STRING)
-- Assuming there is no item of key `key', -- Assuming there is no item of key `a_key',
-- insert `value' with `key'. -- insert `a_value' with `a_key'.
local local
l_value: JSON_BOOLEAN l_value: JSON_BOOLEAN
do do
create l_value.make_boolean (value) create l_value.make (a_value)
replace (l_value, key) replace (l_value, a_key)
end end
remove (key: JSON_STRING) remove (a_key: JSON_STRING)
-- Remove item indexed by `key' if any. -- Remove item indexed by `a_key' if any.
do do
object.remove (key) items.remove (a_key)
end end
wipe_out wipe_out
-- Reset all items to default values; reset status. -- Reset all items to default values; reset status.
do do
object.wipe_out items.wipe_out
end
feature -- Status report
has_key (a_key: JSON_STRING): BOOLEAN
-- has the JSON_OBJECT contains a specific key `a_key'.
do
Result := items.has (a_key)
end
has_item (a_value: JSON_VALUE): BOOLEAN
-- has the JSON_OBJECT contain a specfic item `a_value'
do
Result := items.has_item (a_value)
end end
feature -- Access feature -- Access
has_key (key: JSON_STRING): BOOLEAN item (a_key: JSON_STRING): detachable JSON_VALUE
-- has the JSON_OBJECT contains a specific key 'key'. -- the json_value associated with a key `a_key'.
do do
Result := object.has (key) Result := items.item (a_key)
end
has_item (value: JSON_VALUE): BOOLEAN
-- has the JSON_OBJECT contain a specfic item 'value'
do
Result := object.has_item (value)
end
item (key: JSON_STRING): detachable JSON_VALUE
-- the json_value associated with a key.
do
Result := object.item (key)
end end
current_keys: ARRAY [JSON_STRING] current_keys: ARRAY [JSON_STRING]
-- array containing actually used keys -- Array containing actually used keys.
do do
Result := object.current_keys Result := items.current_keys
end end
representation: STRING representation: STRING
local -- <Precursor>
t: HASH_TABLE [JSON_VALUE, JSON_STRING]
do do
create Result.make (2) create Result.make (2)
Result.append_character ('{') Result.append_character ('{')
from across
t := map_representation items as ic
t.start
until
t.after
loop loop
Result.append (t.key_for_iteration.representation) if Result.count > 1 then
Result.append_character (':')
Result.append (t.item_for_iteration.representation)
t.forth
if not t.after then
Result.append_character (',') Result.append_character (',')
end end
Result.append (ic.key.representation)
Result.append_character (':')
Result.append (ic.item.representation)
end end
Result.append_character ('}') Result.append_character ('}')
end end
@@ -240,9 +253,9 @@ feature -- Access
feature -- Mesurement feature -- Mesurement
count: INTEGER count: INTEGER
-- Number of field -- Number of field.
do do
Result := object.count Result := items.count
end end
feature -- Access feature -- Access
@@ -250,7 +263,7 @@ feature -- Access
new_cursor: TABLE_ITERATION_CURSOR [JSON_VALUE, JSON_STRING] new_cursor: TABLE_ITERATION_CURSOR [JSON_VALUE, JSON_STRING]
-- Fresh cursor associated with current structure -- Fresh cursor associated with current structure
do do
Result := object.new_cursor Result := items.new_cursor
end end
feature -- Status report feature -- Status report
@@ -258,7 +271,7 @@ feature -- Status report
is_empty: BOOLEAN is_empty: BOOLEAN
-- Is empty object? -- Is empty object?
do do
Result := object.is_empty Result := items.is_empty
end end
feature -- Visitor pattern feature -- Visitor pattern
@@ -275,7 +288,7 @@ feature -- Conversion
map_representation: HASH_TABLE [JSON_VALUE, JSON_STRING] map_representation: HASH_TABLE [JSON_VALUE, JSON_STRING]
-- A representation that maps keys to values -- A representation that maps keys to values
do do
Result := object Result := items
end end
feature -- Report feature -- Report
@@ -284,13 +297,13 @@ feature -- Report
-- Hash code value -- Hash code value
do do
from from
object.start items.start
Result := object.out.hash_code Result := items.out.hash_code
until until
object.off items.off
loop loop
Result := ((Result \\ 8388593) |<< 8) + object.item_for_iteration.hash_code Result := ((Result \\ 8388593) |<< 8) + items.item_for_iteration.hash_code
object.forth items.forth
end end
-- Ensure it is a positive value. -- Ensure it is a positive value.
Result := Result.hash_code Result := Result.hash_code
@@ -306,10 +319,10 @@ feature -- Status report
feature {NONE} -- Implementation feature {NONE} -- Implementation
object: HASH_TABLE [JSON_VALUE, JSON_STRING] items: HASH_TABLE [JSON_VALUE, JSON_STRING]
-- Value container -- Value container
invariant invariant
object_not_void: object /= Void items_not_void: items /= Void
end end

View File

@@ -4,9 +4,9 @@ note
A string is a collection of zero or more Unicodes characters, wrapped in double A string is a collection of zero or more Unicodes characters, wrapped in double
quotes, using blackslash espaces. quotes, using blackslash espaces.
]" ]"
author: "Javier Velilla" author: "$Author$"
date: "2008/08/24" date: "$Date$"
revision: "Revision 0.1" revision: "$Revision$"
license: "MIT (see http://www.opensource.org/licenses/mit-license.php)" license: "MIT (see http://www.opensource.org/licenses/mit-license.php)"
class class
@@ -20,16 +20,73 @@ inherit
end end
create create
make_json, make_json_from_string_32, make_with_escaped_json make_from_string, make_from_string_32, make_from_string_general,
make_from_escaped_json_string,
make_with_escaped_json, make_json, make_json_from_string_32
convert convert
make_json ({READABLE_STRING_8, STRING_8, IMMUTABLE_STRING_8}), make_from_string ({READABLE_STRING_8, STRING_8, IMMUTABLE_STRING_8}),
make_json_from_string_32 ({READABLE_STRING_32, STRING_32, IMMUTABLE_STRING_32}) make_from_string_32 ({READABLE_STRING_32, STRING_32, IMMUTABLE_STRING_32}),
make_from_string_general ({READABLE_STRING_GENERAL, STRING_GENERAL, IMMUTABLE_STRING_GENERAL})
feature {NONE} -- Initialization feature {NONE} -- Initialization
make_from_string (s: READABLE_STRING_8)
-- Initialize from ascii string `s'.
require
s_not_void: s /= Void
do
make_from_escaped_json_string (escaped_json_string (s))
end
make_from_string_32 (s: READABLE_STRING_32)
-- Initialize from unicode string `s'.
require
s_not_void: s /= Void
do
make_from_escaped_json_string (escaped_json_string (s))
end
make_from_string_general (s: READABLE_STRING_GENERAL)
-- Initialize from string `s'.
require
s_not_void: s /= Void
do
if attached {READABLE_STRING_8} s as s8 then
make_from_string (s8)
else
make_from_string_32 (s.as_string_32)
end
end
make_from_escaped_json_string (a_escaped_string: READABLE_STRING_8)
-- Initialize with `a_escaped_string' already JSON escaped.
require
a_escaped_string_not_void: a_escaped_string /= Void
do
item := a_escaped_string
end
make_with_escaped_json (a_escaped_string: READABLE_STRING_8)
-- Initialize with `a_escaped_string' already JSON escaped.
obsolete
"Use `make_from_escaped_json_string' Sept/2014"
require
a_escaped_string_not_void: a_escaped_string /= Void
do
make_from_escaped_json_string (a_escaped_string)
end
make_from_json_string (a_json: JSON_STRING)
-- Initialize with `a_json' string value.
do
make_from_escaped_json_string (a_json.item)
end
make_json (s: READABLE_STRING_8) make_json (s: READABLE_STRING_8)
-- Initialize. -- Initialize.
obsolete
"Use `make_from_string' Sept/2014"
require require
item_not_void: s /= Void item_not_void: s /= Void
do do
@@ -38,18 +95,12 @@ feature {NONE} -- Initialization
make_json_from_string_32 (s: READABLE_STRING_32) make_json_from_string_32 (s: READABLE_STRING_32)
-- Initialize from STRING_32 `s'. -- Initialize from STRING_32 `s'.
obsolete
"Use `make_from_string_32' Sept/2014"
require require
item_not_void: s /= Void item_not_void: s /= Void
do do
make_with_escaped_json (escaped_json_string_32 (s)) make_with_escaped_json (escaped_json_string (s))
end
make_with_escaped_json (s: READABLE_STRING_8)
-- Initialize with an_item already escaped
require
item_not_void: s /= Void
do
item := s
end end
feature -- Access feature -- Access
@@ -60,7 +111,7 @@ feature -- Access
feature -- Conversion feature -- Conversion
unescaped_string_8: STRING_8 unescaped_string_8: STRING_8
-- Unescaped string from `item'. -- Unescaped ascii string from `item'.
--| note: valid only if `item' does not encode any unicode character. --| note: valid only if `item' does not encode any unicode character.
local local
s: like item s: like item
@@ -71,7 +122,7 @@ feature -- Conversion
end end
unescaped_string_32: STRING_32 unescaped_string_32: STRING_32
-- Unescaped string 32 from `item' -- Unescaped uncode string from `item'
--| some encoders uses UTF-8 , and not the recommended pure json encoding --| some encoders uses UTF-8 , and not the recommended pure json encoding
--| thus, let's support the UTF-8 encoding during decoding. --| thus, let's support the UTF-8 encoding during decoding.
local local
@@ -83,7 +134,7 @@ feature -- Conversion
end end
representation: STRING representation: STRING
-- String representation of `item' with escaped entities if any -- String representation of `item' with escaped entities if any.
do do
create Result.make (item.count + 2) create Result.make (item.count + 2)
Result.append_character ('%"') Result.append_character ('%"')
@@ -110,11 +161,14 @@ feature -- Conversion
if c = '\' then if c = '\' then
if i < n then if i < n then
inspect s [i + 1] inspect s [i + 1]
when '%"' then
a_output.append_character ('%"')
i := i + 2
when '\' then when '\' then
a_output.append_character ('\') a_output.append_character ('\')
i := i + 2 i := i + 2
when '%"' then when '/' then
a_output.append_character ('%"') a_output.append_character ('/')
i := i + 2 i := i + 2
when 'b' then when 'b' then
a_output.append_character ('%B') a_output.append_character ('%B')
@@ -132,15 +186,15 @@ feature -- Conversion
a_output.append_character ('%T') a_output.append_character ('%T')
i := i + 2 i := i + 2
when 'u' then when 'u' then
--| Leave Unicode \uXXXX unescaped --| Leave unicode \uXXXX unescaped
a_output.append_character ('\') a_output.append_character (c) -- '\'
i := i + 1 i := i + 1
else else
a_output.append_character ('\') a_output.append_character (c) -- '\'
i := i + 1 i := i + 1
end end
else else
a_output.append_character ('\') a_output.append_character (c) -- '\'
i := i + 1 i := i + 1
end end
else else
@@ -172,11 +226,14 @@ feature -- Conversion
if ch = '\' then if ch = '\' then
if i < n then if i < n then
inspect s [i + 1] inspect s [i + 1]
when '%"' then
a_output.append_character ('%"')
i := i + 2
when '\' then when '\' then
a_output.append_character ('\') a_output.append_character ('\')
i := i + 2 i := i + 2
when '%"' then when '/' then
a_output.append_character ('%"') a_output.append_character ('/')
i := i + 2 i := i + 2
when 'b' then when 'b' then
a_output.append_character ('%B') a_output.append_character ('%B')
@@ -200,11 +257,11 @@ feature -- Conversion
end end
i := i + 6 -- i+2+4 i := i + 6 -- i+2+4
else else
a_output.append_character ('\') a_output.append_character (ch) -- '\'
i := i + 1 i := i + 1
end end
else else
a_output.append_character ('\') a_output.append_character (ch) -- '\'
i := i + 1 i := i + 1
end end
else else
@@ -259,12 +316,48 @@ feature -- Comparison
feature -- Change Element feature -- Change Element
append (a_string: STRING) append (a_escaped_string: READABLE_STRING_8)
-- Add a_string -- Add JSON escaped string `a_escaped_string'
require require
a_string_not_void: a_string /= Void a_escaped_string_not_void: a_escaped_string /= Void
do do
item.append_string (a_string) item.append_string (a_escaped_string)
end
append_json_string (a_json_string: JSON_STRING)
-- Add JSON string `a_json_string'
require
a_json_string_not_void: a_json_string /= Void
do
append (a_json_string.item)
end
append_string (s: READABLE_STRING_8)
-- Add ascii string `s'
require
s_not_void: s /= Void
do
append (escaped_json_string (s))
end
append_string_32 (s: READABLE_STRING_32)
-- Add unicode string `s'
require
s_not_void: s /= Void
do
append (escaped_json_string (s))
end
append_string_general (s: READABLE_STRING_GENERAL)
-- Add unicode string `s'
require
s_not_void: s /= Void
do
if attached {READABLE_STRING_8} s as s8 then
append_string (s.as_string_8)
else
append_string_32 (s.as_string_32)
end
end end
feature -- Status report feature -- Status report
@@ -331,46 +424,8 @@ feature {NONE} -- Implementation
end end
end end
escaped_json_string (s: READABLE_STRING_8): STRING_8 escaped_json_string (s: READABLE_STRING_GENERAL): STRING_8
-- JSON string with '"' and '\' characters escaped -- JSON string with '"' and '\' characters and unicode escaped
require
s_not_void: s /= Void
local
i, n: INTEGER
c: CHARACTER_8
do
n := s.count
create Result.make (n + n // 10)
from
i := 1
until
i > n
loop
c := s.item (i)
inspect c
when '%"' then
Result.append_string ("\%"")
when '\' then
Result.append_string ("\\")
when '%B' then
Result.append_string ("\b")
when '%F' then
Result.append_string ("\f")
when '%N' then
Result.append_string ("\n")
when '%R' then
Result.append_string ("\r")
when '%T' then
Result.append_string ("\t")
else
Result.extend (c)
end
i := i + 1
end
end
escaped_json_string_32 (s: READABLE_STRING_32): STRING_8
-- JSON string with '"' and '\' characters and Unicode escaped
require require
s_not_void: s /= Void s_not_void: s /= Void
local local
@@ -394,6 +449,14 @@ feature {NONE} -- Implementation
Result.append_string ("\%"") Result.append_string ("\%"")
when '\' then when '\' then
Result.append_string ("\\") Result.append_string ("\\")
when '/' then
-- To avoid issue with Javascript </script> ...
-- escape only </ to <\/
if s.valid_index (i - 1) and then s.item (i - 1) = '<' then
Result.append_string ("\/")
else
Result.append_string ("/")
end
when '%B' then when '%B' then
Result.append_string ("\b") Result.append_string ("\b")
when '%F' then when '%F' then
@@ -426,7 +489,7 @@ feature {NONE} -- Implementation
h.prepend_integer (0) h.prepend_integer (0)
end end
check check
h.count = 4 hexastring_has_4_chars: h.count = 4
end end
Result.append (h) Result.append (h)
end end

View File

@@ -1,79 +0,0 @@
note
description: ""
author: "jvelilla"
date: "2008/08/24"
revision: "0.1"
class
JSON_TOKENS
feature -- Access
j_OBJECT_OPEN: CHARACTER = '{'
j_ARRAY_OPEN: CHARACTER = '['
j_OBJECT_CLOSE: CHARACTER = '}'
j_ARRAY_CLOSE: CHARACTER = ']'
j_STRING: CHARACTER = '"'
j_PLUS: CHARACTER = '+'
j_MINUS: CHARACTER = '-'
j_DOT: CHARACTER = '.'
feature -- Status report
is_open_token (c: CHARACTER): BOOLEAN
-- Characters which open a type
do
inspect c
when j_OBJECT_OPEN, j_ARRAY_OPEN, j_STRING, j_PLUS, j_MINUS, j_DOT then
Result := True
else
end
end
is_close_token (c: CHARACTER): BOOLEAN
-- Characters which close a type
do
inspect c
when j_OBJECT_CLOSE, j_ARRAY_CLOSE, j_STRING then
Result := True
else
end
end
is_special_character (c: CHARACTER): BOOLEAN
-- Control Characters
-- %F Form feed
-- %H backslasH
-- %N Newline
-- %R carriage Return
-- %T horizontal Tab
-- %B Backspace
-- / Solidus
-- " Quotation
do
inspect c
when '%F', '%H', '%N', '%R', '%T', '%B', '/', '"' then
Result := True
else
end
end
is_special_control (c: CHARACTER): BOOLEAN
--Control Characters
-- \b\f\n\r\t
do
inspect c
when 'b', 'f', 'n', 'r', 't' then
Result := True
else
end
end
end

View File

@@ -8,24 +8,36 @@ class
JSON_PARSER JSON_PARSER
inherit inherit
JSON_READER JSON_READER
rename
make as make_reader,
reset as reset_reader
end
JSON_TOKENS JSON_TOKENS
create create
make_with_string,
make_parser make_parser
feature {NONE} -- Initialize feature {NONE} -- Initialize
make_with_string (a_content: STRING)
-- Initialize parser with JSON content `a_content'.
require
a_content_not_empty: a_content /= Void and then not a_content.is_empty
do
create errors.make
make_reader (a_content)
reset
end
make_parser (a_json: STRING) make_parser (a_json: STRING)
-- Initialize. -- Initialize.
require obsolete
json_not_empty: a_json /= Void and then not a_json.is_empty "Use `make_with_string' [sept/2014]."
do do
make (a_json) make_with_string (a_json)
is_parsed := True
create errors.make
end end
feature -- Status report feature -- Status report
@@ -33,23 +45,99 @@ feature -- Status report
is_parsed: BOOLEAN is_parsed: BOOLEAN
-- Is parsed ? -- Is parsed ?
is_valid: BOOLEAN
-- Is valid?
do
Result := not has_error
end
has_error: BOOLEAN
-- Has error?
errors: LINKED_LIST [STRING] errors: LINKED_LIST [STRING]
-- Current errors -- Current errors
current_errors: STRING errors_as_string: STRING
-- Current errors as string -- String representation of `errors'.
do do
create Result.make_empty create Result.make_empty
from across
errors.start errors as ic
until
errors.after
loop loop
Result.append_string (errors.item + "%N") Result.append_string (ic.item)
errors.forth Result.append_character ('%N')
end end
end end
current_errors: STRING
-- Current errors as string
obsolete
"USe errors_as_string [sept/2014]"
do
Result := errors_as_string
end
feature -- Access
parsed_json_value: detachable JSON_VALUE
-- Parsed json value if any.
require
is_parsed: is_parsed
attribute
ensure
attached_result_if_valid: is_valid implies Result /= Void
end
parsed_json_object: detachable JSON_OBJECT
-- parsed json value as a JSON_OBJECT if it is an object.
require
is_parsed: is_parsed
do
if attached {JSON_OBJECT} parsed_json_value as j_object then
Result := j_object
end
end
parsed_json_array: detachable JSON_ARRAY
-- parsed json value as a JSON_OBJECT if it is an array.
require
is_parsed: is_parsed
do
if attached {JSON_ARRAY} parsed_json_value as j_array then
Result := j_array
end
end
feature -- Commands
reset
-- Reset parsing values.
do
parsed_json_value := Void
errors.wipe_out
has_error := False
is_parsed := False
end
parse_content
-- Parse JSON content `representation'.
-- start ::= object | array
do
reset
reset_reader
if is_valid_start_symbol then
parsed_json_value := next_json_value
if extra_elements then
report_error ("Remaining element outside the main json value!")
end
else
report_error ("Syntax error unexpected token, expecting `{' or `['")
end
is_parsed := is_valid
end
feature -- Element change feature -- Element change
report_error (e: STRING) report_error (e: STRING)
@@ -57,43 +145,64 @@ feature -- Element change
require require
e_not_void: e /= Void e_not_void: e /= Void
do do
has_error := True
errors.force (e) errors.force (e)
ensure
has_error: has_error
is_not_valid: not is_valid
end end
feature -- Commands feature -- Obsolete commands
parse_json: detachable JSON_VALUE parse_json: detachable JSON_VALUE
-- Parse JSON data `representation' -- Parse JSON data `representation'
-- start ::= object | array -- start ::= object | array
obsolete
"Use `parse_content' and `parsed_json_value' [sept/2014]."
do do
if is_valid_start_symbol then parse_content
Result := parse if is_parsed then
if extra_elements then Result := parsed_json_value
is_parsed := False
end
else
is_parsed := False
report_error ("Syntax error unexpected token, expecting `{' or `['")
end end
end end
parse: detachable JSON_VALUE parse: detachable JSON_VALUE
-- Parse JSON data `representation' -- Next JSON value from current position on `representation'.
obsolete
"Use restricted `next_parsed_json_value' [sept/2014]."
do
Result := next_parsed_json_value
end
feature {JSON_PARSER_ACCESS} -- Obsolete commands: restricted area
next_parsed_json_value: detachable JSON_VALUE
-- Return next json value from current position.
--| this does not call `reset_reader'.
do
reset
Result := next_json_value
end
feature {NONE} -- Implementation: parsing
next_json_value: detachable JSON_VALUE
-- Next JSON value from current position on `representation'.
local local
c: CHARACTER c: CHARACTER
do do
if is_parsed then if not has_error then
skip_white_spaces skip_white_spaces
c := actual c := actual
inspect c inspect c
when j_OBJECT_OPEN then when token_object_open then
Result := parse_object Result := parse_object
when j_STRING then when token_double_quote then
Result := parse_string Result := parse_string
when j_ARRAY_OPEN then when token_array_open then
Result := parse_array Result := parse_array
else else
if c.is_digit or c = j_MINUS then if c.is_digit or c = token_minus then
Result := parse_number Result := parse_number
elseif is_null then elseif is_null then
Result := create {JSON_NULL} Result := create {JSON_NULL}
@@ -101,25 +210,24 @@ feature -- Commands
next next
next next
elseif is_true then elseif is_true then
Result := create {JSON_BOOLEAN}.make_boolean (True) Result := create {JSON_BOOLEAN}.make_true
next next
next next
next next
elseif is_false then elseif is_false then
Result := create {JSON_BOOLEAN}.make_boolean (False) Result := create {JSON_BOOLEAN}.make_false
next next
next next
next next
next next
else else
is_parsed := False
report_error ("JSON is not well formed in parse") report_error ("JSON is not well formed in parse")
Result := Void Result := Void
end end
end end
end end
ensure ensure
is_parsed_implies_result_not_void: is_parsed implies Result /= Void is_parsed_implies_result_not_void: not has_error implies Result /= Void
end end
parse_object: JSON_OBJECT parse_object: JSON_OBJECT
@@ -132,13 +240,13 @@ feature -- Commands
l_value: detachable JSON_VALUE l_value: detachable JSON_VALUE
do do
create Result.make create Result.make
-- check if is an empty object {} --| check if is an empty object {}
next next
skip_white_spaces skip_white_spaces
if actual = j_OBJECT_CLOSE then if actual = token_object_close then
--is an empty object --| is an empty object
else else
-- a complex object {"key" : "value"} --| a complex object {"key" : "value"}
previous previous
from from
has_more := True has_more := True
@@ -150,24 +258,22 @@ feature -- Commands
l_json_string := parse_string l_json_string := parse_string
next next
skip_white_spaces skip_white_spaces
if actual = ':' then if actual = token_colon then --| token_colon = ':'
next next
skip_white_spaces skip_white_spaces
else else
is_parsed := False
report_error ("%N Input string is a not well formed JSON, expected: : found: " + actual.out) report_error ("%N Input string is a not well formed JSON, expected: : found: " + actual.out)
has_more := False has_more := False
end end
l_value := parse l_value := next_json_value
if is_parsed and then (l_value /= Void and l_json_string /= Void) then if not has_error and then (l_value /= Void and l_json_string /= Void) then
Result.put (l_value, l_json_string) Result.put (l_value, l_json_string)
next next
skip_white_spaces skip_white_spaces
if actual = j_OBJECT_CLOSE then if actual = token_object_close then
has_more := False has_more := False
elseif actual /= ',' then elseif actual /= token_comma then
has_more := False has_more := False
is_parsed := False
report_error ("JSON Object syntactically malformed expected , found: [" + actual.out + "]") report_error ("JSON Object syntactically malformed expected , found: [" + actual.out + "]")
end end
else else
@@ -187,7 +293,7 @@ feature -- Commands
c: like actual c: like actual
do do
create l_json_string.make_empty create l_json_string.make_empty
if actual = j_STRING then if actual = token_double_quote then
from from
has_more := True has_more := True
until until
@@ -195,9 +301,9 @@ feature -- Commands
loop loop
next next
c := actual c := actual
if c = j_STRING then if c = token_double_quote then
has_more := False has_more := False
elseif c = '%H' then elseif c = '%H' then -- '%H' = '\' = reverse solidus
next next
c := actual c := actual
if c = 'u' then if c = 'u' then
@@ -208,12 +314,10 @@ feature -- Commands
l_json_string.append (l_unicode) l_json_string.append (l_unicode)
else else
has_more := False has_more := False
is_parsed := False
report_error ("Input String is not well formed JSON, expected a Unicode value, found [" + c.out + " ]") report_error ("Input String is not well formed JSON, expected a Unicode value, found [" + c.out + " ]")
end end
elseif (not is_special_character (c) and not is_special_control (c)) or c = '%N' then elseif (not is_special_character (c) and not is_special_control (c)) or c = '%N' then
has_more := False has_more := False
is_parsed := False
report_error ("Input String is not well formed JSON, found [" + c.out + " ]") report_error ("Input String is not well formed JSON, found [" + c.out + " ]")
else else
l_json_string.append_character ('\') l_json_string.append_character ('\')
@@ -222,14 +326,13 @@ feature -- Commands
else else
if is_special_character (c) and c /= '/' then if is_special_character (c) and c /= '/' then
has_more := False has_more := False
is_parsed := False
report_error ("Input String is not well formed JSON, found [" + c.out + " ]") report_error ("Input String is not well formed JSON, found [" + c.out + " ]")
else else
l_json_string.append_character (c) l_json_string.append_character (c)
end end
end end
end end
create Result.make_with_escaped_json (l_json_string) create Result.make_from_escaped_json_string (l_json_string)
else else
Result := Void Result := Void
end end
@@ -244,11 +347,11 @@ feature -- Commands
l_value: detachable JSON_VALUE l_value: detachable JSON_VALUE
c: like actual c: like actual
do do
create Result.make_array create Result.make_empty
-- check if is an empty array [] -- check if is an empty array []
next next
skip_white_spaces skip_white_spaces
if actual = j_array_close then if actual = token_array_close then
-- is an empty array -- is an empty array
else else
previous previous
@@ -259,17 +362,16 @@ feature -- Commands
loop loop
next next
skip_white_spaces skip_white_spaces
l_value := parse l_value := next_json_value
if is_parsed and then l_value /= Void then if not has_error and then l_value /= Void then
Result.add (l_value) Result.add (l_value)
next next
skip_white_spaces skip_white_spaces
c := actual c := actual
if c = j_ARRAY_CLOSE then if c = token_array_close then
flag := False flag := False
elseif c /= ',' then elseif c /= token_comma then
flag := False flag := False
is_parsed := False
report_error ("Array is not well formed JSON, found [" + c.out + " ]") report_error ("Array is not well formed JSON, found [" + c.out + " ]")
end end
else else
@@ -297,7 +399,7 @@ feature -- Commands
loop loop
next next
c := actual c := actual
if not has_next or is_close_token (c) or c = ',' or c = '%N' or c = '%R' then if not has_next or is_close_token (c) or c = token_comma or c = '%N' or c = '%R' then
flag := False flag := False
previous previous
else else
@@ -312,7 +414,6 @@ feature -- Commands
create Result.make_real (sb.to_double) create Result.make_real (sb.to_double)
end end
else else
is_parsed := False
report_error ("Expected a number, found: [ " + sb + " ]") report_error ("Expected a number, found: [ " + sb + " ]")
end end
end end
@@ -357,7 +458,7 @@ feature -- Commands
end end
read_unicode: STRING read_unicode: STRING
-- Read Unicode and return value -- Read unicode and return value.
local local
i: INTEGER i: INTEGER
do do
@@ -392,30 +493,30 @@ feature {NONE} -- Implementation
i := 1 i := 1
--| "-?" --| "-?"
c := a_number [i] c := a_number [i]
if c = '-' then if c = token_minus then
s.extend (c); s.extend (c)
i := i + 1; i := i + 1
c := a_number [i] c := a_number [i]
end end
--| "0|[1-9]\d* --| "0|[1-9]\d*
if c.is_digit then if c.is_digit then
if c = '0' then if c = '0' then
--| "0" --| "0"
s.extend (c); s.extend (c)
i := i + 1; i := i + 1
c := a_number [i] c := a_number [i]
else else
--| "[1-9]" --| "[1-9]"
s.extend (c); s.extend (c)
i := i + 1; i := i + 1
c := a_number [i] c := a_number [i]
--| "\d*" --| "\d*"
from from
until until
i > n or not c.is_digit i > n or not c.is_digit
loop loop
s.extend (c); s.extend (c)
i := i + 1; i := i + 1
c := a_number [i] c := a_number [i]
end end
end end
@@ -423,18 +524,18 @@ feature {NONE} -- Implementation
end end
if Result then if Result then
--| "(\.\d+)?" --| "(\.\d+)?"
if c = '.' then if c = token_dot then
--| "\.\d+" = "\.\d\d*" --| "\.\d+" = "\.\d\d*"
s.extend (c); s.extend (c)
i := i + 1; i := i + 1
c := a_number [i] c := a_number [i]
if c.is_digit then if c.is_digit then
from from
until until
i > n or not c.is_digit i > n or not c.is_digit
loop loop
s.extend (c); s.extend (c)
i := i + 1; i := i + 1
c := a_number [i] c := a_number [i]
end end
else else
@@ -443,14 +544,14 @@ feature {NONE} -- Implementation
end end
end end
if Result then --| "(?:[eE][+-]?\d+)?\b" if Result then --| "(?:[eE][+-]?\d+)?\b"
if c = 'e' or c = 'E' then if is_exp_token (c) then
--| "[eE][+-]?\d+" --| "[eE][+-]?\d+"
s.extend (c); s.extend (c)
i := i + 1; i := i + 1
c := a_number [i] c := a_number [i]
if c = '+' or c = '-' then if c = token_plus or c = token_minus then
s.extend (c); s.extend (c)
i := i + 1; i := i + 1
c := a_number [i] c := a_number [i]
end end
if c.is_digit then if c.is_digit then
@@ -458,8 +559,8 @@ feature {NONE} -- Implementation
until until
i > n or not c.is_digit i > n or not c.is_digit
loop loop
s.extend (c); s.extend (c)
i := i + 1; i := i + 1
c := a_number [i] c := a_number [i]
end end
else else
@@ -472,8 +573,8 @@ feature {NONE} -- Implementation
until until
i > n or not c.is_space i > n or not c.is_space
loop loop
s.extend (c); s.extend (c)
i := i + 1; i := i + 1
c := a_number [i] c := a_number [i]
end end
Result := i > n and then s.same_string (a_number) Result := i > n and then s.same_string (a_number)
@@ -481,8 +582,7 @@ feature {NONE} -- Implementation
end end
is_valid_unicode (a_unicode: STRING): BOOLEAN is_valid_unicode (a_unicode: STRING): BOOLEAN
-- is 'a_unicode' a valid Unicode based on this regular expression -- is 'a_unicode' a valid unicode based on the regular expression "\\u[0-9a-fA-F]{4}" .
-- "\\u[0-9a-fA-F]{4}"
local local
i: INTEGER i: INTEGER
do do
@@ -525,7 +625,7 @@ feature {NONE} -- Implementation
-- expecting `{' or `[' as start symbol -- expecting `{' or `[' as start symbol
do do
if attached representation as s and then s.count > 0 then if attached representation as s and then s.count > 0 then
Result := s [1] = '{' or s [1] = '[' Result := s [1] = token_object_open or s [1] = token_array_open
end end
end end

View File

@@ -0,0 +1,9 @@
note
description: "Inherit to access restricted feature from {JSON_PARSER}."
date: "$Date$"
revision: "$Revision$"
deferred class
JSON_PARSER_ACCESS
end

View File

@@ -20,13 +20,19 @@ feature {NONE} -- Initialization
feature -- Commands feature -- Commands
reset
-- Reset reader
do
index := 1
end
set_representation (a_json: STRING) set_representation (a_json: STRING)
-- Set `representation'. -- Set `representation'.
do do
a_json.left_adjust a_json.left_adjust
a_json.right_adjust a_json.right_adjust
representation := a_json representation := a_json
index := 1 reset
end end
read: CHARACTER read: CHARACTER

View File

@@ -0,0 +1,87 @@
note
description: "Token used by the JSON_PARSER"
author: "$Author$"
date: "$Date$"
revision: "$Revision$"
class
JSON_TOKENS
feature -- Access
token_object_open: CHARACTER = '{'
token_object_close: CHARACTER = '}'
token_array_open: CHARACTER = '['
token_array_close: CHARACTER = ']'
token_double_quote: CHARACTER = '"'
token_plus: CHARACTER = '+'
token_minus: CHARACTER = '-'
token_dot: CHARACTER = '.'
token_exp: CHARACTER = 'e'
token_comma: CHARACTER = ','
token_colon: CHARACTER = ':'
feature -- Status report
is_open_token (c: CHARACTER): BOOLEAN
-- Characters which open a type
do
inspect c
when token_object_open, token_array_open, token_double_quote, token_plus, token_minus, token_dot then
Result := True
else
end
end
is_close_token (c: CHARACTER): BOOLEAN
-- Characters which close a type
do
inspect c
when token_object_close, token_array_close, token_double_quote then
Result := True
else
end
end
is_special_character (c: CHARACTER): BOOLEAN
-- Control Characters
-- %F Form feed
-- %H backslasH
-- %N Newline
-- %R carriage Return
-- %T horizontal Tab
-- %B Backspace
-- / Solidus
-- " Quotation
do
inspect c
when '"', '%H' , '/', '%B', '%F', '%N', '%R', '%T' then -- '%H' = '\' = reverse solidus
Result := True
else
end
end
is_special_control (c: CHARACTER): BOOLEAN
-- Control Characters
-- \b\f\n\r\t
do
inspect c
when 'b', 'f', 'n', 'r', 't' then
Result := True
else
end
end
is_exp_token (c: CHARACTER): BOOLEAN
-- Is number exposant token?
do
Result := c = token_exp or else c.as_lower = token_exp
end
end

View File

@@ -0,0 +1,46 @@
note
description: "Objects that ..."
author: ""
date: "$Date$"
revision: "$Revision$"
class
JSON_FILE_READER
feature -- Access
read_json_from (a_path: READABLE_STRING_GENERAL): detachable STRING
local
l_file: PLAIN_TEXT_FILE
l_last_string: detachable STRING
l_file_count: INTEGER
l_fetch_done: BOOLEAN
do
create l_file.make_with_name (a_path)
-- We perform several checks until we make a real attempt to open the file.
if not l_file.exists then
print ("error: '" + a_path.out + "' does not exist%N") -- FIXME: unicode may be truncated
else
if not l_file.is_readable then
print ("error: '" + a_path.out + "' is not readable.%N") -- FIXME: unicode may be truncated
else
l_file_count := l_file.count
l_file.open_read
from
create Result.make (l_file_count)
until
l_fetch_done
loop
l_file.read_stream (1_024)
l_last_string := l_file.last_string
l_fetch_done := l_file.exhausted or l_file.end_of_file or l_last_string.count < 1_024
if not l_last_string.is_empty then
Result.append (l_last_string)
end
end
l_file.close
end
end
end
end

View File

@@ -48,7 +48,7 @@ feature {NONE} -- Implementation
name_key: JSON_STRING name_key: JSON_STRING
-- Author's name label. -- Author's name label.
once once
create Result.make_json ("name") create Result.make_from_string ("name")
end end
end -- class JSON_AUTHOR_CONVERTER end -- class JSON_AUTHOR_CONVERTER

View File

@@ -60,7 +60,7 @@ feature -- Conversion
to_json (o: like object): JSON_OBJECT to_json (o: like object): JSON_OBJECT
do do
create Result.make create Result.make_with_capacity (2)
Result.put (json.value (o.name), name_key) Result.put (json.value (o.name), name_key)
Result.put (json.value (o.books), books_key) Result.put (json.value (o.books), books_key)
end end
@@ -70,13 +70,13 @@ feature {NONE} -- Implementation
name_key: JSON_STRING name_key: JSON_STRING
-- Collection's name label. -- Collection's name label.
once once
create Result.make_json ("name") create Result.make_from_string ("name")
end end
books_key: JSON_STRING books_key: JSON_STRING
-- Book list label. -- Book list label.
once once
create Result.make_json ("books") create Result.make_from_string ("books")
end end
end -- class JSON_BOOK_COLLECTION_CONVERTER end -- class JSON_BOOK_COLLECTION_CONVERTER

View File

@@ -45,7 +45,7 @@ feature -- Conversion
to_json (o: like object): JSON_OBJECT to_json (o: like object): JSON_OBJECT
do do
create Result.make create Result.make_with_capacity (3)
Result.put (json.value (o.title), title_key) Result.put (json.value (o.title), title_key)
Result.put (json.value (o.isbn), isbn_key) Result.put (json.value (o.isbn), isbn_key)
Result.put (json.value (o.author), author_key) Result.put (json.value (o.author), author_key)
@@ -56,19 +56,19 @@ feature {NONE} -- Implementation
title_key: JSON_STRING title_key: JSON_STRING
-- Book's title label. -- Book's title label.
once once
create Result.make_json ("title") create Result.make_from_string ("title")
end end
isbn_key: JSON_STRING isbn_key: JSON_STRING
-- Book ISBN label. -- Book ISBN label.
once once
create Result.make_json ("isbn") create Result.make_from_string ("isbn")
end end
author_key: JSON_STRING author_key: JSON_STRING
-- Author label. -- Author label.
once once
create Result.make_json ("author") create Result.make_from_string ("author")
end end
end -- class JSON_BOOK_CONVERTER end -- class JSON_BOOK_CONVERTER

View File

@@ -51,13 +51,13 @@ feature -- Test
if attached {HASH_TABLE [ANY, HASHABLE]} json.object (l_value, "HASH_TABLE") as t2 then if attached {HASH_TABLE [ANY, HASHABLE]} json.object (l_value, "HASH_TABLE") as t2 then
create l_ucs_key.make_from_string ("1") create l_ucs_key.make_from_string ("1")
if attached {STRING_32} t2 [l_ucs_key] as l_ucs_value then if attached {STRING_32} t2 [l_ucs_key] as l_ucs_value then
assert ("ucs_value.string.is_equal (%"foo%")", l_ucs_value.string.is_equal ("foo")) assert ("ucs_value.string.is_equal (%"foo%")", l_ucs_value.same_string_general ("foo"))
else else
assert ("ucs_value /= Void", False) assert ("ucs_value /= Void", False)
end end
create l_ucs_key.make_from_string ("2") create l_ucs_key.make_from_string ("2")
if attached {STRING_32} t2 [l_ucs_key] as l_ucs_value then if attached {STRING_32} t2 [l_ucs_key] as l_ucs_value then
assert ("ucs_value.string.is_equal (%"bar%")", l_ucs_value.string.is_equal ("bar")) assert ("ucs_value.string.is_equal (%"bar%")", l_ucs_value.same_string_general ("bar"))
else else
assert ("ucs_value /= Void", False) assert ("ucs_value /= Void", False)
end end

View File

@@ -10,6 +10,11 @@ inherit
EQA_TEST_SET EQA_TEST_SET
JSON_PARSER_ACCESS
undefine
default_create
end
feature -- Test feature -- Test
test_json_number_and_integer test_json_number_and_integer
@@ -35,15 +40,15 @@ feature -- Test
-- that can represent the value of the JSON number, in this case -- that can represent the value of the JSON number, in this case
-- we know it is INTEGER_8 since the value is 42 -- we know it is INTEGER_8 since the value is 42
jrep := "42" jrep := "42"
create parser.make_parser (jrep) create parser.make_with_string (jrep)
if attached {JSON_NUMBER} parser.parse as l_jn then if attached {JSON_NUMBER} parser.next_parsed_json_value as l_jn then
if attached {INTEGER_8} json.object (jn, Void) as l_i8 then if attached {INTEGER_8} json.object (jn, Void) as l_i8 then
assert ("l_i8 = 42", l_i8 = 42) assert ("l_i8 = 42", l_i8 = 42)
else else
assert ("json.object (jn, Void) is a INTEGER_8", False) assert ("json.object (jn, Void) is a INTEGER_8", False)
end end
else else
assert ("parser.parse is a JSON_NUMBER", False) assert ("parser.next_parsed_json_value is a JSON_NUMBER", False)
end end
end end
@@ -70,15 +75,15 @@ feature -- Test
-- that can represent the value of the JSON number, in this case -- that can represent the value of the JSON number, in this case
-- we know it is INTEGER_8 since the value is 42 -- we know it is INTEGER_8 since the value is 42
jrep := "42" jrep := "42"
create parser.make_parser (jrep) create parser.make_with_string (jrep)
if attached {JSON_NUMBER} parser.parse as l_jn then if attached {JSON_NUMBER} parser.next_parsed_json_value as l_jn then
if attached {INTEGER_8} json.object (jn, Void) as l_i8 then if attached {INTEGER_8} json.object (jn, Void) as l_i8 then
assert ("l_i8 = 42", l_i8 = 42) assert ("l_i8 = 42", l_i8 = 42)
else else
assert ("json.object (jn, Void) is a INTEGER_8", False) assert ("json.object (jn, Void) is a INTEGER_8", False)
end end
else else
assert ("parser.parse is a JSON_NUMBER", False) assert ("parser.next_parsed_json_value is a JSON_NUMBER", False)
end end
end end
@@ -105,15 +110,15 @@ feature -- Test
-- that can represent the value of the JSON number, in this case -- that can represent the value of the JSON number, in this case
-- we know it is INTEGER_16 since the value is 300 -- we know it is INTEGER_16 since the value is 300
jrep := "300" jrep := "300"
create parser.make_parser (jrep) create parser.make_with_string (jrep)
if attached {JSON_NUMBER} parser.parse as l_jn then if attached {JSON_NUMBER} parser.next_parsed_json_value as l_jn then
if attached {INTEGER_16} json.object (jn, Void) as l_i16 then if attached {INTEGER_16} json.object (jn, Void) as l_i16 then
assert ("l_i16 = 300", l_i16 = 300) assert ("l_i16 = 300", l_i16 = 300)
else else
assert ("json.object (jn, Void) is a INTEGER_16", False) assert ("json.object (jn, Void) is a INTEGER_16", False)
end end
else else
assert ("parser.parse is a JSON_NUMBER", False) assert ("parser.next_parsed_json_value is a JSON_NUMBER", False)
end end
end end
@@ -140,15 +145,15 @@ feature -- Test
-- that can represent the value of the JSON number, in this case -- that can represent the value of the JSON number, in this case
-- we know it is INTEGER_32 since the value is 100000 -- we know it is INTEGER_32 since the value is 100000
jrep := "100000" jrep := "100000"
create parser.make_parser (jrep) create parser.make_with_string (jrep)
if attached {JSON_NUMBER} parser.parse as l_jn then if attached {JSON_NUMBER} parser.next_parsed_json_value as l_jn then
if attached {INTEGER_32} json.object (jn, Void) as l_i32 then if attached {INTEGER_32} json.object (jn, Void) as l_i32 then
assert ("l_i32 = 100000", l_i32 = 100000) assert ("l_i32 = 100000", l_i32 = 100000)
else else
assert ("json.object (jn, Void) is a INTEGER_32", False) assert ("json.object (jn, Void) is a INTEGER_32", False)
end end
else else
assert ("parser.parse is a JSON_NUMBER", False) assert ("parser.next_parsed_json_value is a JSON_NUMBER", False)
end end
end end
@@ -175,15 +180,15 @@ feature -- Test
-- that can represent the value of the JSON number, in this case -- that can represent the value of the JSON number, in this case
-- we know it is INTEGER_32 since the value is 42949672960 -- we know it is INTEGER_32 since the value is 42949672960
jrep := "42949672960" jrep := "42949672960"
create parser.make_parser (jrep) create parser.make_with_string (jrep)
if attached {JSON_NUMBER} parser.parse as l_jn then if attached {JSON_NUMBER} parser.next_parsed_json_value as l_jn then
if attached {INTEGER_64} json.object (jn, Void) as l_i64 then if attached {INTEGER_64} json.object (jn, Void) as l_i64 then
assert ("l_i64 = 42949672960", l_i64 = 42949672960) assert ("l_i64 = 42949672960", l_i64 = 42949672960)
else else
assert ("json.object (jn, Void) is a INTEGER_64", False) assert ("json.object (jn, Void) is a INTEGER_64", False)
end end
else else
assert ("parser.parse is a JSON_NUMBER", False) assert ("parser.next_parsed_json_value is a JSON_NUMBER", False)
end end
end end
@@ -210,15 +215,15 @@ feature -- Test
-- that can represent the value of the JSON number, in this case -- that can represent the value of the JSON number, in this case
-- we know it is INTEGER_16 since the value is 200 -- we know it is INTEGER_16 since the value is 200
jrep := "200" jrep := "200"
create parser.make_parser (jrep) create parser.make_with_string (jrep)
if attached {JSON_NUMBER} parser.parse as l_jn then if attached {JSON_NUMBER} parser.next_parsed_json_value as l_jn then
if attached {INTEGER_16} json.object (jn, Void) as i16 then if attached {INTEGER_16} json.object (jn, Void) as i16 then
assert ("i16 = 200", i16 = 200) assert ("i16 = 200", i16 = 200)
else else
assert ("json.object (jn, Void) is an INTEGER_16", False) assert ("json.object (jn, Void) is an INTEGER_16", False)
end end
else else
assert ("parser.parse is a JSON_NUMBER", False) assert ("parser.next_parsed_json_value is a JSON_NUMBER", False)
end end
end end
@@ -245,15 +250,15 @@ feature -- Test
-- that can represent the value of the JSON number, in this case -- that can represent the value of the JSON number, in this case
-- we know it is INTEGER_32 since the value is 32768 -- we know it is INTEGER_32 since the value is 32768
jrep := "32768" jrep := "32768"
create parser.make_parser (jrep) create parser.make_with_string (jrep)
if attached {JSON_NUMBER} parser.parse as l_jn then if attached {JSON_NUMBER} parser.next_parsed_json_value as l_jn then
if attached {INTEGER_32} json.object (jn, Void) as i32 then if attached {INTEGER_32} json.object (jn, Void) as i32 then
assert ("i32 = 32768", i32 = 32768) assert ("i32 = 32768", i32 = 32768)
else else
assert ("json.object (jn, Void) is a INTEGER_32", False) assert ("json.object (jn, Void) is a INTEGER_32", False)
end end
else else
assert ("parser.parse is a JSON_NUMBER", False) assert ("parser.next_parsed_json_value is a JSON_NUMBER", False)
end end
end end
@@ -280,15 +285,15 @@ feature -- Test
-- that can represent the value of the JSON number, in this case -- that can represent the value of the JSON number, in this case
-- we know it is INTEGER_64 since the value is 2147483648 -- we know it is INTEGER_64 since the value is 2147483648
jrep := "2147483648" jrep := "2147483648"
create parser.make_parser (jrep) create parser.make_with_string (jrep)
if attached {JSON_NUMBER} parser.parse as l_jn then if attached {JSON_NUMBER} parser.next_parsed_json_value as l_jn then
if attached {INTEGER_64} json.object (jn, Void) as i64 then if attached {INTEGER_64} json.object (jn, Void) as i64 then
assert ("i64 = 2147483648", i64 = 2147483648) assert ("i64 = 2147483648", i64 = 2147483648)
else else
assert ("json.object (jn, Void) is a INTEGER_64", False) assert ("json.object (jn, Void) is a INTEGER_64", False)
end end
else else
assert ("parser.parse is a JSON_NUMBER", False) assert ("parser.next_parsed_json_value is a JSON_NUMBER", False)
end end
end end
@@ -315,15 +320,15 @@ feature -- Test
-- that can represent the value of the JSON number, in this case -- that can represent the value of the JSON number, in this case
-- we know it is INTEGER_32 since the value is 42949672960 -- we know it is INTEGER_32 since the value is 42949672960
jrep := "9223372036854775808" -- 1 higher than largest positive number that can be represented by INTEGER 64 jrep := "9223372036854775808" -- 1 higher than largest positive number that can be represented by INTEGER 64
create parser.make_parser (jrep) create parser.make_with_string (jrep)
if attached {JSON_NUMBER} parser.parse as l_jn then if attached {JSON_NUMBER} parser.next_parsed_json_value as l_jn then
if attached {NATURAL_64} json.object (jn, Void) as l_n64 then if attached {NATURAL_64} json.object (jn, Void) as l_n64 then
assert ("l_n64 = 9223372036854775808", l_n64 = 9223372036854775808) assert ("l_n64 = 9223372036854775808", l_n64 = 9223372036854775808)
else else
assert ("json.object (jn, Void) is a NATURAL_64", False) assert ("json.object (jn, Void) is a NATURAL_64", False)
end end
else else
assert ("parser.parse is a JSON_NUMBER", False) assert ("parser.next_parsed_json_value is a JSON_NUMBER", False)
end end
end end
@@ -349,15 +354,15 @@ feature -- Test
-- Note: The JSON_FACTORY will always return a REAL_64 if the value -- Note: The JSON_FACTORY will always return a REAL_64 if the value
-- of the JSON number is a floating point number -- of the JSON number is a floating point number
jrep := "3.14" jrep := "3.14"
create parser.make_parser (jrep) create parser.make_with_string (jrep)
if attached {JSON_NUMBER} parser.parse as l_jn then if attached {JSON_NUMBER} parser.next_parsed_json_value as l_jn then
if attached {REAL_64} json.object (jn, Void) as r64 then if attached {REAL_64} json.object (jn, Void) as r64 then
assert ("3.14 <= r64 and r64 <= 3.141", 3.14 <= r64 and r64 <= 3.141) assert ("3.14 <= r64 and r64 <= 3.141", 3.14 <= r64 and r64 <= 3.141)
else else
assert ("json.object (jn, Void) is a REAL_64", False) assert ("json.object (jn, Void) is a REAL_64", False)
end end
else else
assert ("parser.parse is a JSON_NUMBER", False) assert ("parser.next_parsed_json_value is a JSON_NUMBER", False)
end end
end end
@@ -381,15 +386,15 @@ feature -- Test
-- JSON representation -> JSON value -> Eiffel value -- JSON representation -> JSON value -> Eiffel value
jrep := "3.1400001049041748" jrep := "3.1400001049041748"
create parser.make_parser (jrep) create parser.make_with_string (jrep)
if attached {JSON_NUMBER} parser.parse as l_jn then if attached {JSON_NUMBER} parser.next_parsed_json_value as l_jn then
if attached {REAL_64} json.object (l_jn, Void) as r64 then if attached {REAL_64} json.object (l_jn, Void) as r64 then
assert ("r64 = 3.1400001049041748", r64 = 3.1400001049041748) assert ("r64 = 3.1400001049041748", r64 = 3.1400001049041748)
else else
assert ("json.object (l_jn, Void) is a REAL_64", False) assert ("json.object (l_jn, Void) is a REAL_64", False)
end end
else else
assert ("parser.parse is a JSON_NUMBER", False) assert ("parser.next_parsed_json_value is a JSON_NUMBER", False)
end end
end end
@@ -414,15 +419,15 @@ feature -- Test
-- JSON representation -> JSON value -> Eiffel value -- JSON representation -> JSON value -> Eiffel value
jrep := "3.1415926535897931" jrep := "3.1415926535897931"
create parser.make_parser (jrep) create parser.make_with_string (jrep)
if attached {JSON_NUMBER} parser.parse as l_jn then if attached {JSON_NUMBER} parser.next_parsed_json_value as l_jn then
if attached {REAL_64} json.object (jn, Void) as l_r64 then if attached {REAL_64} json.object (jn, Void) as l_r64 then
assert ("l_r64 = 3.1415926535897931", l_r64 = 3.1415926535897931) assert ("l_r64 = 3.1415926535897931", l_r64 = 3.1415926535897931)
else else
assert ("json.object (jn, Void) is a REAL_64", False) assert ("json.object (jn, Void) is a REAL_64", False)
end end
else else
assert ("parser.parse is a JSON_NUMBER", False) assert ("parser.next_parsed_json_value is a JSON_NUMBER", False)
end end
end end
@@ -434,7 +439,7 @@ feature -- Test
do do
-- Eiffel value -> JSON value -> JSON representation -- Eiffel value -> JSON value -> JSON representation
b := True b := True
create jb.make_boolean (b) create jb.make (b)
assert ("jb.representation.is_equal (%"true%")", jb.representation.is_equal ("true")) assert ("jb.representation.is_equal (%"true%")", jb.representation.is_equal ("true"))
-- Eiffel value -> JSON value -> JSON representation with factory -- Eiffel value -> JSON value -> JSON representation with factory
if attached {JSON_BOOLEAN} json.value (b) as l_jb then if attached {JSON_BOOLEAN} json.value (b) as l_jb then
@@ -444,20 +449,20 @@ feature -- Test
end end
-- JSON representation -> JSON value -> Eiffel value -- JSON representation -> JSON value -> Eiffel value
create parser.make_parser ("true") create parser.make_with_string ("true")
if attached {JSON_BOOLEAN} parser.parse as l_jb then if attached {JSON_BOOLEAN} parser.next_parsed_json_value as l_jb then
if attached {BOOLEAN} json.object (l_jb, Void) as l_b then if attached {BOOLEAN} json.object (l_jb, Void) as l_b then
assert ("l_b = True", l_b = True) assert ("l_b = True", l_b = True)
else else
assert ("json.object (l_jb, Void) is BOOLEAN", False) assert ("json.object (l_jb, Void) is BOOLEAN", False)
end end
else else
assert ("parser.parse is a JSON_BOOLEAN", False) assert ("parser.next_parsed_json_value is a JSON_BOOLEAN", False)
end end
-- Eiffel value -> JSON value -> JSON representation -- Eiffel value -> JSON value -> JSON representation
b := False b := False
create jb.make_boolean (b) create jb.make (b)
assert ("jb.representation.same_string (%"false%")", jb.representation.same_string ("false")) assert ("jb.representation.same_string (%"false%")", jb.representation.same_string ("false"))
-- Eiffel value -> JSON value -> JSON representation with factory -- Eiffel value -> JSON value -> JSON representation with factory
if attached {JSON_BOOLEAN} json.value (b) as l_jb then if attached {JSON_BOOLEAN} json.value (b) as l_jb then
@@ -467,15 +472,15 @@ feature -- Test
end end
-- JSON representation -> JSON value -> Eiffel value -- JSON representation -> JSON value -> Eiffel value
create parser.make_parser ("false") create parser.make_with_string ("false")
if attached {JSON_BOOLEAN} parser.parse as l_jb then if attached {JSON_BOOLEAN} parser.next_parsed_json_value as l_jb then
if attached {BOOLEAN} json.object (l_jb, Void) as l_b then if attached {BOOLEAN} json.object (l_jb, Void) as l_b then
assert ("l_b = False", l_b = False) assert ("l_b = False", l_b = False)
else else
assert ("json.object (l_jb, Void) is a BOOLEAN", False) assert ("json.object (l_jb, Void) is a BOOLEAN", False)
end end
else else
assert ("parser.parse is a JSON_BOOLEAN", False) assert ("parser.next_parsed_json_value is a JSON_BOOLEAN", False)
end end
end end
@@ -497,11 +502,11 @@ feature -- Test
end end
-- JSON representation -> JSON value -> Eiffel value -- JSON representation -> JSON value -> Eiffel value
create parser.make_parser (jrep) create parser.make_with_string (jrep)
if attached parser.parse as l_json_null then if attached parser.next_parsed_json_value as l_json_null then
assert ("a = Void", json.object (l_json_null, Void) = Void) assert ("a = Void", json.object (l_json_null, Void) = Void)
else else
assert ("parser.parse /= Void", False) assert ("parser.next_parsed_json_value /= Void", False)
end end
end end
@@ -514,7 +519,7 @@ feature -- Test
do do
c := 'a' c := 'a'
-- Eiffel value -> JSON value -> JSON representation -- Eiffel value -> JSON value -> JSON representation
create js.make_json (c.out) create js.make_from_string (c.out)
assert ("js.representation.is_equal (%"%"a%"%")", js.representation.is_equal ("%"a%"")) assert ("js.representation.is_equal (%"%"a%"%")", js.representation.is_equal ("%"a%""))
-- Eiffel value -> JSON value -> JSON representation with factory -- Eiffel value -> JSON value -> JSON representation with factory
if attached {JSON_STRING} json.value (c) as l_json_str then if attached {JSON_STRING} json.value (c) as l_json_str then
@@ -525,13 +530,13 @@ feature -- Test
-- JSON representation -> JSON value -> Eiffel value -- JSON representation -> JSON value -> Eiffel value
jrep := "%"a%"" jrep := "%"a%""
create parser.make_parser (jrep) create parser.make_with_string (jrep)
if attached {JSON_STRING} parser.parse as l_json_str then if attached {JSON_STRING} parser.next_parsed_json_value as l_json_str then
if attached {STRING_32} json.object (l_json_str, Void) as ucs then if attached {STRING_32} json.object (l_json_str, Void) as ucs then
assert ("ucs.string.is_equal (%"a%")", ucs.string.is_equal ("a")) assert ("ucs.string.is_equal (%"a%")", ucs.string.is_equal ("a"))
end end
else else
assert ("parser.parse /= Void", False) assert ("parser.next_parsed_json_value /= Void", False)
end end
end end
@@ -546,7 +551,7 @@ feature -- Test
jrep := "%"foobar%"" jrep := "%"foobar%""
-- Eiffel value -> JSON value -> JSON representation -- Eiffel value -> JSON value -> JSON representation
create js.make_json (s) create js.make_from_string (s)
assert ("js.representation.is_equal (%"%"foobar%"%")", js.representation.is_equal (jrep)) assert ("js.representation.is_equal (%"%"foobar%"%")", js.representation.is_equal (jrep))
-- Eiffel value -> JSON value -> JSON representation with factory -- Eiffel value -> JSON value -> JSON representation with factory
if attached {JSON_STRING} json.value (s) as l_js then if attached {JSON_STRING} json.value (s) as l_js then
@@ -556,13 +561,13 @@ feature -- Test
end end
-- JSON representation -> JSON value -> Eiffel value -- JSON representation -> JSON value -> Eiffel value
create parser.make_parser (jrep) create parser.make_with_string (jrep)
if attached {JSON_STRING} parser.parse as l_js then if attached {JSON_STRING} parser.next_parsed_json_value as l_js then
if attached {STRING_32} json.object (l_js, Void) as l_ucs then if attached {STRING_32} json.object (l_js, Void) as l_ucs then
assert ("ucs.string.is_equal (%"foobar%")", l_ucs.string.is_equal (s)) assert ("ucs.string.is_equal (%"foobar%")", l_ucs.string.is_equal (s))
end end
else else
assert ("parser.parse /= Void", False) assert ("parser.next_parsed_json_value /= Void", False)
end end
end end
@@ -578,7 +583,7 @@ feature -- Test
create ucs.make_from_string (s) create ucs.make_from_string (s)
-- Eiffel value -> JSON value -> JSON representation -- Eiffel value -> JSON value -> JSON representation
create js.make_json (ucs) create js.make_from_string (ucs)
assert ("js.representation.is_equal (%"%"foobar%"%")", js.representation.is_equal (jrep)) assert ("js.representation.is_equal (%"%"foobar%"%")", js.representation.is_equal (jrep))
-- Eiffel value -> JSON value -> JSON representation with factory -- Eiffel value -> JSON value -> JSON representation with factory
@@ -589,15 +594,15 @@ feature -- Test
end end
-- JSON representation -> JSON value -> Eiffel value -- JSON representation -> JSON value -> Eiffel value
create parser.make_parser (jrep) create parser.make_with_string (jrep)
if attached {JSON_STRING} parser.parse as l_js then if attached {JSON_STRING} parser.next_parsed_json_value as l_js then
if attached {STRING_32} json.object (l_js, Void) as l_ucs then if attached {STRING_32} json.object (l_js, Void) as l_ucs then
assert ("ucs.string.is_equal (%"foobar%")", l_ucs.string.is_equal (s)) assert ("ucs.string.is_equal (%"foobar%")", l_ucs.string.is_equal (s))
else else
assert ("json.object (js, Void) /= Void", False) assert ("json.object (js, Void) /= Void", False)
end end
else else
assert ("parser.parse /= Void", False) assert ("parser.next_parsed_json_value /= Void", False)
end end
end end
@@ -610,7 +615,7 @@ feature -- Test
do do
jrep := "%"foo\\bar%"" jrep := "%"foo\\bar%""
create s.make_from_string ("foo\bar") create s.make_from_string ("foo\bar")
create js.make_json (s) create js.make_from_string (s)
assert ("js.representation.same_string (%"%"foo\\bar%"%")", js.representation.same_string (jrep)) assert ("js.representation.same_string (%"%"foo\\bar%"%")", js.representation.same_string (jrep))
-- Eiffel value -> JSON value -> JSON representation with factory -- Eiffel value -> JSON value -> JSON representation with factory
@@ -621,32 +626,84 @@ feature -- Test
end end
-- JSON representation -> JSON value -> Eiffel value -- JSON representation -> JSON value -> Eiffel value
create parser.make_parser (jrep) create parser.make_with_string (jrep)
if attached {JSON_STRING} parser.parse as l_js then if attached {JSON_STRING} parser.next_parsed_json_value as l_js then
if attached {STRING_32} json.object (l_js, Void) as l_ucs then if attached {STRING_32} json.object (l_js, Void) as l_ucs then
assert ("ucs.same_string (%"foo\bar%")", l_ucs.same_string ("foo\bar")) assert ("ucs.same_string (%"foo\bar%")", l_ucs.same_string ("foo\bar"))
end end
else else
assert ("parser.parse /= Void", False) assert ("parser.next_parsed_json_value /= Void", False)
end end
jrep := "%"foo\\bar%"" jrep := "%"foo\\bar%""
create parser.make_parser (jrep) create parser.make_with_string (jrep)
if attached {JSON_STRING} parser.parse as jstring then if attached {JSON_STRING} parser.next_parsed_json_value as jstring then
assert ("unescaped string %"foo\\bar%" to %"foo\bar%"", jstring.unescaped_string_8.same_string ("foo\bar")) assert ("unescaped string %"foo\\bar%" to %"foo\bar%"", jstring.unescaped_string_8.same_string ("foo\bar"))
else else
assert ("parser.parse /= Void", False) assert ("parser.next_parsed_json_value /= Void", False)
end end
create js.make_json_from_string_32 ({STRING_32} "你好") create js.make_from_string_32 ({STRING_32} "你好")
assert ("escaping unicode string32 %"%%/20320/%%/22909/%" %"\u4F60\u597D%"", js.item.same_string ("\u4F60\u597D")) assert ("escaping unicode string32 %"%%/20320/%%/22909/%" %"\u4F60\u597D%"", js.item.same_string ("\u4F60\u597D"))
jrep := "%"\u4F60\u597D%"" --| Ni hao jrep := "%"\u4F60\u597D%"" --| Ni hao
create parser.make_parser (jrep) create parser.make_with_string (jrep)
if attached {JSON_STRING} parser.parse as jstring then if attached {JSON_STRING} parser.next_parsed_json_value as jstring then
assert ("same unicode string32 %"%%/20320/%%/22909/%"", jstring.unescaped_string_32.same_string ({STRING_32} "你好")) assert ("same unicode string32 %"%%/20320/%%/22909/%"", jstring.unescaped_string_32.same_string ({STRING_32} "你好"))
else else
assert ("parser.parse /= Void", False) assert ("parser.next_parsed_json_value /= Void", False)
end end
end end
test_json_string_and_special_characters_2
local
js: detachable JSON_STRING
s,j: STRING
do
s := "foo%Tbar"
j := "foo\tbar"
create js.make_from_string (s)
assert ("string %"" + s + "%" to json %"" + j + "%"", js.item.same_string (j))
create js.make_from_escaped_json_string (js.item)
assert ("json %"" + j + "%" to string %"" + s + "%"", js.unescaped_string_8.same_string (s))
s := "tab=%T cr=%R newline=%N backslash=%H slash=/ end"
j := "tab=\t cr=\r newline=\n backslash=\\ slash=/ end"
create js.make_from_string (s)
assert ("string %"" + s + "%" to json %"" + j + "%"", js.item.same_string (j))
create js.make_from_escaped_json_string (js.item)
assert ("json %"" + j + "%" to string %"" + s + "%"", js.unescaped_string_8.same_string (s))
s := "<script>tab=%T cr=%R newline=%N backslash=%H slash=/ end</script>"
j := "<script>tab=\t cr=\r newline=\n backslash=\\ slash=/ end<\/script>"
create js.make_from_string (s)
assert ("string %"" + s + "%" to json %"" + j + "%"", js.item.same_string (j))
create js.make_from_escaped_json_string (js.item)
assert ("json %"" + j + "%" to string %"" + s + "%"", js.unescaped_string_8.same_string (s))
create js.make_from_escaped_json_string ("tab=\t")
assert ("js.item.same_string (%"tab=\t%")", js.item.same_string ("tab=\t"))
create js.make_from_escaped_json_string (js.item)
assert ("js.item.same_string (%"tab=\t%")", js.item.same_string ("tab=\t"))
-- <\/script>
create js.make_from_escaped_json_string ("<script>tab=\t<\/script>")
assert ("js.item.same_string (%"<script>tab=\t<\/script>%")", js.item.same_string ("<script>tab=\t<\/script>"))
assert ("js.unescaped_string_8.same_string (%"<script>tab=%%T</script>%")", js.unescaped_string_8.same_string ("<script>tab=%T</script>"))
create js.make_from_escaped_json_string (js.item)
assert ("js.item.same_string (%"<script>tab=\t<\/script>%")", js.item.same_string ("<script>tab=\t<\/script>"))
assert ("js.unescaped_string_8.same_string (%"<script>tab=%%T</script>%")", js.unescaped_string_8.same_string ("<script>tab=%T</script>"))
-- </script>
create js.make_from_escaped_json_string ("<script>tab=\t</script>")
assert ("js.item.same_string (%"<script>tab=\t</script>%")", js.item.same_string ("<script>tab=\t</script>"))
assert ("js.unescaped_string_8.same_string (%"<script>tab=%%T</script>%")", js.unescaped_string_8.same_string ("<script>tab=%T</script>"))
create js.make_from_escaped_json_string (js.item)
assert ("js.item.same_string (%"<script>tab=\t<\/script>%")", js.item.same_string ("<script>tab=\t</script>"))
assert ("js.unescaped_string_8.same_string (%"<script>tab=%%T</script>%")", js.unescaped_string_8.same_string ("<script>tab=%T</script>"))
end
test_json_array test_json_array
local local
ll: LINKED_LIST [INTEGER_8] ll: LINKED_LIST [INTEGER_8]
@@ -665,7 +722,7 @@ feature -- Test
ll.extend (5) ll.extend (5)
-- Note: Currently there is no simple way of creating a JSON_ARRAY -- Note: Currently there is no simple way of creating a JSON_ARRAY
-- from an LINKED_LIST. -- from an LINKED_LIST.
create ja.make_array create ja.make (ll.count)
from from
ll.start ll.start
until until
@@ -690,15 +747,15 @@ feature -- Test
-- it means we will get an LINKED_LIST [ANY] containing the INTEGER_8 -- it means we will get an LINKED_LIST [ANY] containing the INTEGER_8
-- values 0, 1, 1, 2, 3, 5 -- values 0, 1, 1, 2, 3, 5
jrep := "[0,1,1,2,3,5]" jrep := "[0,1,1,2,3,5]"
create parser.make_parser (jrep) create parser.make_with_string (jrep)
if attached {JSON_ARRAY} parser.parse as l_ja then if attached {JSON_ARRAY} parser.next_parsed_json_value as l_ja then
if attached {LINKED_LIST [detachable ANY]} json.object (ja, Void) as l_ll2 then if attached {LINKED_LIST [detachable ANY]} json.object (ja, Void) as l_ll2 then
assert ("ll2.is_equal (ll)", l_ll2.is_equal (ll)) assert ("ll2.is_equal (ll)", l_ll2.is_equal (ll))
else else
assert ("json.object (ja, Void) /= Void", False) assert ("json.object (ja, Void) /= Void", False)
end end
else else
assert ("parser.parse /= Void", False) assert ("parser.next_parsed_json_value /= Void", False)
end end
end end
@@ -720,14 +777,14 @@ feature -- Test
-- a HASH_TABLE, so we do it manually. -- a HASH_TABLE, so we do it manually.
-- t = {"name": "foobar", "size": 42, "contents", [0, 1, 1, 2, 3, 5]} -- t = {"name": "foobar", "size": 42, "contents", [0, 1, 1, 2, 3, 5]}
create jo.make create jo.make
create js_key.make_json ("name") create js_key.make_from_string ("name")
create js.make_json ("foobar") create js.make_from_string ("foobar")
jo.put (js, js_key) jo.put (js, js_key)
create js_key.make_json ("size") create js_key.make_from_string ("size")
create jn.make_integer (42) create jn.make_integer (42)
jo.put (jn, js_key) jo.put (jn, js_key)
create js_key.make_json ("contents") create js_key.make_from_string ("contents")
create ja.make_array create ja.make (6)
create jn.make_integer (0) create jn.make_integer (0)
ja.add (jn) ja.add (jn)
create jn.make_integer (1) create jn.make_integer (1)
@@ -763,8 +820,8 @@ feature -- Test
-- JSON representation -> JSON value -> Eiffel value -> JSON value -> JSON representation -- JSON representation -> JSON value -> Eiffel value -> JSON value -> JSON representation
jrep := "{%"name%":%"foobar%",%"size%":42,%"contents%":[0,1,1,2,3,5]}" jrep := "{%"name%":%"foobar%",%"size%":42,%"contents%":[0,1,1,2,3,5]}"
create parser.make_parser (jrep) create parser.make_with_string (jrep)
if attached {JSON_OBJECT} parser.parse as l_jo then if attached {JSON_OBJECT} parser.next_parsed_json_value as l_jo then
if attached {HASH_TABLE [detachable ANY, STRING_GENERAL]} json.object (l_jo, Void) as l_t2 then if attached {HASH_TABLE [detachable ANY, STRING_GENERAL]} json.object (l_jo, Void) as l_t2 then
if attached json.value (l_t2) as l_jo_2 then if attached json.value (l_t2) as l_jo_2 then
assert ("jrep.is_equal (jo.representation)", jrep.is_equal (l_jo_2.representation)) assert ("jrep.is_equal (jo.representation)", jrep.is_equal (l_jo_2.representation))
@@ -775,7 +832,7 @@ feature -- Test
assert ("json.object (jo, Void) /= Void", False) assert ("json.object (jo, Void) /= Void", False)
end end
else else
assert ("parser.parse /= Void", jo /= Void) assert ("parser.next_parsed_json_value /= Void", jo /= Void)
end end
end end

View File

@@ -1,4 +1,4 @@
note note
description: "[ description: "[
Eiffel tests that can be executed by testing tool. Eiffel tests that can be executed by testing tool.
]" ]"
@@ -11,7 +11,6 @@ class
TEST_JSON_SUITE TEST_JSON_SUITE
inherit inherit
EQA_TEST_SET EQA_TEST_SET
redefine redefine
on_prepare on_prepare
@@ -34,8 +33,8 @@ feature -- Tests Pass
do do
if attached json_file_from ("pass1.json") as json_file then if attached json_file_from ("pass1.json") as json_file then
parse_json := new_json_parser (json_file) parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json parse_json.parse_content
assert ("pass1.json", parse_json.is_parsed = True) assert ("pass1.json", parse_json.is_valid)
end end
end end
@@ -46,8 +45,8 @@ feature -- Tests Pass
do do
if attached json_file_from ("pass2.json") as json_file then if attached json_file_from ("pass2.json") as json_file then
parse_json := new_json_parser (json_file) parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json parse_json.parse_content
assert ("pass2.json", parse_json.is_parsed = True) assert ("pass2.json",parse_json.is_valid)
end end
end end
@@ -58,8 +57,8 @@ feature -- Tests Pass
do do
if attached json_file_from ("pass3.json") as json_file then if attached json_file_from ("pass3.json") as json_file then
parse_json := new_json_parser (json_file) parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json parse_json.parse_content
assert ("pass3.json", parse_json.is_parsed = True) assert ("pass3.json",parse_json.is_valid)
end end
end end
@@ -69,19 +68,18 @@ feature -- Tests Pass
utf: UTF_CONVERTER utf: UTF_CONVERTER
s: READABLE_STRING_32 s: READABLE_STRING_32
do do
s := {STRING_32} "{ %"nihaoma%": %"你好吗\t?%" }" s := {STRING_32} "{ %"nihaoma%": %"你好吗\t?%" }"
parse_json := new_json_parser (utf.string_32_to_utf_8_string_8 (s)) parse_json := new_json_parser (utf.string_32_to_utf_8_string_8 (s))
json_value := parse_json.parse_json parse_json.parse_content
assert ("utf8.pass1.json", parse_json.is_parsed = True) assert ("utf8.pass1.json", parse_json.is_valid)
if attached {JSON_OBJECT} json_value as jo and then attached {JSON_STRING} jo.item ("nihaoma") as js then if attached {JSON_OBJECT} parse_json.parsed_json_value as jo and then attached {JSON_STRING} jo.item ("nihaoma") as js then
assert ("utf8.nihaoma", js.unescaped_string_32.same_string ({STRING_32} "你好吗%T?")) assert ("utf8.nihaoma", js.unescaped_string_32.same_string ({STRING_32} "你好吗%T?"))
else else
assert ("utf8.nihaoma", False) assert ("utf8.nihaoma", False)
end end
end end
feature -- Tests Failures feature -- Tests Failures
test_json_fail1 test_json_fail1
-- --
local local
@@ -89,8 +87,8 @@ feature -- Tests Failures
do do
if attached json_file_from ("fail1.json") as json_file then if attached json_file_from ("fail1.json") as json_file then
parse_json := new_json_parser (json_file) parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json parse_json.parse_content
assert ("fail1.json", parse_json.is_parsed = False) assert ("fail1.json", parse_json.is_valid = False)
end end
end end
@@ -101,8 +99,8 @@ feature -- Tests Failures
do do
if attached json_file_from ("fail2.json") as json_file then if attached json_file_from ("fail2.json") as json_file then
parse_json := new_json_parser (json_file) parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json parse_json.parse_content
assert ("fail2.json", parse_json.is_parsed = False) assert ("fail2.json",parse_json.is_valid = False)
end end
end end
@@ -113,8 +111,8 @@ feature -- Tests Failures
do do
if attached json_file_from ("fail3.json") as json_file then if attached json_file_from ("fail3.json") as json_file then
parse_json := new_json_parser (json_file) parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json parse_json.parse_content
assert ("fail3.json", parse_json.is_parsed = False) assert ("fail3.json",parse_json.is_valid = False)
end end
end end
@@ -125,8 +123,8 @@ feature -- Tests Failures
do do
if attached json_file_from ("fail4.json") as json_file then if attached json_file_from ("fail4.json") as json_file then
parse_json := new_json_parser (json_file) parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json parse_json.parse_content
assert ("fail4.json", parse_json.is_parsed = False) assert ("fail4.json",parse_json.is_valid = False)
end end
end end
@@ -137,11 +135,12 @@ feature -- Tests Failures
do do
if attached json_file_from ("fail5.json") as json_file then if attached json_file_from ("fail5.json") as json_file then
parse_json := new_json_parser (json_file) parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json parse_json.parse_content
assert ("fail5.json", parse_json.is_parsed = False) assert ("fail5.json",parse_json.is_valid = False)
end end
end end
test_json_fail6 test_json_fail6
-- --
local local
@@ -149,8 +148,8 @@ feature -- Tests Failures
do do
if attached json_file_from ("fail6.json") as json_file then if attached json_file_from ("fail6.json") as json_file then
parse_json := new_json_parser (json_file) parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json parse_json.parse_content
assert ("fail6.json", parse_json.is_parsed = False) assert ("fail6.json",parse_json.is_valid = False )
end end
end end
@@ -161,8 +160,8 @@ feature -- Tests Failures
do do
if attached json_file_from ("fail7.json") as json_file then if attached json_file_from ("fail7.json") as json_file then
parse_json := new_json_parser (json_file) parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json parse_json.parse_content
assert ("fail7.json", parse_json.is_parsed = False) assert ("fail7.json",parse_json.is_valid = False)
end end
end end
@@ -173,11 +172,12 @@ feature -- Tests Failures
do do
if attached json_file_from ("fail8.json") as json_file then if attached json_file_from ("fail8.json") as json_file then
parse_json := new_json_parser (json_file) parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json parse_json.parse_content
assert ("fail8.json", parse_json.is_parsed = False) assert ("fail8.json",parse_json.is_valid = False )
end end
end end
test_json_fail9 test_json_fail9
-- --
local local
@@ -185,11 +185,12 @@ feature -- Tests Failures
do do
if attached json_file_from ("fail9.json") as json_file then if attached json_file_from ("fail9.json") as json_file then
parse_json := new_json_parser (json_file) parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json parse_json.parse_content
assert ("fail9.json", parse_json.is_parsed = False) assert ("fail9.json",parse_json.is_valid = False)
end end
end end
test_json_fail10 test_json_fail10
-- --
local local
@@ -197,8 +198,8 @@ feature -- Tests Failures
do do
if attached json_file_from ("fail10.json") as json_file then if attached json_file_from ("fail10.json") as json_file then
parse_json := new_json_parser (json_file) parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json parse_json.parse_content
assert ("fail10.json", parse_json.is_parsed = False) assert ("fail10.json",parse_json.is_valid = False)
end end
end end
@@ -209,8 +210,8 @@ feature -- Tests Failures
do do
if attached json_file_from ("fail11.json") as json_file then if attached json_file_from ("fail11.json") as json_file then
parse_json := new_json_parser (json_file) parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json parse_json.parse_content
assert ("fail11.json", parse_json.is_parsed = False) assert ("fail11.json",parse_json.is_valid = False)
end end
end end
@@ -221,8 +222,8 @@ feature -- Tests Failures
do do
if attached json_file_from ("fail12.json") as json_file then if attached json_file_from ("fail12.json") as json_file then
parse_json := new_json_parser (json_file) parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json parse_json.parse_content
assert ("fail12.json", parse_json.is_parsed = False) assert ("fail12.json",parse_json.is_valid = False)
end end
end end
@@ -233,8 +234,8 @@ feature -- Tests Failures
do do
if attached json_file_from ("fail13.json") as json_file then if attached json_file_from ("fail13.json") as json_file then
parse_json := new_json_parser (json_file) parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json parse_json.parse_content
assert ("fail13.json", parse_json.is_parsed = False) assert ("fail13.json",parse_json.is_valid = False)
end end
end end
@@ -245,8 +246,8 @@ feature -- Tests Failures
do do
if attached json_file_from ("fail14.json") as json_file then if attached json_file_from ("fail14.json") as json_file then
parse_json := new_json_parser (json_file) parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json parse_json.parse_content
assert ("fail14.json", parse_json.is_parsed = False) assert ("fail14.json",parse_json.is_valid = False)
end end
end end
@@ -257,8 +258,8 @@ feature -- Tests Failures
do do
if attached json_file_from ("fail15.json") as json_file then if attached json_file_from ("fail15.json") as json_file then
parse_json := new_json_parser (json_file) parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json parse_json.parse_content
assert ("fail15.json", parse_json.is_parsed = False) assert ("fail15.json",parse_json.is_valid = False)
end end
end end
@@ -269,8 +270,8 @@ feature -- Tests Failures
do do
if attached json_file_from ("fail16.json") as json_file then if attached json_file_from ("fail16.json") as json_file then
parse_json := new_json_parser (json_file) parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json parse_json.parse_content
assert ("fail16.json", parse_json.is_parsed = False) assert ("fail16.json",parse_json.is_valid = False)
end end
end end
@@ -281,8 +282,8 @@ feature -- Tests Failures
do do
if attached json_file_from ("fail17.json") as json_file then if attached json_file_from ("fail17.json") as json_file then
parse_json := new_json_parser (json_file) parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json parse_json.parse_content
assert ("fail17.json", parse_json.is_parsed = False) assert ("fail17.json",parse_json.is_valid = False)
end end
end end
@@ -293,8 +294,8 @@ feature -- Tests Failures
do do
if attached json_file_from ("fail18.json") as json_file then if attached json_file_from ("fail18.json") as json_file then
parse_json := new_json_parser (json_file) parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json parse_json.parse_content
assert ("fail18.json", parse_json.is_parsed = True) assert ("fail18.json",parse_json.is_valid = True)
end end
end end
@@ -305,8 +306,8 @@ feature -- Tests Failures
do do
if attached json_file_from ("fail19.json") as json_file then if attached json_file_from ("fail19.json") as json_file then
parse_json := new_json_parser (json_file) parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json parse_json.parse_content
assert ("fail19.json", parse_json.is_parsed = False) assert ("fail19.json",parse_json.is_valid = False)
end end
end end
@@ -317,8 +318,8 @@ feature -- Tests Failures
do do
if attached json_file_from ("fail20.json") as json_file then if attached json_file_from ("fail20.json") as json_file then
parse_json := new_json_parser (json_file) parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json parse_json.parse_content
assert ("fail20.json", parse_json.is_parsed = False) assert ("fail20.json",parse_json.is_valid = False)
end end
end end
@@ -329,11 +330,12 @@ feature -- Tests Failures
do do
if attached json_file_from ("fail21.json") as json_file then if attached json_file_from ("fail21.json") as json_file then
parse_json := new_json_parser (json_file) parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json parse_json.parse_content
assert ("fail21.json", parse_json.is_parsed = False) assert ("fail21.json",parse_json.is_valid = False)
end end
end end
test_json_fail22 test_json_fail22
-- --
local local
@@ -341,8 +343,8 @@ feature -- Tests Failures
do do
if attached json_file_from ("fail22.json") as json_file then if attached json_file_from ("fail22.json") as json_file then
parse_json := new_json_parser (json_file) parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json parse_json.parse_content
assert ("fail22.json", parse_json.is_parsed = False) assert ("fail22.json",parse_json.is_valid = False)
end end
end end
@@ -353,8 +355,8 @@ feature -- Tests Failures
do do
if attached json_file_from ("fail23.json") as json_file then if attached json_file_from ("fail23.json") as json_file then
parse_json := new_json_parser (json_file) parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json parse_json.parse_content
assert ("fail23.json", parse_json.is_parsed = False) assert ("fail23.json",parse_json.is_valid = False)
end end
end end
@@ -365,8 +367,8 @@ feature -- Tests Failures
do do
if attached json_file_from ("fail24.json") as json_file then if attached json_file_from ("fail24.json") as json_file then
parse_json := new_json_parser (json_file) parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json parse_json.parse_content
assert ("fail24.json", parse_json.is_parsed = False) assert ("fail24.json",parse_json.is_valid = False)
end end
end end
@@ -377,11 +379,12 @@ feature -- Tests Failures
do do
if attached json_file_from ("fail25.json") as json_file then if attached json_file_from ("fail25.json") as json_file then
parse_json := new_json_parser (json_file) parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json parse_json.parse_content
assert ("fail25.json", parse_json.is_parsed = False) assert ("fail25.json",parse_json.is_valid = False)
end end
end end
test_json_fail26 test_json_fail26
-- --
local local
@@ -389,11 +392,12 @@ feature -- Tests Failures
do do
if attached json_file_from ("fail26.json") as json_file then if attached json_file_from ("fail26.json") as json_file then
parse_json := new_json_parser (json_file) parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json parse_json.parse_content
assert ("fail26.json", parse_json.is_parsed = False) assert ("fail26.json",parse_json.is_valid = False)
end end
end end
test_json_fail27 test_json_fail27
-- --
local local
@@ -401,11 +405,12 @@ feature -- Tests Failures
do do
if attached json_file_from ("fail27.json") as json_file then if attached json_file_from ("fail27.json") as json_file then
parse_json := new_json_parser (json_file) parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json parse_json.parse_content
assert ("fail27.json", parse_json.is_parsed = False) assert ("fail27.json",parse_json.is_valid = False)
end end
end end
test_json_fail28 test_json_fail28
-- --
local local
@@ -413,11 +418,12 @@ feature -- Tests Failures
do do
if attached json_file_from ("fail28.json") as json_file then if attached json_file_from ("fail28.json") as json_file then
parse_json := new_json_parser (json_file) parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json parse_json.parse_content
assert ("fail28.json", parse_json.is_parsed = False) assert ("fail28.json",parse_json.is_valid = False)
end end
end end
test_json_fail29 test_json_fail29
-- --
local local
@@ -425,11 +431,12 @@ feature -- Tests Failures
do do
if attached json_file_from ("fail29.json") as json_file then if attached json_file_from ("fail29.json") as json_file then
parse_json := new_json_parser (json_file) parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json parse_json.parse_content
assert ("fail29.json", parse_json.is_parsed = False) assert ("fail29.json",parse_json.is_valid = False )
end end
end end
test_json_fail30 test_json_fail30
-- --
local local
@@ -437,8 +444,8 @@ feature -- Tests Failures
do do
if attached json_file_from ("fail30.json") as json_file then if attached json_file_from ("fail30.json") as json_file then
parse_json := new_json_parser (json_file) parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json parse_json.parse_content
assert ("fail30.json", parse_json.is_parsed = False) assert ("fail30.json",parse_json.is_valid = False)
end end
end end
@@ -449,8 +456,8 @@ feature -- Tests Failures
do do
if attached json_file_from ("fail31.json") as json_file then if attached json_file_from ("fail31.json") as json_file then
parse_json := new_json_parser (json_file) parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json parse_json.parse_content
assert ("fail31.json", parse_json.is_parsed = False) assert ("fail31.json",parse_json.is_valid = False)
end end
end end
@@ -461,8 +468,8 @@ feature -- Tests Failures
do do
if attached json_file_from ("fail32.json") as json_file then if attached json_file_from ("fail32.json") as json_file then
parse_json := new_json_parser (json_file) parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json parse_json.parse_content
assert ("fail32.json", parse_json.is_parsed = False) assert ("fail32.json",parse_json.is_valid = False)
end end
end end
@@ -473,8 +480,8 @@ feature -- Tests Failures
do do
if attached json_file_from ("fail33.json") as json_file then if attached json_file_from ("fail33.json") as json_file then
parse_json := new_json_parser (json_file) parse_json := new_json_parser (json_file)
json_value := parse_json.parse_json parse_json.parse_content
assert ("fail33.json", parse_json.is_parsed = False) assert ("fail33.json",parse_json.is_valid = False)
end end
end end
@@ -482,19 +489,16 @@ feature -- JSON_FROM_FILE
file_reader: JSON_FILE_READER file_reader: JSON_FILE_READER
json_value: detachable JSON_VALUE json_file_from (fn: READABLE_STRING_GENERAL): detachable STRING
json_file_from (fn: STRING): detachable STRING
local local
f: RAW_FILE f: RAW_FILE
l_path: STRING l_path: PATH
test_dir: STRING test_dir: PATH
i: INTEGER i: INTEGER
do do
test_dir := (create {EXECUTION_ENVIRONMENT}).current_working_directory test_dir := (create {EXECUTION_ENVIRONMENT}).current_working_path
test_dir.append_character ((create {OPERATING_ENVIRONMENT}).directory_separator) l_path := test_dir.extended (fn)
l_path := test_dir + fn create f.make_with_path (l_path)
create f.make_with_name (l_path)
if f.exists then if f.exists then
-- Found json file -- Found json file
else else
@@ -505,26 +509,27 @@ feature -- JSON_FROM_FILE
until until
i = 0 i = 0
loop loop
test_dir.append_character ('.') test_dir := test_dir.extended ("..")
test_dir.append_character ('.')
test_dir.append_character ((create {OPERATING_ENVIRONMENT}).directory_separator)
i := i - 1 i := i - 1
end end
l_path := test_dir + fn l_path := test_dir.extended (fn)
end end
create f.make_with_name (l_path) create f.make_with_path (l_path)
if f.exists then if f.exists then
Result := file_reader.read_json_from (l_path) Result := file_reader.read_json_from (l_path.name)
end end
assert ("File contains json data", Result /= Void) assert ("File contains json data", Result /= Void)
end end
new_json_parser (a_string: STRING): JSON_PARSER new_json_parser (a_string: STRING): JSON_PARSER
do do
create Result.make_parser (a_string) create Result.make_with_string (a_string)
end end
invariant invariant
file_reader /= Void file_reader /= Void
end end

View File

@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="ISO-8859-1"?> <?xml version="1.0" encoding="ISO-8859-1"?>
<system xmlns="http://www.eiffel.com/developers/xml/configuration-1-8-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-8-0 http://www.eiffel.com/developers/xml/configuration-1-8-0.xsd" name="test_suite" uuid="EA141B17-6A21-4781-8B5F-E9939BAE968A"> <system xmlns="http://www.eiffel.com/developers/xml/configuration-1-13-0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.eiffel.com/developers/xml/configuration-1-13-0 http://www.eiffel.com/developers/xml/configuration-1-13-0.xsd" name="test_suite" uuid="EA141B17-6A21-4781-8B5F-E9939BAE968A">
<target name="test_suite"> <target name="test_suite">
<root cluster="test_suite" class="APPLICATION" feature="make"/> <root cluster="test_suite" class="APPLICATION" feature="make"/>
<file_rule> <file_rule>
@@ -7,11 +7,11 @@
<exclude>/CVS$</exclude> <exclude>/CVS$</exclude>
<exclude>/.svn$</exclude> <exclude>/.svn$</exclude>
</file_rule> </file_rule>
<option warning="true" is_attached_by_default="true" void_safety="all" syntax="standard"> <option warning="true" full_class_checking="false" is_attached_by_default="true" void_safety="transitional" syntax="standard">
<assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/> <assertions precondition="true" postcondition="true" check="true" invariant="true" loop="true" supplier_precondition="true"/>
</option> </option>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/> <library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="json" location="..\..\..\library\json-safe.ecf"/> <library name="json" location="..\..\..\library\json-safe.ecf" readonly="false"/>
<library name="testing" location="$ISE_LIBRARY\library\testing\testing-safe.ecf"/> <library name="testing" location="$ISE_LIBRARY\library\testing\testing-safe.ecf"/>
<cluster name="test_suite" location=".\" recursive="true"/> <cluster name="test_suite" location=".\" recursive="true"/>
</target> </target>