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
*.bat text
*.json text
*.txt text

2
.gitignore vendored
View File

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

View File

@@ -1,4 +1,4 @@
History file for EJSON
History file for EJSON
======================
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

View File

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

View File

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

View File

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

View File

@@ -14,7 +14,7 @@ note
class
SHARED_EJSON
feature
feature -- Access
json: EJSON
-- 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"?>
<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">
<root all_classes="true"/>
<file_rule>
@@ -9,20 +9,13 @@
</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">
<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>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf" readonly="true"/>
<cluster name="json" location=".\" recursive="true">
<file_rule>
<exclude>^/gobo$</exclude>
<exclude>^/kernel$</exclude>
<exclude>^/extras$</exclude>
</file_rule>
<cluster name="kernel" location=".\kernel\" recursive="true"/>
<cluster name="extras" location=".\extras\" recursive="true"/>
<cluster name="json" location=".\" >
<cluster name="json_kernel" location=".\kernel" recursive="true"/>
<cluster name="json_parser" location=".\parser" recursive="true"/>
<cluster name="json_utility" location=".\utility" recursive="true"/>
</cluster>
<cluster name="json_converter" location=".\converter" recursive="true"/>
</target>
</system>

View File

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

View File

@@ -12,6 +12,6 @@
<library name="base" location="$ISE_LIBRARY\library\base\base.ecf" readonly="true"/>
<library name="json" location="json.ecf" readonly="true"/>
<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>
</system>

View File

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

View File

@@ -1,8 +1,8 @@
note
description: "JSON Truth values"
author: "Javier Velilla"
date: "2008/08/24"
revision: "Revision 0.1"
description: "JSON Boolean values"
author: "$Author$"
date: "$Date$"
revision: "$Revision$"
class
JSON_BOOLEAN
@@ -12,14 +12,36 @@ inherit
JSON_VALUE
create
make,
make_true, make_false,
make_boolean
feature {NONE} -- Initialization
make_boolean (an_item: BOOLEAN)
--Initialize.
make (a_value: BOOLEAN)
-- Initialize Current JSON boolean with `a_boolean'.
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
feature -- Access

View File

@@ -1,8 +1,8 @@
note
description: "JSON Numbers, octal and hexadecimal formats are not used."
author: "Javier Velilla"
date: "2008/08/24"
revision: "Revision 0.1"
author: "$Author$"
date: "$Date$"
revision: "$Revision$"
license: "MIT (see http://www.opensource.org/licenses/mit-license.php)"
class
@@ -24,21 +24,21 @@ feature {NONE} -- initialization
-- Initialize an instance of JSON_NUMBER from the integer value of `an_argument'.
do
item := an_argument.out
numeric_type := INTEGER_TYPE
numeric_type := integer_type
end
make_natural (an_argument: NATURAL_64)
-- Initialize an instance of JSON_NUMBER from the unsigned integer value of `an_argument'.
do
item := an_argument.out
numeric_type := NATURAL_TYPE
numeric_type := natural_type
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'.
do
item := an_argument.out
numeric_type := DOUBLE_TYPE
numeric_type := double_type
end
feature -- Access
@@ -46,6 +46,9 @@ feature -- Access
item: STRING
-- Content
numeric_type: INTEGER
-- Type of number (integer, natural or real).
hash_code: INTEGER
--Hash code value
do
@@ -57,6 +60,52 @@ feature -- Access
Result := item
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
accept (a_visitor: JSON_VISITOR)
@@ -85,13 +134,11 @@ feature -- Status report
feature -- Implementation
INTEGER_TYPE: INTEGER = 1
integer_type: INTEGER = 1
DOUBLE_TYPE: INTEGER = 2
double_type, real_type: INTEGER = 2
NATURAL_TYPE: INTEGER = 3
numeric_type: INTEGER
natural_type: INTEGER = 3
invariant
item_not_void: item /= Void

View File

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

View File

@@ -4,9 +4,9 @@ note
A string is a collection of zero or more Unicodes characters, wrapped in double
quotes, using blackslash espaces.
]"
author: "Javier Velilla"
date: "2008/08/24"
revision: "Revision 0.1"
author: "$Author$"
date: "$Date$"
revision: "$Revision$"
license: "MIT (see http://www.opensource.org/licenses/mit-license.php)"
class
@@ -20,16 +20,73 @@ inherit
end
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
make_json ({READABLE_STRING_8, STRING_8, IMMUTABLE_STRING_8}),
make_json_from_string_32 ({READABLE_STRING_32, STRING_32, IMMUTABLE_STRING_32})
make_from_string ({READABLE_STRING_8, STRING_8, IMMUTABLE_STRING_8}),
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
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)
-- Initialize.
obsolete
"Use `make_from_string' Sept/2014"
require
item_not_void: s /= Void
do
@@ -38,18 +95,12 @@ feature {NONE} -- Initialization
make_json_from_string_32 (s: READABLE_STRING_32)
-- Initialize from STRING_32 `s'.
obsolete
"Use `make_from_string_32' Sept/2014"
require
item_not_void: s /= Void
do
make_with_escaped_json (escaped_json_string_32 (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
make_with_escaped_json (escaped_json_string (s))
end
feature -- Access
@@ -60,7 +111,7 @@ feature -- Access
feature -- Conversion
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.
local
s: like item
@@ -71,7 +122,7 @@ feature -- Conversion
end
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
--| thus, let's support the UTF-8 encoding during decoding.
local
@@ -83,7 +134,7 @@ feature -- Conversion
end
representation: STRING
-- String representation of `item' with escaped entities if any
-- String representation of `item' with escaped entities if any.
do
create Result.make (item.count + 2)
Result.append_character ('%"')
@@ -110,11 +161,14 @@ feature -- Conversion
if c = '\' then
if i < n then
inspect s [i + 1]
when '%"' then
a_output.append_character ('%"')
i := i + 2
when '\' then
a_output.append_character ('\')
i := i + 2
when '%"' then
a_output.append_character ('%"')
when '/' then
a_output.append_character ('/')
i := i + 2
when 'b' then
a_output.append_character ('%B')
@@ -132,15 +186,15 @@ feature -- Conversion
a_output.append_character ('%T')
i := i + 2
when 'u' then
--| Leave Unicode \uXXXX unescaped
a_output.append_character ('\')
--| Leave unicode \uXXXX unescaped
a_output.append_character (c) -- '\'
i := i + 1
else
a_output.append_character ('\')
a_output.append_character (c) -- '\'
i := i + 1
end
else
a_output.append_character ('\')
a_output.append_character (c) -- '\'
i := i + 1
end
else
@@ -172,11 +226,14 @@ feature -- Conversion
if ch = '\' then
if i < n then
inspect s [i + 1]
when '%"' then
a_output.append_character ('%"')
i := i + 2
when '\' then
a_output.append_character ('\')
i := i + 2
when '%"' then
a_output.append_character ('%"')
when '/' then
a_output.append_character ('/')
i := i + 2
when 'b' then
a_output.append_character ('%B')
@@ -200,11 +257,11 @@ feature -- Conversion
end
i := i + 6 -- i+2+4
else
a_output.append_character ('\')
a_output.append_character (ch) -- '\'
i := i + 1
end
else
a_output.append_character ('\')
a_output.append_character (ch) -- '\'
i := i + 1
end
else
@@ -259,12 +316,48 @@ feature -- Comparison
feature -- Change Element
append (a_string: STRING)
-- Add a_string
append (a_escaped_string: READABLE_STRING_8)
-- Add JSON escaped string `a_escaped_string'
require
a_string_not_void: a_string /= Void
a_escaped_string_not_void: a_escaped_string /= Void
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
feature -- Status report
@@ -331,46 +424,8 @@ feature {NONE} -- Implementation
end
end
escaped_json_string (s: READABLE_STRING_8): STRING_8
-- JSON string with '"' and '\' characters 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
escaped_json_string (s: READABLE_STRING_GENERAL): STRING_8
-- JSON string with '"' and '\' characters and unicode escaped
require
s_not_void: s /= Void
local
@@ -394,6 +449,14 @@ feature {NONE} -- Implementation
Result.append_string ("\%"")
when '\' then
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
Result.append_string ("\b")
when '%F' then
@@ -426,7 +489,7 @@ feature {NONE} -- Implementation
h.prepend_integer (0)
end
check
h.count = 4
hexastring_has_4_chars: h.count = 4
end
Result.append (h)
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
inherit
JSON_READER
rename
make as make_reader,
reset as reset_reader
end
JSON_TOKENS
create
make_with_string,
make_parser
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)
-- Initialize.
require
json_not_empty: a_json /= Void and then not a_json.is_empty
obsolete
"Use `make_with_string' [sept/2014]."
do
make (a_json)
is_parsed := True
create errors.make
make_with_string (a_json)
end
feature -- Status report
@@ -33,23 +45,99 @@ feature -- Status report
is_parsed: BOOLEAN
-- Is parsed ?
is_valid: BOOLEAN
-- Is valid?
do
Result := not has_error
end
has_error: BOOLEAN
-- Has error?
errors: LINKED_LIST [STRING]
-- Current errors
current_errors: STRING
-- Current errors as string
errors_as_string: STRING
-- String representation of `errors'.
do
create Result.make_empty
from
errors.start
until
errors.after
across
errors as ic
loop
Result.append_string (errors.item + "%N")
errors.forth
Result.append_string (ic.item)
Result.append_character ('%N')
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
report_error (e: STRING)
@@ -57,43 +145,64 @@ feature -- Element change
require
e_not_void: e /= Void
do
has_error := True
errors.force (e)
ensure
has_error: has_error
is_not_valid: not is_valid
end
feature -- Commands
feature -- Obsolete commands
parse_json: detachable JSON_VALUE
-- Parse JSON data `representation'
-- start ::= object | array
obsolete
"Use `parse_content' and `parsed_json_value' [sept/2014]."
do
if is_valid_start_symbol then
Result := parse
if extra_elements then
is_parsed := False
end
else
is_parsed := False
report_error ("Syntax error unexpected token, expecting `{' or `['")
parse_content
if is_parsed then
Result := parsed_json_value
end
end
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
c: CHARACTER
do
if is_parsed then
if not has_error then
skip_white_spaces
c := actual
inspect c
when j_OBJECT_OPEN then
when token_object_open then
Result := parse_object
when j_STRING then
when token_double_quote then
Result := parse_string
when j_ARRAY_OPEN then
when token_array_open then
Result := parse_array
else
if c.is_digit or c = j_MINUS then
if c.is_digit or c = token_minus then
Result := parse_number
elseif is_null then
Result := create {JSON_NULL}
@@ -101,25 +210,24 @@ feature -- Commands
next
next
elseif is_true then
Result := create {JSON_BOOLEAN}.make_boolean (True)
Result := create {JSON_BOOLEAN}.make_true
next
next
next
elseif is_false then
Result := create {JSON_BOOLEAN}.make_boolean (False)
Result := create {JSON_BOOLEAN}.make_false
next
next
next
next
else
is_parsed := False
report_error ("JSON is not well formed in parse")
Result := Void
end
end
end
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
parse_object: JSON_OBJECT
@@ -132,13 +240,13 @@ feature -- Commands
l_value: detachable JSON_VALUE
do
create Result.make
-- check if is an empty object {}
--| check if is an empty object {}
next
skip_white_spaces
if actual = j_OBJECT_CLOSE then
--is an empty object
if actual = token_object_close then
--| is an empty object
else
-- a complex object {"key" : "value"}
--| a complex object {"key" : "value"}
previous
from
has_more := True
@@ -150,24 +258,22 @@ feature -- Commands
l_json_string := parse_string
next
skip_white_spaces
if actual = ':' then
if actual = token_colon then --| token_colon = ':'
next
skip_white_spaces
else
is_parsed := False
report_error ("%N Input string is a not well formed JSON, expected: : found: " + actual.out)
has_more := False
end
l_value := parse
if is_parsed and then (l_value /= Void and l_json_string /= Void) then
l_value := next_json_value
if not has_error and then (l_value /= Void and l_json_string /= Void) then
Result.put (l_value, l_json_string)
next
skip_white_spaces
if actual = j_OBJECT_CLOSE then
if actual = token_object_close then
has_more := False
elseif actual /= ',' then
elseif actual /= token_comma then
has_more := False
is_parsed := False
report_error ("JSON Object syntactically malformed expected , found: [" + actual.out + "]")
end
else
@@ -187,7 +293,7 @@ feature -- Commands
c: like actual
do
create l_json_string.make_empty
if actual = j_STRING then
if actual = token_double_quote then
from
has_more := True
until
@@ -195,9 +301,9 @@ feature -- Commands
loop
next
c := actual
if c = j_STRING then
if c = token_double_quote then
has_more := False
elseif c = '%H' then
elseif c = '%H' then -- '%H' = '\' = reverse solidus
next
c := actual
if c = 'u' then
@@ -208,12 +314,10 @@ feature -- Commands
l_json_string.append (l_unicode)
else
has_more := False
is_parsed := False
report_error ("Input String is not well formed JSON, expected a Unicode value, found [" + c.out + " ]")
end
elseif (not is_special_character (c) and not is_special_control (c)) or c = '%N' then
has_more := False
is_parsed := False
report_error ("Input String is not well formed JSON, found [" + c.out + " ]")
else
l_json_string.append_character ('\')
@@ -222,14 +326,13 @@ feature -- Commands
else
if is_special_character (c) and c /= '/' then
has_more := False
is_parsed := False
report_error ("Input String is not well formed JSON, found [" + c.out + " ]")
else
l_json_string.append_character (c)
end
end
end
create Result.make_with_escaped_json (l_json_string)
create Result.make_from_escaped_json_string (l_json_string)
else
Result := Void
end
@@ -244,11 +347,11 @@ feature -- Commands
l_value: detachable JSON_VALUE
c: like actual
do
create Result.make_array
create Result.make_empty
-- check if is an empty array []
next
skip_white_spaces
if actual = j_array_close then
if actual = token_array_close then
-- is an empty array
else
previous
@@ -259,17 +362,16 @@ feature -- Commands
loop
next
skip_white_spaces
l_value := parse
if is_parsed and then l_value /= Void then
l_value := next_json_value
if not has_error and then l_value /= Void then
Result.add (l_value)
next
skip_white_spaces
c := actual
if c = j_ARRAY_CLOSE then
if c = token_array_close then
flag := False
elseif c /= ',' then
elseif c /= token_comma then
flag := False
is_parsed := False
report_error ("Array is not well formed JSON, found [" + c.out + " ]")
end
else
@@ -297,7 +399,7 @@ feature -- Commands
loop
next
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
previous
else
@@ -312,7 +414,6 @@ feature -- Commands
create Result.make_real (sb.to_double)
end
else
is_parsed := False
report_error ("Expected a number, found: [ " + sb + " ]")
end
end
@@ -357,7 +458,7 @@ feature -- Commands
end
read_unicode: STRING
-- Read Unicode and return value
-- Read unicode and return value.
local
i: INTEGER
do
@@ -392,30 +493,30 @@ feature {NONE} -- Implementation
i := 1
--| "-?"
c := a_number [i]
if c = '-' then
s.extend (c);
i := i + 1;
if c = token_minus then
s.extend (c)
i := i + 1
c := a_number [i]
end
--| "0|[1-9]\d*
if c.is_digit then
if c = '0' then
--| "0"
s.extend (c);
i := i + 1;
s.extend (c)
i := i + 1
c := a_number [i]
else
--| "[1-9]"
s.extend (c);
i := i + 1;
s.extend (c)
i := i + 1
c := a_number [i]
--| "\d*"
from
until
i > n or not c.is_digit
loop
s.extend (c);
i := i + 1;
s.extend (c)
i := i + 1
c := a_number [i]
end
end
@@ -423,18 +524,18 @@ feature {NONE} -- Implementation
end
if Result then
--| "(\.\d+)?"
if c = '.' then
if c = token_dot then
--| "\.\d+" = "\.\d\d*"
s.extend (c);
i := i + 1;
s.extend (c)
i := i + 1
c := a_number [i]
if c.is_digit then
from
until
i > n or not c.is_digit
loop
s.extend (c);
i := i + 1;
s.extend (c)
i := i + 1
c := a_number [i]
end
else
@@ -443,14 +544,14 @@ feature {NONE} -- Implementation
end
end
if Result then --| "(?:[eE][+-]?\d+)?\b"
if c = 'e' or c = 'E' then
if is_exp_token (c) then
--| "[eE][+-]?\d+"
s.extend (c);
i := i + 1;
s.extend (c)
i := i + 1
c := a_number [i]
if c = '+' or c = '-' then
s.extend (c);
i := i + 1;
if c = token_plus or c = token_minus then
s.extend (c)
i := i + 1
c := a_number [i]
end
if c.is_digit then
@@ -458,8 +559,8 @@ feature {NONE} -- Implementation
until
i > n or not c.is_digit
loop
s.extend (c);
i := i + 1;
s.extend (c)
i := i + 1
c := a_number [i]
end
else
@@ -472,8 +573,8 @@ feature {NONE} -- Implementation
until
i > n or not c.is_space
loop
s.extend (c);
i := i + 1;
s.extend (c)
i := i + 1
c := a_number [i]
end
Result := i > n and then s.same_string (a_number)
@@ -481,8 +582,7 @@ feature {NONE} -- Implementation
end
is_valid_unicode (a_unicode: STRING): BOOLEAN
-- is 'a_unicode' a valid Unicode based on this regular expression
-- "\\u[0-9a-fA-F]{4}"
-- is 'a_unicode' a valid unicode based on the regular expression "\\u[0-9a-fA-F]{4}" .
local
i: INTEGER
do
@@ -525,7 +625,7 @@ feature {NONE} -- Implementation
-- expecting `{' or `[' as start symbol
do
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

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
reset
-- Reset reader
do
index := 1
end
set_representation (a_json: STRING)
-- Set `representation'.
do
a_json.left_adjust
a_json.right_adjust
representation := a_json
index := 1
reset
end
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
-- Author's name label.
once
create Result.make_json ("name")
create Result.make_from_string ("name")
end
end -- class JSON_AUTHOR_CONVERTER

View File

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

View File

@@ -45,7 +45,7 @@ feature -- Conversion
to_json (o: like object): JSON_OBJECT
do
create Result.make
create Result.make_with_capacity (3)
Result.put (json.value (o.title), title_key)
Result.put (json.value (o.isbn), isbn_key)
Result.put (json.value (o.author), author_key)
@@ -56,19 +56,19 @@ feature {NONE} -- Implementation
title_key: JSON_STRING
-- Book's title label.
once
create Result.make_json ("title")
create Result.make_from_string ("title")
end
isbn_key: JSON_STRING
-- Book ISBN label.
once
create Result.make_json ("isbn")
create Result.make_from_string ("isbn")
end
author_key: JSON_STRING
-- Author label.
once
create Result.make_json ("author")
create Result.make_from_string ("author")
end
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
create l_ucs_key.make_from_string ("1")
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
assert ("ucs_value /= Void", False)
end
create l_ucs_key.make_from_string ("2")
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
assert ("ucs_value /= Void", False)
end

View File

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

View File

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

View File

@@ -1,5 +1,5 @@
<?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">
<root cluster="test_suite" class="APPLICATION" feature="make"/>
<file_rule>
@@ -7,11 +7,11 @@
<exclude>/CVS$</exclude>
<exclude>/.svn$</exclude>
</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"/>
</option>
<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"/>
<cluster name="test_suite" location=".\" recursive="true"/>
</target>