This commit is contained in:
2015-04-07 18:36:38 +02:00
59 changed files with 3873 additions and 2872 deletions

View File

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

View File

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

View File

@@ -1,10 +1,12 @@
History file for EJSON History file for EJSON
====================== ======================
team: "" team: ""
date: "2011-07-06" date: "2011-07-06"
revision: "0.3.0" revision: "0.3.0"
WARNING: THIS FILE IS NOT UP TO DATE
+++++++++++++++++++++Important Changes since 0.2.0 version++++++++++++++++++++++++++++++++++++++++++++++ +++++++++++++++++++++Important Changes since 0.2.0 version++++++++++++++++++++++++++++++++++++++++++++++

View File

@@ -1,4 +1,5 @@
Copyright (c) 2010 Javier Velilla and others, http://ejson.origo.ethz.ch Copyright (c) 2010-2014 Javier Velilla, Jocelyn Fiat and others,
https://github.com/eiffelhub/json .
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

@@ -1,21 +1,26 @@
Readme file for eJSON Readme file for eJSON
===================== =====================
team: "Javier Velilla,Jocelyn Fiat, Paul Cohen" team: "Javier Velilla, Jocelyn Fiat"
date: "$Date$" previous contributors: "Paul Cohen"
revision: "$Revision$" date: "2014-nov-17"
1. Introduction 1. Introduction
--------------- ---------------
eJSON stands for Eiffel JSON library and is a small Eiffel library for dealing eJSON stands for Eiffel JSON library and is a small Eiffel library for dealing
with the JSON format. The objective of the library is to provide two basic with the JSON format. This library provides a JSON parser and visitors,
features Eiffel2JSON and JSON2Eiffel. including a pretty printer.
The converters part is now obsolete and not recommended (remember: the
objective of converters were to provide two basic features Eiffel2JSON and
JSON2Eiffel). There will be a new design for converters as a standalone
library on top of Current json library.
2. Legal stuff 2. Legal stuff
-------------- --------------
eJSON is copyrighted by the author Javier Velilla and others. It is licensed eJSON is copyrighted by the author Javier Velilla, Jocelyn Fiat and others. It is licensed
under the MIT License. See the file license.txt in the same directory as this under the MIT License. See the file license.txt in the same directory as this
readme file. readme file.
@@ -46,11 +51,9 @@ Currently the only documentation on eJSON is available at:
EJSON requires that you have: EJSON requires that you have:
1. Gobo 3.9 installed or later 1. One of the following compiler combinations installed:
2. One of the following compiler combinations installed: * ISE Eiffel 13.11 or later.
* ISE Eiffel 6.5 or later.
* gec [try to test] * gec [try to test]
* tecomp [try to test]
eJSON probably works fine with other versions of the above compilers. eJSON probably works fine with other versions of the above compilers.
There are no known platform dependencies (Windows, Linux). There are no known platform dependencies (Windows, Linux).
@@ -58,6 +61,8 @@ There are no known platform dependencies (Windows, Linux).
To install eJSON simply extract the ejson-X.Y.Z.zip file to some appropriate To install eJSON simply extract the ejson-X.Y.Z.zip file to some appropriate
place on your hard disk. There are no requirements on environment variables or place on your hard disk. There are no requirements on environment variables or
registry variables. registry variables.
Note eJSON is also delivered within EiffelStudio release, under
$ISE_LIBRARY/contrib/library/text/parser/json
To verify that everything works you should compile the example programs and/or To verify that everything works you should compile the example programs and/or
the test program. the test program.
@@ -70,18 +75,18 @@ installation.
Directory Description Directory Description
--------- ----------- --------- -----------
doc Contains the eJSON.pdf documentation file. doc Contains documentation file.
examples Contains the two example programs. examples Contains example codes.
ejson Contains the actual eJSON library classes. library Contains the actual eJSON library classes.
test Contains a test program for eJSON. test Contains test suite for eJSON.
7. Contacting the Team 7. Contacting the Team
---------------------- ----------------------
Contact the team: Contact the team:
https://github.com/eiffelhub/json/issues
Javier Velilla «javier.hector@gmail.com» Javier Velilla «javier.hector@gmail.com»
Paul Cohen «paco@seibostudios.se»
Jocelyn Fiat «jfiat@eiffel.com» Jocelyn Fiat «jfiat@eiffel.com»
8. Releases 8. Releases
@@ -92,6 +97,14 @@ history.txt.
Version Date Description Version Date Description
------- ---- ----------- ------- ---- -----------
0.6.0 2014-11-17 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.
Marked converters classes as obsolete.
0.5.0 2013-11-dd Added JSON_ITERATOR, simplified JSON_OBJECT 0.5.0 2013-11-dd Added JSON_ITERATOR, simplified JSON_OBJECT
0.4.0 2012-12-12 Updated documentation URI 0.4.0 2012-12-12 Updated documentation URI
0.3.0 2011-07-06 JSON Factory Converters 0.3.0 2011-07-06 JSON Factory Converters

View File

@@ -0,0 +1,295 @@
== Preface ==
This document is a living document! As always read and try out the code to understand what's really going on.
=== About the project ===
The eJSON project was started by Javier Velilla in 2008. The aim was simply to
provide JSON support to Eiffel programmers. A couple of other people have been
involved to various extent since the start; Berend de Boer, Jocelyn Fiat and
Manu Stapf. In 2009 Paul Cohen joined the project as an active developer and
later Jocelyn Fiat.
The current active maintainers:
- Javier Velilla
- Jocelyn Fiat
The formal name of the project is “eJSON”.
For questions regarding eJSON please contact
- <javier.hector at gmail.com>
- <jfiat at eiffel.com>
- or directly on [https://github.com/eiffelhub/json/issues]
=== Current version and status ===
The latest release is 0.6.0. eJSON has been improved and cleaned.
The converters are not obsolete.
== Introduction ==
=== What is JSON? ===
JSON (JavaScript Object Notation) is a lightweight computer data interchange format. It is a text-based, human-readable format for representing simple data structures and associative arrays (called objects). See the [http://en.wikipedia.org/wiki/JSON Wikipedia article on JSON], [http://www.json.org www.json.org] and [http://www.json.com www.json.com] for more information.
The JSON format is specified in [http://www.ietf.org/rfc/rfc4627.txt IETF RFC 4627] by Douglas Crockford. The official [http://www.iana.org/assignments/media-types Internet MIME media type] for JSON is "application/json". The recommended file name extension for JSON files is ".json".
=== Advantages ===
1. Lightweight data-interchange format.
2. Easy for humans to read and write.
3. Enables easy integration with AJAX/JavaScript web applications. See the article [http://www.developer.com/lang/jscript/article.php/3596836 Speeding Up AJAX with JSON] for a good short discussion on this subject.
4. JSON data structures translate with ease into the native data structures universal to almost all programming languages used today.
=== Use in Eiffel applications ===
JSON can be used as a general serialization format for Eiffel objects. As such it could be used as a:
* Data representation format in REST-based web service applications written in Eiffel.
* Serialization format for Eiffel objects in persistence solutions.
* File format for configuration files in Eiffel systems.
=== Prerequisites ===
eJSON works today with EiffelStudio 13.11
There is an optional extension that requires the latest snapshot of the Gobo Eiffel libraries (a working snapshot is distributed with EiffelStudio). The depencencies on Gobo are on Gobo's unicode
and regex libraries and for some of the extra features in eJSON, on Gobos structure classes DS_HASH_TABLE and DS_LINKED_LIST.
eJSON is intended to work with all ECMA compliant Eiffel compilers.
=== Installation ===
You can either download a given release and install on your machine or you can get the latest snapshot of the code.
To download go to the [http://ejson.origo.ethz.ch/download download page].
To get the latest snapshot of the code do:
: $ git clone https://github.com/eiffelhub/json.git json
*[https://github.com/eiffelhub/json/releases download page]
*[https://github.com/eiffelhub/json github project]
Note that the latest json release is also delivered with EiffelStudio installation under <code>$ISE_LIBRARY/contrib/library/text/parser/json</code>.
=== Cluster and directory layout ===
json/
library/ (Root directory for eJSON library classes)
kernel/ (All classes in this cluster should eventually only depend on ECMA Eiffel and FreeELKS).
json_array.e
json_boolean.e
json_null.e
json_number.e
json_object.e
json_string.e
json_value.e
parser/
json_parser.e
json_parser_access.e
json_reader.e
json_tokens.e
utility/
file/
json_file_reader.e
visitor/
json_visitor.e
json_iterator.e
json_pretty_string_visitor.e
print_json_visitor.e
converters/ (JSON core converter classes !OBSOLETE!)
json_converter.e
json_hash_table_converter.e
json_list_converter.e
json_linked_list_converter.e
json_arrayed_list_converter.e
support/
ejson.e
shared_ejson.e
gobo_converters/ (JSON core converter classes support for GOBO !OBSOLETE!)
converters/
json_ds_hash_table_converter.e
json_ds_linked_list_converter.e
shared_gobo_ejson.e
test/ (Contains autotest suite)
autotest/ (AutoTest based unit test).
examples/ (Example code)
=== Future development ===
Here is a list of suggestions for future development of eJSON.
* Ongoing: Provide a JSON_FACTORY class for easy conversion between arbitrary JSON and Eiffel values.
* Ongoing: Provide a mechanism for users to add custom converters between JSON values and user space Eiffel classes.
* Ongoing: Implement a full test framework for eJSON.
* Suggestion: Investigate performance and improve it if neccessary.
* Suggestion: Support JSON references. See [http://www.json.com/2007/10/19/json-referencing-proposal-and-library JSON Referencing Proposal and Library] and [http://www.sitepen.com/blog/2008/06/17/json-referencing-in-dojo JSON referencing in Dojo] for more information.
* Suggestion: Support JSON path. See [http://goessner.net/articles/JsonPath JSONPath - XPath for JSON] for more information.
* Suggestion: Support JSON schema validation. See [http://json-schema.org JSON Schema Proposal] for more information.
* Suggestion: Support RDF JSON serialization. See [http://n2.talis.com/wiki/RDF_JSON_Specification RDF JSON Specification] for more information.
* Suggestion: Add support to JSON classes for conversion from Eiffel manifest values. So one can write things like:
== A simple example ==
There are two basic approaches to using eJSON; either you use the basic JSON_VALUE classes, converting to and from JSON values to corresponding Eiffel instances or you use the high level eJSON interface class SHARED_EJSON. Of course you can use a mix of both approaches if you find it appropriate!
Here is an example of how to create a JSON number value from an INTEGER and then obtain the JSON representation for that value.
simple_example is
local
i: INTEGER
jn: JSON_NUMBER
s: STRING
do
i := 42
create jn.make_integer (i)
s := jn.representation -- s.is_equal ("42")
end
== Mapping of JSON values to Eiffel values ==
=== JSON number ===
JSON numbers are represented by the class JSON_NUMBER. JSON number values can be converted to/from NATURAL_*, INTEGER_* and REAL_64 values. For floating point values REAL_* is used. The complete mapping is as follows:
JSON number -> Eiffel:
* -128 <= n <= +127 -> INTEGER_8
* n can't be represented by INTEGER_8 and -32768 <= n <= +32767 -> INTEGER_16
* n can't be represented by INTEGER_16 and -2147483648 <= n <= +2147483647 -> INTEGER_32
* n can't be represented by INTEGER_32 and -9223372036854775808 <= n <= +9223372036854775807 -> INTEGER_64
* n can't be represented by INTEGER_64 and 9223372036854775808 <= n <= 18446744073709551615 -> NATURAL_64
* n has fractional dot '.' -> REAL_64.
* n -> eJSON exception if number can't be represented by a INTEGER_64, NATURAL_64 or REAL_64.
Eiffel -> JSON number:
* NATURAL_8, NATURAL_16, NATURAL_32, NATURAL_64, NATURAL -> JSON number
* INTEGER_8, INTEGER_16, INTEGER_32, INTEGER_64, INTEGER -> JSON number
* REAL_32, REAL_64, REAL -> JSON number
You can use the following creation routines to create JSON_NUMBER instances:
* JSON_NUMBER.make_integer
* JSON_NUMBER.make_real
* JSON_NUMBER.make_natural
eiffel_to_json_number_representation is
local
i: INTEGER
r: REAL
jn: JSON_NUMBER
do
print ("JSON representation of Eiffel INTEGER: '")
i := 123
create jn.make_integer (i)
print (jn.representation)
print ("'%N")
print ("JSON representation of Eiffel REAL: '")
r := 12.3
create jn.make_real (r)
print (jn.representation)
print ("'%N")
end
The output of the above code will be:
JSON representation of Eiffel INTEGER: '123'
JSON representation of Eiffel REAL: '12.300000190734863'
=== JSON boolean ===
JSON boolean values are represented by the class JSON_BOOLEAN. The JSON boolean value "true" is converted to/from the BOOLEAN value "True" and the JSON boolean value "false is converted to/from the BOOLEAN value "False".
eiffel_to_json_boolean_representation is
local
b: BOOLEAN
jb: JSON_BOOLEAN
do
print ("JSON representation of Eiffel BOOLEAN: '")
b := True
create jb.make (b)
print (jb.representation)
print ("'%N")
print("JSON representation of Eiffel BOOLEAN: '")
b := False
create jb.make (b)
print (jb.representation)
print ("'%N")
end
The output of the above code will be:
JSON representation of Eiffel BOOLEAN: 'true'
JSON representation of Eiffel BOOLEAN: 'false'
=== JSON string ===
JSON strings are represented by the class JSON_STRING. JSON string values can be converted to/from STRING_32, STRING and CHARACTER values. The complete mapping is as follows:
JSON string -> Eiffel:
* All JSON strings -> STRING or STRING_32
Eiffel -> JSON string:
* STRING_32 -> JSON string
* STRING -> JSON string
* CHARACTER -> JSON string
eiffel_to_json_string_representation is
local
s: STRING
js: JSON_STRING
do
print ("JSON representation of Eiffel STRING: '")
s := "JSON rocks!"
create js.make_from_string (s)
print (js.representation)
print ("'%N")
end
The output of the above code will be:
JSON representation of Eiffel STRING: '"JSON rocks!"'
Note: JSON escape unicode characters, as well a other specific characters, to get the unescaped string value, use either 'unescaped_string_8' or 'unescaped_string_32'.
=== JSON null ===
The JSON null value is represented by the class JSON_NULL. The JSON null value can be converted to/from Void.
eiffel_to_json_null_representation is
local
a: ANY
jn: JSON_NULL
do
create jn
print ("JSON representation for JSON null value: '")
print (jn.representation)
print ("'%N")
a := Void
if attached {JSON_NULL} json.value (a) as l_jn then -- json from SHARED_EJSON!
print ("JSON representation of Eiffel Void reference: '")
print (l_jn.representation)
print ("'%N")
end
end
The output of the above code will be:
JSON representation for JSON null value: 'null'
JSON representation of Eiffel Void reference: 'null'
=== JSON array ===
JSON array is represented by the class JSON_ARRAY.
=== JSON object ===
JSON object is represented by the class JSON_OBJECT.
== The eJSON visitor pattern ==
TBD. See examples.
== The eJSON file reader class ==
TBD.

View File

@@ -0,0 +1,83 @@
class
BASIC
create
make
feature {NONE} -- Initialization
make
-- Initialize `Current'.
local
parser: JSON_PARSER
printer: JSON_PRETTY_STRING_VISITOR
s: STRING_32
do
-- Create parser for content `json_content'
create parser.make_with_string (json_content)
-- Parse the content
parser.parse_content
if
parser.is_valid and then
attached parser.parsed_json_value as jv
then
-- Json content is valid, and well parser.
-- and the parsed json value is `jv'
-- Let's access the glossary/title value
if
attached {JSON_OBJECT} jv as j_object and then
attached {JSON_OBJECT} j_object.item ("glossary") as j_glossary and then
attached {JSON_STRING} j_glossary.item ("title") as j_title
then
print ("The glossary title is %"" + j_title.unescaped_string_8 + "%".%N")
else
print ("The glossary title was not found!%N")
end
-- Pretty print the parsed JSON
create s.make_empty
create printer.make (s)
jv.accept (printer)
print ("The JSON formatted using a pretty printer:%N")
print (s)
end
end
feature -- Status
feature -- Access
json_content: STRING = "[
{
"glossary": {
"title": "example glossary",
"GlossDiv": {
"title": "S",
"GlossList": {
"GlossEntry": {
"ID": "SGML",
"SortAs": "SGML",
"GlossTerm": "Standard Generalized Markup Language",
"Acronym": "SGML",
"Abbrev": "ISO 8879:1986",
"GlossDef": {
"para": "A meta-markup language, used to create markup languages such as DocBook.",
"GlossSeeAlso": ["GML", "XML"]
},
"GlossSee": "markup"
}
}
}
}
}
]"
feature -- Change
feature {NONE} -- Implementation
invariant
-- invariant_clause: True
end

View File

@@ -0,0 +1,10 @@
<?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="basic" uuid="5156B9EE-0436-42A3-BDA1-74710DF05A35">
<target name="basic">
<root class="BASIC" feature="make"/>
<setting name="console_application" value="true"/>
<library name="base" location="$ISE_LIBRARY\library\base\base-safe.ecf"/>
<library name="json" location="..\..\library\json-safe.ecf" readonly="false"/>
<cluster name="basic" location=".\"/>
</target>
</system>

View File

@@ -5,9 +5,14 @@ note
revision: "$Revision$" revision: "$Revision$"
file: "$HeadURL: $" file: "$HeadURL: $"
class JSON_ARRAYED_LIST_CONVERTER class
JSON_ARRAYED_LIST_CONVERTER
obsolete
"This JSON converter design has issues [Sept/2014]."
inherit inherit
JSON_LIST_CONVERTER JSON_LIST_CONVERTER
redefine redefine
object object
@@ -27,4 +32,7 @@ feature {NONE} -- Factory
create Result.make (nb) create Result.make (nb)
end end
note
copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json."
license: "https://github.com/eiffelhub/json/blob/master/License.txt"
end -- class JSON_ARRAYED_LIST_CONVERTER end -- class JSON_ARRAYED_LIST_CONVERTER

View File

@@ -0,0 +1,44 @@
note
description: "A JSON converter"
author: "Paul Cohen"
date: "$Date$"
revision: "$Revision$"
file: "$HeadURL: $"
deferred class
JSON_CONVERTER
obsolete
"This JSON converter design has issues [Sept/2014]."
inherit
SHARED_EJSON
feature -- Access
object: ANY
-- Eiffel object
deferred
end
feature -- Conversion
from_json (j: attached like to_json): detachable like object
-- Convert from JSON value.
-- Returns Void if unable to convert
deferred
end
to_json (o: like object): detachable JSON_VALUE
-- Convert to JSON value
deferred
end
invariant
has_eiffel_object: object /= Void -- An empty object must be created at creation time!
note
copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json."
license: "https://github.com/eiffelhub/json/blob/master/License.txt"
end

View File

@@ -0,0 +1,88 @@
note
description: "A JSON converter for HASH_TABLE [ANY, HASHABLE]"
author: "Paul Cohen"
date: "$Date: 2014-01-30 15:27:41 +0100 (jeu., 30 janv. 2014) $"
revision: "$Revision: 94128 $"
file: "$HeadURL: $"
class
JSON_HASH_TABLE_CONVERTER
obsolete
"This JSON converter design has issues [Sept/2014]."
inherit
JSON_CONVERTER
create
make
feature {NONE} -- Initialization
make
do
create object.make (0)
end
feature -- Access
object: HASH_TABLE [ANY, HASHABLE]
feature -- Conversion
from_json (j: attached like to_json): like object
do
create Result.make (j.count)
across
j as ic
loop
if attached json.object (ic.item, Void) as l_object then
if attached {HASHABLE} json.object (ic.key, Void) as h then
Result.put (l_object, h)
else
check
key_is_hashable: False
end
end
else
check
object_attached: False
end
end
end
end
to_json (o: like object): detachable JSON_OBJECT
local
js: JSON_STRING
failed: BOOLEAN
do
create Result.make
across
o as c
loop
if attached {JSON_STRING} json.value (c.key) as l_key then
js := l_key
else
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
end
if failed then
Result := Void
end
end
note
copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json."
license: "https://github.com/eiffelhub/json/blob/master/License.txt"
end -- class JSON_HASH_TABLE_CONVERTER

View File

@@ -5,9 +5,14 @@ note
revision: "$Revision$" revision: "$Revision$"
file: "$HeadURL: $" file: "$HeadURL: $"
class JSON_LINKED_LIST_CONVERTER class
JSON_LINKED_LIST_CONVERTER
obsolete
"This JSON converter design has issues [Sept/2014]."
inherit inherit
JSON_LIST_CONVERTER JSON_LIST_CONVERTER
redefine redefine
object object
@@ -27,4 +32,7 @@ feature {NONE} -- Factory
create Result.make create Result.make
end end
note
copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json."
license: "https://github.com/eiffelhub/json/blob/master/License.txt"
end -- class JSON_LINKED_LIST_CONVERTER end -- class JSON_LINKED_LIST_CONVERTER

View File

@@ -0,0 +1,80 @@
note
description: "A JSON converter for LIST [ANY]"
author: "Paul Cohen"
date: "$Date$"
revision: "$Revision$"
file: "$HeadURL: $"
deferred class
JSON_LIST_CONVERTER
obsolete
"This JSON converter design has issues [Sept/2014]."
inherit
JSON_CONVERTER
feature {NONE} -- Initialization
make
do
object := new_object (0)
end
feature -- Access
object: LIST [detachable ANY]
feature {NONE} -- Factory
new_object (nb: INTEGER): like object
deferred
ensure
Result /= Void
end
feature -- Conversion
from_json (j: attached like to_json): detachable like object
local
i: INTEGER
do
Result := new_object (j.count)
from
i := 1
until
i > j.count
loop
Result.extend (json.object (j [i], Void))
i := i + 1
end
end
to_json (o: like object): detachable JSON_ARRAY
local
c: ITERATION_CURSOR [detachable ANY]
failed: BOOLEAN
do
create Result.make (o.count)
from
c := o.new_cursor
until
c.after
loop
if attached json.value (c.item) as jv then
Result.add (jv)
else
failed := True
end
c.forth
end
if failed then
Result := Void
end
end
note
copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json."
license: "https://github.com/eiffelhub/json/blob/master/License.txt"
end -- class JSON_ARRAYED_LIST_CONVERTER

View File

@@ -5,9 +5,14 @@ note
revision: "$Revision$" revision: "$Revision$"
file: "$HeadURL: $" file: "$HeadURL: $"
class EJSON class
EJSON
obsolete
"This JSON converter design has issues [Sept/2014]."
inherit inherit
EXCEPTIONS EXCEPTIONS
feature -- Access feature -- Access
@@ -25,7 +30,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
@@ -47,7 +52,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
@@ -56,22 +61,22 @@ feature -- Access
if attached value (a @ i) as v then if attached value (a @ i) as v then
ja.add (v) ja.add (v)
else else
check value_attached: False end check
value_attached: False
end
end end
i := i + 1 i := i + 1
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
if an_object /= Void and then attached converter_for (an_object) as jc then if an_object /= Void and then attached converter_for (an_object) as jc then
@@ -160,12 +165,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
@@ -190,8 +193,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
@@ -205,7 +208,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
@@ -262,7 +265,10 @@ 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
note
copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json."
license: "https://github.com/eiffelhub/json/blob/master/License.txt"
end -- class EJSON end -- class EJSON

View File

@@ -0,0 +1,43 @@
note
description: "[
Shared factory class for creating JSON objects. Maps JSON
objects to ELKS HASH_TABLEs and JSON arrays to ELKS
LINKED_LISTs. Use non-conforming inheritance from this
class to ensure that your classes share the same
JSON_FACTORY instance.
]"
author: "Paul Cohen"
date: "$Date$"
revision: "$Revision: 89185 $"
file: "$HeadURL: $"
class
SHARED_EJSON
obsolete
"This JSON converter design has issues [Sept/2014]."
feature -- Access
json: EJSON
-- A shared EJSON instance with default converters for
--LINKED_LIST [ANY] and HASH_TABLE [ANY, HASHABLE]
local
jalc: JSON_ARRAYED_LIST_CONVERTER
jllc: JSON_LINKED_LIST_CONVERTER
jhtc: JSON_HASH_TABLE_CONVERTER
once
create Result
create jalc.make
Result.add_converter (jalc)
create jllc.make
Result.add_converter (jllc)
create jhtc.make
Result.add_converter (jhtc)
end
note
copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json."
license: "https://github.com/eiffelhub/json/blob/master/License.txt"
end -- class SHARED_EJSON

View File

@@ -1,37 +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

@@ -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

@@ -1,36 +0,0 @@
note
description: "A JSON converter"
author: "Paul Cohen"
date: "$Date$"
revision: "$Revision$"
file: "$HeadURL: $"
deferred class JSON_CONVERTER
inherit
SHARED_EJSON
feature -- Access
object: ANY
-- Eiffel object
deferred
end
feature -- Conversion
from_json (j: attached like to_json): detachable like object
-- Convert from JSON value.
-- Returns Void if unable to convert
deferred
end
to_json (o: like object): detachable JSON_VALUE
-- Convert to JSON value
deferred
end
invariant
has_eiffel_object: object /= Void -- An empty object must be created at creation time!
end

View File

@@ -1,76 +0,0 @@
note
description: "A JSON converter for HASH_TABLE [ANY, HASHABLE]"
author: "Paul Cohen"
date: "$Date: 2014-01-30 15:27:41 +0100 (jeu., 30 janv. 2014) $"
revision: "$Revision: 94128 $"
file: "$HeadURL: $"
class JSON_HASH_TABLE_CONVERTER
inherit
JSON_CONVERTER
create
make
feature {NONE} -- Initialization
make
do
create object.make (0)
end
feature -- Access
object: HASH_TABLE [ANY, HASHABLE]
feature -- Conversion
from_json (j: attached like to_json): like object
do
create Result.make (j.count)
across
j as ic
loop
if attached json.object (ic.item, Void) as l_object then
if attached {HASHABLE} json.object (ic.key, Void) as h then
Result.put (l_object, h)
else
check key_is_hashable: False end
end
else
check object_attached: False end
end
end
end
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
loop
if attached {JSON_STRING} json.value (c.key) as l_key then
js := l_key
else
create js.make_json (c.key.out)
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
end
end
end -- class JSON_HASH_TABLE_CONVERTER

View File

@@ -1,74 +0,0 @@
note
description: "A JSON converter for LIST [ANY]"
author: "Paul Cohen"
date: "$Date$"
revision: "$Revision$"
file: "$HeadURL: $"
deferred class JSON_LIST_CONVERTER
inherit
JSON_CONVERTER
feature {NONE} -- Initialization
make
do
object := new_object (0)
end
feature -- Access
object: LIST [detachable ANY]
feature {NONE} -- Factory
new_object (nb: INTEGER): like object
deferred
ensure
Result /= Void
end
feature -- Conversion
from_json (j: attached like to_json): detachable like object
local
i: INTEGER
do
Result := new_object (j.count)
from
i := 1
until
i > j.count
loop
Result.extend (json.object (j [i], Void))
i := i + 1
end
end
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
from
c := o.new_cursor
until
c.after
loop
jv := json.value (c.item)
if jv /= Void then
Result.add (jv)
else
failed := True
end
c.forth
end
if failed then
Result := Void
end
end
end -- class JSON_ARRAYED_LIST_CONVERTER

View File

@@ -7,15 +7,15 @@ note
[] []
[elements] [elements]
]" ]"
author: "$Author$"
author: "Javier Velilla" date: "$date$"
date: "2008/08/24" revision: "$Revision$"
revision: "Revision 0.1"
class class
JSON_ARRAY JSON_ARRAY
inherit inherit
JSON_VALUE JSON_VALUE
ITERABLE [JSON_VALUE] ITERABLE [JSON_VALUE]
@@ -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,20 +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 has_new_value: old items.count + 1 = items.count and items.first = v
values.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 has_new_value: old items.count + 1 = items.count and items.has (v)
values.has (v)
end end
prune_all (v: JSON_VALUE) prune_all (v: JSON_VALUE)
@@ -122,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
@@ -169,10 +180,13 @@ 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
note
copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json."
license: "https://github.com/eiffelhub/json/blob/master/License.txt"
end end

View File

@@ -1,24 +1,47 @@
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
inherit 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
@@ -58,4 +81,7 @@ feature -- Status report
Result := item.out Result := item.out
end end
note
copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json."
license: "https://github.com/eiffelhub/json/blob/master/License.txt"
end end

View File

@@ -8,6 +8,7 @@ class
JSON_NULL JSON_NULL
inherit inherit
JSON_VALUE JSON_VALUE
feature --Access feature --Access
@@ -44,4 +45,7 @@ feature {NONE}-- Implementation
null_value: STRING = "null" null_value: STRING = "null"
note
copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json."
license: "https://github.com/eiffelhub/json/blob/master/License.txt"
end end

View File

@@ -1,24 +1,22 @@
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
JSON_NUMBER JSON_NUMBER
inherit inherit
JSON_VALUE JSON_VALUE
redefine redefine
is_equal is_equal
end end
create create
make_integer, make_integer, make_natural, make_real
make_natural,
make_real
feature {NONE} -- initialization feature {NONE} -- initialization
@@ -26,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
@@ -48,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
@@ -59,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)
@@ -87,13 +134,16 @@ feature -- Status report
feature -- Implementation feature -- Implementation
INTEGER_TYPE: INTEGER = 1 integer_type: INTEGER = 1
DOUBLE_TYPE: INTEGER = 2
NATURAL_TYPE: INTEGER = 3
numeric_type: INTEGER double_type, real_type: INTEGER = 2
natural_type: INTEGER = 3
invariant invariant
item_not_void: item /= Void item_not_void: item /= Void
note
copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json."
license: "https://github.com/eiffelhub/json/blob/master/License.txt"
end end

View File

@@ -1,25 +1,24 @@
note note
description: "[ description: "[
An JSON_OBJECT represent an object in JSON. An JSON_OBJECT represent an object in JSON.
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
JSON_OBJECT JSON_OBJECT
inherit inherit
JSON_VALUE JSON_VALUE
TABLE_ITERABLE [JSON_VALUE, JSON_STRING] TABLE_ITERABLE [JSON_VALUE, JSON_STRING]
@@ -27,214 +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 (a_value: INTEGER_64; a_key: JSON_STRING)
put_integer (value: INTEGER_64; key: JSON_STRING) -- Assuming there is no item of key `a_key',
-- Assuming there is no item of key `key', -- insert `a_value' with `a_key'.
-- insert `value' with `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
@@ -242,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
@@ -252,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
@@ -260,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
@@ -277,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
@@ -286,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
@@ -308,10 +319,13 @@ 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
note
copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json."
license: "https://github.com/eiffelhub/json/blob/master/License.txt"
end end

View File

@@ -1,39 +1,92 @@
note note
description: "[ description: "[
A JSON_STRING represent a string in JSON. A JSON_STRING represent a string in JSON.
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: "$Author$"
author: "Javier Velilla" date: "$Date$"
date: "2008/08/24" revision: "$Revision$"
revision: "Revision 0.1"
license: "MIT (see http://www.opensource.org/licenses/mit-license.php)" license: "MIT (see http://www.opensource.org/licenses/mit-license.php)"
class class
JSON_STRING JSON_STRING
inherit inherit
JSON_VALUE JSON_VALUE
redefine redefine
is_equal is_equal
end end
create create
make_json, make_from_string, make_from_string_32, make_from_string_general,
make_json_from_string_32, make_from_escaped_json_string,
make_with_escaped_json 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
@@ -42,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
@@ -64,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
@@ -75,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
@@ -87,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 ('%"')
@@ -105,16 +152,23 @@ feature -- Conversion
do do
s := item s := item
n := s.count n := s.count
from i := 1 until i > n loop from
i := 1
until
i > n
loop
c := s [i] c := s [i]
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
@@ -163,16 +217,23 @@ feature -- Conversion
do do
s := item s := item
n := s.count n := s.count
from i := 1 until i > n loop from
i := 1
until
i > n
loop
ch := s.item (i) ch := s.item (i)
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')
@@ -196,48 +257,38 @@ 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
c := ch.natural_32_code c := ch.natural_32_code
if c <= 0x7F then if c <= 0x7F then
-- 0xxxxxxx -- 0xxxxxxx
check ch = c.to_character_32 end check
ch = c.to_character_32
end
a_output.append_character (ch) a_output.append_character (ch)
elseif c <= 0xDF then elseif c <= 0xDF then
-- 110xxxxx 10xxxxxx -- 110xxxxx 10xxxxxx
i := i + 1 i := i + 1
if i <= n then if i <= n then
a_output.append_code ( a_output.append_code (((c & 0x1F) |<< 6) | (s.code (i) & 0x3F))
((c & 0x1F) |<< 6) |
(s.code (i) & 0x3F)
)
end end
elseif c <= 0xEF then elseif c <= 0xEF then
-- 1110xxxx 10xxxxxx 10xxxxxx -- 1110xxxx 10xxxxxx 10xxxxxx
i := i + 2 i := i + 2
if i <= n then if i <= n then
a_output.append_code ( a_output.append_code (((c & 0xF) |<< 12) | ((s.code (i - 1) & 0x3F) |<< 6) | (s.code (i) & 0x3F))
((c & 0xF) |<< 12) |
((s.code (i - 1) & 0x3F) |<< 6) |
(s.code (i) & 0x3F)
)
end end
elseif c <= 0xF7 then elseif c <= 0xF7 then
-- 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx -- 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
i := i + 3 i := i + 3
if i <= n then if i <= n then
a_output.append_code ( a_output.append_code (((c & 0x7) |<< 18) | ((s.code (i - 2) & 0x3F) |<< 12) | ((s.code (i - 1) & 0x3F) |<< 6) | (s.code (i) & 0x3F))
((c & 0x7) |<< 18) |
((s.code (i - 2) & 0x3F) |<< 12) |
((s.code (i - 1) & 0x3F) |<< 6) |
(s.code (i) & 0x3F)
)
end end
end end
i := i + 1 i := i + 1
@@ -265,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
@@ -317,13 +404,11 @@ feature {NONE} -- Implementation
char: CHARACTER char: CHARACTER
do do
nb := s.count nb := s.count
if nb >= 2 and then s.item (2) = 'x' then if nb >= 2 and then s.item (2) = 'x' then
i := 3 i := 3
else else
i := 1 i := 1
end end
from from
until until
i > nb i > nb
@@ -339,35 +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
@@ -378,18 +436,37 @@ feature {NONE} -- Implementation
do do
n := s.count n := s.count
create Result.make (n + n // 10) create Result.make (n + n // 10)
from i := 1 until i > n loop from
i := 1
until
i > n
loop
uc := s.item (i) uc := s.item (i)
if uc.is_character_8 then if uc.is_character_8 then
c := uc.to_character_8 c := uc.to_character_8
inspect c inspect c
when '%"' then Result.append_string ("\%"") when '%"' then
when '\' then Result.append_string ("\\") Result.append_string ("\%"")
when '%B' then Result.append_string ("\b") when '\' then
when '%F' then Result.append_string ("\f") Result.append_string ("\\")
when '%N' then Result.append_string ("\n") when '/' then
when '%R' then Result.append_string ("\r") -- To avoid issue with Javascript </script> ...
when '%T' then Result.append_string ("\t") -- 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
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 else
Result.extend (c) Result.extend (c)
end end
@@ -405,14 +482,15 @@ feature {NONE} -- Implementation
j := j + 1 j := j + 1
end end
h := h.substring (j, h.count) h := h.substring (j, h.count)
from from
until until
h.count >= 4 h.count >= 4
loop loop
h.prepend_integer (0) h.prepend_integer (0)
end end
check h.count = 4 end check
hexastring_has_4_chars: h.count = 4
end
Result.append (h) Result.append (h)
end end
i := i + 1 i := i + 1
@@ -422,4 +500,7 @@ feature {NONE} -- Implementation
invariant invariant
item_not_void: item /= Void item_not_void: item /= Void
note
copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json."
license: "https://github.com/eiffelhub/json/blob/master/License.txt"
end end

View File

@@ -14,11 +14,11 @@ note
revision: "Revision 0.1" revision: "Revision 0.1"
license: "MIT (see http://www.opensource.org/licenses/mit-license.php)" license: "MIT (see http://www.opensource.org/licenses/mit-license.php)"
deferred class deferred class
JSON_VALUE JSON_VALUE
inherit inherit
HASHABLE HASHABLE
DEBUG_OUTPUT DEBUG_OUTPUT
@@ -40,4 +40,7 @@ feature -- Visitor pattern
deferred deferred
end end
note
copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json."
license: "https://github.com/eiffelhub/json/blob/master/License.txt"
end end

View File

@@ -1,513 +0,0 @@
note
description: "Parse serialized JSON data"
author: "jvelilla"
date: "2008/08/24"
revision: "Revision 0.1"
class
JSON_PARSER
inherit
JSON_READER
JSON_TOKENS
create
make_parser
feature {NONE} -- Initialize
make_parser (a_json: STRING)
-- Initialize.
require
json_not_empty: a_json /= Void and then not a_json.is_empty
do
make (a_json)
is_parsed := True
create errors.make
end
feature -- Status report
is_parsed: BOOLEAN
-- Is parsed?
errors: LINKED_LIST [STRING]
-- Current errors
current_errors: STRING
-- Current errors as string
do
create Result.make_empty
from
errors.start
until
errors.after
loop
Result.append_string (errors.item + "%N")
errors.forth
end
end
feature -- Element change
report_error (e: STRING)
-- Report error `e'
require
e_not_void: e /= Void
do
errors.force (e)
end
feature -- Commands
parse_json: detachable JSON_VALUE
-- Parse JSON data `representation'
-- start ::= object | array
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 `['")
end
end
parse: detachable JSON_VALUE
-- Parse JSON data `representation'
local
c: CHARACTER
do
if is_parsed then
skip_white_spaces
c := actual
inspect c
when j_OBJECT_OPEN then
Result := parse_object
when j_STRING then
Result := parse_string
when j_ARRAY_OPEN then
Result := parse_array
else
if c.is_digit or c = j_MINUS then
Result := parse_number
elseif is_null then
Result := create {JSON_NULL}
next
next
next
elseif is_true then
Result := create {JSON_BOOLEAN}.make_boolean (True)
next
next
next
elseif is_false then
Result := create {JSON_BOOLEAN}.make_boolean (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
end
parse_object: JSON_OBJECT
-- object
-- {}
-- {"key" : "value" [,]}
local
has_more: BOOLEAN
l_json_string: detachable JSON_STRING
l_value: detachable JSON_VALUE
do
create Result.make
-- check if is an empty object {}
next
skip_white_spaces
if actual = j_OBJECT_CLOSE then
--is an empty object
else
-- a complex object {"key" : "value"}
previous
from has_more := True until not has_more loop
next
skip_white_spaces
l_json_string := parse_string
next
skip_white_spaces
if actual = ':' then
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
Result.put (l_value, l_json_string)
next
skip_white_spaces
if actual = j_OBJECT_CLOSE then
has_more := False
elseif actual /= ',' then
has_more := False
is_parsed := False
report_error ("JSON Object syntactically malformed expected , found: [" + actual.out + "]")
end
else
has_more := False
-- explain the error
end
end
end
end
parse_string: detachable JSON_STRING
-- Parsed string
local
has_more: BOOLEAN
l_json_string: STRING
l_unicode: STRING
c: like actual
do
create l_json_string.make_empty
if actual = j_STRING then
from
has_more := True
until
not has_more
loop
next
c := actual
if c = j_STRING then
has_more := False
elseif c = '%H' then
next
c := actual
if c = 'u' then
create l_unicode.make_from_string ("\u")
l_unicode.append (read_unicode)
c := actual
if is_valid_unicode (l_unicode) then
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 ('\')
l_json_string.append_character (c)
end
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)
else
Result := Void
end
end
parse_array: JSON_ARRAY
-- array
-- []
-- [elements [,]]
local
flag: BOOLEAN
l_value: detachable JSON_VALUE
c: like actual
do
create Result.make_array
--check if is an empty array []
next
skip_white_spaces
if actual = j_array_close then
--is an empty array
else
previous
from
flag := True
until
not flag
loop
next
skip_white_spaces
l_value := parse
if is_parsed and then l_value /= Void then
Result.add (l_value)
next
skip_white_spaces
c := actual
if c = j_ARRAY_CLOSE then
flag := False
elseif c /= ',' then
flag := False
is_parsed := False
report_error ("Array is not well formed JSON, found [" + c.out + " ]")
end
else
flag := False
report_error ("Array is not well formed JSON, found [" + actual.out + " ]")
end
end
end
end
parse_number: detachable JSON_NUMBER
-- Parsed number
local
sb: STRING
flag: BOOLEAN
is_integer: BOOLEAN
c: like actual
do
create sb.make_empty
sb.append_character (actual)
from
flag := True
until
not flag
loop
next
c := actual
if not has_next or is_close_token (c)
or c = ',' or c = '%N' or c = '%R'
then
flag := False
previous
else
sb.append_character (c)
end
end
if is_valid_number (sb) then
if sb.is_integer then
create Result.make_integer (sb.to_integer)
is_integer := True
elseif sb.is_double and not is_integer then
create Result.make_real (sb.to_double)
end
else
is_parsed := False
report_error ("Expected a number, found: [ " + sb + " ]")
end
end
is_null: BOOLEAN
-- Word at index represents null?
local
l_null: STRING
l_string: STRING
do
l_null := null_id
l_string := json_substring (index,index + l_null.count - 1)
if l_string.is_equal (l_null) then
Result := True
end
end
is_false: BOOLEAN
-- Word at index represents false?
local
l_false: STRING
l_string: STRING
do
l_false := false_id
l_string := json_substring (index, index + l_false.count - 1)
if l_string.is_equal (l_false) then
Result := True
end
end
is_true: BOOLEAN
-- Word at index represents true?
local
l_true: STRING
l_string: STRING
do
l_true := true_id
l_string := json_substring (index,index + l_true.count - 1)
if l_string.is_equal (l_true) then
Result := True
end
end
read_unicode: STRING
-- Read Unicode and return value
local
i: INTEGER
do
create Result.make_empty
from
i := 1
until
i > 4 or not has_next
loop
next
Result.append_character (actual)
i := i + 1
end
end
feature {NONE} -- Implementation
is_valid_number (a_number: STRING): BOOLEAN
-- is 'a_number' a valid number based on this regular expression
-- "-?(?: 0|[1-9]\d+)(?: \.\d+)?(?: [eE][+-]?\d+)?\b"?
local
s: detachable STRING
c: CHARACTER
i,n: INTEGER
do
create s.make_empty
n := a_number.count
if n = 0 then
Result := False
else
Result := True
i := 1
--| "-?"
c := a_number[i]
if c = '-' 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; c := a_number[i]
else
--| "[1-9]"
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; c := a_number[i]
end
end
end
end
if Result then
--| "(\.\d+)?"
if c = '.' then
--| "\.\d+" = "\.\d\d*"
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; c := a_number[i]
end
else
Result := False --| expecting digit
end
end
end
if Result then --| "(?:[eE][+-]?\d+)?\b"
if c = 'e' or c = 'E' then
--| "[eE][+-]?\d+"
s.extend (c); i := i + 1; c := a_number[i]
if c = '+' or c = '-' then
s.extend (c); i := i + 1; c := a_number[i]
end
if c.is_digit then
from until i > n or not c.is_digit loop
s.extend (c); i := i + 1; c := a_number[i]
end
else
Result := False --| expecting digit
end
end
end
if Result then --| "\b"
from until i > n or not c.is_space loop
s.extend (c); i := i + 1; c := a_number[i]
end
Result := i > n and then s.same_string (a_number)
end
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}"
local
i: INTEGER
do
if
a_unicode.count = 6 and then
a_unicode[1] = '\' and then
a_unicode[2] = 'u'
then
from
Result := True
i := 3
until
i > 6 or Result = False
loop
inspect a_unicode[i]
when '0'..'9', 'a'..'f', 'A'..'F' then
else
Result := False
end
i := i + 1
end
end
end
extra_elements: BOOLEAN
-- has more elements?
local
c: like actual
do
if has_next then
next
end
from
c := actual
until
c /= ' ' or c /= '%R' or c /= '%U' or c /= '%T' or c /= '%N' or not has_next
loop
next
end
Result := has_next
end
is_valid_start_symbol : BOOLEAN
-- expecting `{' or `[' as start symbol
do
if attached representation as s and then s.count > 0 then
Result := s[1] = '{' or s[1] = '['
end
end
feature {NONE} -- Constants
false_id: STRING = "false"
true_id: STRING = "true"
null_id: STRING = "null"
end

View File

@@ -1,77 +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

@@ -1,38 +0,0 @@
note
description: "[
Shared factory class for creating JSON objects. Maps JSON
objects to ELKS HASH_TABLEs and JSON arrays to ELKS
LINKED_LISTs. Use non-conforming inheritance from this
class to ensure that your classes share the same
JSON_FACTORY instance.
]"
author: "Paul Cohen"
date: "$Date$"
revision: "$Revision: 89185 $"
file: "$HeadURL: $"
class SHARED_EJSON
feature
json: EJSON
-- A shared EJSON instance with default converters for
--LINKED_LIST [ANY] and HASH_TABLE [ANY, HASHABLE]
local
jalc: JSON_ARRAYED_LIST_CONVERTER
jllc: JSON_LINKED_LIST_CONVERTER
jhtc: JSON_HASH_TABLE_CONVERTER
once
create Result
create jalc.make
Result.add_converter (jalc)
create jllc.make
Result.add_converter (jllc)
create jhtc.make
Result.add_converter (jhtc)
end
end -- class SHARED_EJSON

View File

@@ -0,0 +1,4 @@
${NOTE_KEYWORD}
copyright: "2010-${YEAR}, Javier Velilla and others https://github.com/eiffelhub/json."
license: "https://github.com/eiffelhub/json/blob/master/License.txt"

View File

@@ -0,0 +1,679 @@
note
description: "Parse serialized JSON data"
author: "$Author$"
date: "$Date$"
revision: "$Revision$"
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.
obsolete
"Use `make_with_string' [sept/2014]."
do
make_with_string (a_json)
end
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
errors_as_string: STRING
-- String representation of `errors'.
do
create Result.make_empty
across
errors as ic
loop
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)
-- Report error `e'
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 -- 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
parse_content
if is_parsed then
Result := parsed_json_value
end
end
parse_object: detachable JSON_OBJECT
-- Parse JSON data `representation'
-- start ::= object | array
obsolete
"Use `parse_content' and `parsed_json_value' [nov/2014]."
do
parse_content
if is_parsed and then attached {JSON_OBJECT} parsed_json_value as jo then
Result := jo
end
end
parse: detachable JSON_VALUE
-- Next JSON value from current position on `representation'.
obsolete
"Use restricted `next_parsed_json_value' [sept/2014]."
do
Result := next_parsed_json_value
is_parsed := is_valid
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 not has_error then
skip_white_spaces
c := actual
inspect c
when token_object_open then
Result := next_json_object
when token_double_quote then
Result := parse_string
when token_array_open then
Result := parse_array
else
if c.is_digit or c = token_minus then
Result := parse_number
elseif is_null then
Result := create {JSON_NULL}
next
next
next
elseif is_true then
Result := create {JSON_BOOLEAN}.make_true
next
next
next
elseif is_false then
Result := create {JSON_BOOLEAN}.make_false
next
next
next
next
else
report_error ("JSON is not well formed in parse")
Result := Void
end
end
end
ensure
is_parsed_implies_result_not_void: not has_error implies Result /= Void
end
next_json_object: JSON_OBJECT
-- object
-- {}
-- {"key" : "value" [,]}
local
has_more: BOOLEAN
l_json_string: detachable JSON_STRING
l_value: detachable JSON_VALUE
do
create Result.make
--| check if is an empty object {}
next
skip_white_spaces
if actual = token_object_close then
--| is an empty object
else
--| a complex object {"key" : "value"}
previous
from
has_more := True
until
not has_more
loop
next
skip_white_spaces
l_json_string := parse_string
next
skip_white_spaces
if actual = token_colon then --| token_colon = ':'
next
skip_white_spaces
else
report_error ("%N Input string is a not well formed JSON, expected: : found: " + actual.out)
has_more := False
end
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 = token_object_close then
has_more := False
elseif actual /= token_comma then
has_more := False
report_error ("JSON Object syntactically malformed expected , found: [" + actual.out + "]")
end
else
has_more := False
-- explain the error
end
end
end
end
parse_string: detachable JSON_STRING
-- Parsed string
local
has_more: BOOLEAN
l_json_string: STRING
l_unicode: STRING
c: like actual
do
create l_json_string.make_empty
if actual = token_double_quote then
from
has_more := True
until
not has_more
loop
next
c := actual
if c = token_double_quote then
has_more := False
elseif c = '%H' then -- '%H' = '\' = reverse solidus
next
c := actual
if c = 'u' then
create l_unicode.make_from_string ("\u")
l_unicode.append (read_unicode)
c := actual
if is_valid_unicode (l_unicode) then
l_json_string.append (l_unicode)
else
has_more := 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
report_error ("Input String is not well formed JSON, found [" + c.out + " ]")
else
l_json_string.append_character ('\')
l_json_string.append_character (c)
end
else
if is_special_character (c) and c /= '/' then
has_more := 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_from_escaped_json_string (l_json_string)
else
Result := Void
end
end
parse_array: JSON_ARRAY
-- array
-- []
-- [elements [,]]
local
flag: BOOLEAN
l_value: detachable JSON_VALUE
c: like actual
do
create Result.make_empty
-- check if is an empty array []
next
skip_white_spaces
if actual = token_array_close then
-- is an empty array
else
previous
from
flag := True
until
not flag
loop
next
skip_white_spaces
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 = token_array_close then
flag := False
elseif c /= token_comma then
flag := False
report_error ("Array is not well formed JSON, found [" + c.out + " ]")
end
else
flag := False
report_error ("Array is not well formed JSON, found [" + actual.out + " ]")
end
end
end
end
parse_number: detachable JSON_NUMBER
-- Parsed number
local
sb: STRING
flag: BOOLEAN
is_integer: BOOLEAN
c: like actual
do
create sb.make_empty
sb.append_character (actual)
from
flag := True
until
not flag
loop
next
c := actual
if not has_next or is_close_token (c) or c = token_comma or c = '%N' or c = '%R' then
flag := False
previous
else
sb.append_character (c)
end
end
if is_valid_number (sb) then
if sb.is_integer then
create Result.make_integer (sb.to_integer)
is_integer := True
elseif sb.is_double and not is_integer then
create Result.make_real (sb.to_double)
end
else
report_error ("Expected a number, found: [ " + sb + " ]")
end
end
is_null: BOOLEAN
-- Word at index represents null?
local
l_null: STRING
l_string: STRING
do
l_null := null_id
l_string := json_substring (index, index + l_null.count - 1)
if l_string.is_equal (l_null) then
Result := True
end
end
is_false: BOOLEAN
-- Word at index represents false?
local
l_false: STRING
l_string: STRING
do
l_false := false_id
l_string := json_substring (index, index + l_false.count - 1)
if l_string.is_equal (l_false) then
Result := True
end
end
is_true: BOOLEAN
-- Word at index represents true?
local
l_true: STRING
l_string: STRING
do
l_true := true_id
l_string := json_substring (index, index + l_true.count - 1)
if l_string.is_equal (l_true) then
Result := True
end
end
read_unicode: STRING
-- Read unicode and return value.
local
i: INTEGER
do
create Result.make_empty
from
i := 1
until
i > 4 or not has_next
loop
next
Result.append_character (actual)
i := i + 1
end
end
feature {NONE} -- Implementation
is_valid_number (a_number: STRING): BOOLEAN
-- is 'a_number' a valid number based on this regular expression
-- "-?(?: 0|[1-9]\d+)(?: \.\d+)?(?: [eE][+-]?\d+)?\b"?
local
s: detachable STRING
c: CHARACTER
i, n: INTEGER
do
create s.make_empty
n := a_number.count
if n = 0 then
Result := False
else
Result := True
i := 1
--| "-?"
c := a_number [i]
if c = token_minus then
s.extend (c)
i := i + 1
if i > n then
Result := False
else
c := a_number [i]
end
end
--| "0|[1-9]\d*
if Result and c.is_digit then
if c = '0' then
--| "0"
s.extend (c)
i := i + 1
if i <= n then
c := a_number [i]
end
else
--| "[1-9]"
s.extend (c)
--| "\d*"
i := i + 1
if i <= n then
c := a_number [i]
from
until
i > n or not c.is_digit
loop
s.extend (c)
i := i + 1
if i <= n then
c := a_number [i]
end
end
end
end
end
end
if i > n then
-- Exit
else
if Result then
--| "(\.\d+)?"
if c = token_dot then
--| "\.\d+" = "\.\d\d*"
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
if i <= n then
c := a_number [i]
end
end
else
Result := False --| expecting digit
end
end
end
if Result then --| "(?:[eE][+-]?\d+)?\b"
if is_exp_token (c) then
--| "[eE][+-]?\d+"
s.extend (c)
i := i + 1
c := a_number [i]
if c = token_plus or c = token_minus then
s.extend (c)
i := i + 1
if i <= n then
c := a_number [i]
end
end
if c.is_digit then
from
until
i > n or not c.is_digit
loop
s.extend (c)
i := i + 1
if i <= n then
c := a_number [i]
end
end
else
Result := False --| expecting digit
end
end
end
if Result then --| "\b"
from
until
i > n or not c.is_space
loop
s.extend (c)
i := i + 1
if i <= n then
c := a_number [i]
end
end
Result := i > n and then s.same_string (a_number)
end
end
end
is_valid_unicode (a_unicode: STRING): BOOLEAN
-- is 'a_unicode' a valid unicode based on the regular expression "\\u[0-9a-fA-F]{4}" .
local
i: INTEGER
do
if a_unicode.count = 6 and then a_unicode [1] = '\' and then a_unicode [2] = 'u' then
from
Result := True
i := 3
until
i > 6 or Result = False
loop
inspect a_unicode [i]
when '0'..'9', 'a'..'f', 'A'..'F' then
else
Result := False
end
i := i + 1
end
end
end
extra_elements: BOOLEAN
-- has more elements?
local
c: like actual
do
if has_next then
next
end
from
c := actual
until
c /= ' ' or c /= '%R' or c /= '%U' or c /= '%T' or c /= '%N' or not has_next
loop
next
end
Result := has_next
end
is_valid_start_symbol: BOOLEAN
-- expecting `{' or `[' as start symbol
do
if attached representation as s and then s.count > 0 then
Result := s [1] = token_object_open or s [1] = token_array_open
end
end
feature {NONE} -- Constants
false_id: STRING = "false"
true_id: STRING = "true"
null_id: STRING = "null"
note
copyright: "2010-2015, Javier Velilla and others https://github.com/eiffelhub/json."
license: "https://github.com/eiffelhub/json/blob/master/License.txt"
end

View File

@@ -0,0 +1,12 @@
note
description: "Inherit to access restricted feature from {JSON_PARSER}."
date: "$Date$"
revision: "$Revision$"
deferred class
JSON_PARSER_ACCESS
note
copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json."
license: "https://github.com/eiffelhub/json/blob/master/License.txt"
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
@@ -115,4 +121,7 @@ feature {NONE} -- Implementation
invariant invariant
representation_not_void: representation /= Void representation_not_void: representation /= Void
note
copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json."
license: "https://github.com/eiffelhub/json/blob/master/License.txt"
end end

View File

@@ -0,0 +1,90 @@
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
note
copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json."
license: "https://github.com/eiffelhub/json/blob/master/License.txt"
end

View File

@@ -0,0 +1,49 @@
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
note
copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json."
license: "https://github.com/eiffelhub/json/blob/master/License.txt"
end

View File

@@ -1,8 +1,5 @@
note note
description: description: "JSON Iterator"
"JSON Iterator"
pattern: "Iterator visitor" pattern: "Iterator visitor"
author: "Jocelyn Fiat" author: "Jocelyn Fiat"
license: "MIT (see http://www.opensource.org/licenses/mit-license.php)" license: "MIT (see http://www.opensource.org/licenses/mit-license.php)"
@@ -13,6 +10,7 @@ deferred class
JSON_ITERATOR JSON_ITERATOR
inherit inherit
JSON_VISITOR JSON_VISITOR
feature -- Visitor Pattern feature -- Visitor Pattern
@@ -57,4 +55,7 @@ feature -- Visitor Pattern
do do
end end
note
copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json."
license: "https://github.com/eiffelhub/json/blob/master/License.txt"
end end

View File

@@ -6,6 +6,7 @@ class
JSON_PRETTY_STRING_VISITOR JSON_PRETTY_STRING_VISITOR
inherit inherit
JSON_VISITOR JSON_VISITOR
create create
@@ -26,21 +27,58 @@ feature -- Initialization
output := a_output output := a_output
create indentation.make_empty create indentation.make_empty
indentation_step := "%T" indentation_step := "%T"
object_count_inlining := a_object_count_inlining object_count_inlining := a_object_count_inlining
array_count_inlining := a_array_count_inlining array_count_inlining := a_array_count_inlining
end end
feature -- Access feature -- Access
output: STRING_32 output: STRING_GENERAL
-- JSON representation -- JSON representation
indentation: like output feature -- Settings
indentation_step: like indentation indentation_step: STRING
-- Text used for indentation.
--| by default a tabulation "%T"
line_number: INTEGER object_count_inlining: INTEGER
-- Inline where object item count is under `object_count_inlining'.
--| ex 3:
--| { "a", "b", "c" }
--| ex 2:
--| {
--| "a",
--| "b",
--| "c"
--| }
array_count_inlining: INTEGER
-- Inline where array item count is under `object_count_inlining'.
feature -- Element change
set_indentation_step (a_step: STRING)
-- Set `indentation_step' to `a_step'.
do
indentation_step := a_step
end
set_object_count_inlining (a_nb: INTEGER)
-- Set `object_count_inlining' to `a_nb'.
do
object_count_inlining := a_nb
end
set_array_count_inlining (a_nb: INTEGER)
-- Set `array_count_inlining' to `a_nb'.
do
array_count_inlining := a_nb
end
feature {NONE} -- Implementation
indentation: STRING
indent indent
do do
@@ -59,8 +97,7 @@ feature -- Access
line_number := line_number + 1 line_number := line_number + 1
end end
object_count_inlining: INTEGER line_number: INTEGER
array_count_inlining: INTEGER
feature -- Visitor Pattern feature -- Visitor Pattern
@@ -71,10 +108,14 @@ feature -- Visitor Pattern
l_json_array: ARRAYED_LIST [JSON_VALUE] l_json_array: ARRAYED_LIST [JSON_VALUE]
l_line: like line_number l_line: like line_number
l_multiple_lines: BOOLEAN l_multiple_lines: BOOLEAN
l_output: like output
do do
l_output := output
l_json_array := a_json_array.array_representation l_json_array := a_json_array.array_representation
l_multiple_lines := l_json_array.count >= array_count_inlining or across l_json_array as p some attached {JSON_OBJECT} p.item or attached {JSON_ARRAY} p.item end l_multiple_lines := l_json_array.count >= array_count_inlining
output.append ("[") or across l_json_array as p some attached {JSON_OBJECT} p.item or attached {JSON_ARRAY} p.item end
l_output.append_code (91) -- '[' : 91
l_line := line_number l_line := line_number
indent indent
from from
@@ -82,27 +123,21 @@ feature -- Visitor Pattern
until until
l_json_array.off l_json_array.off
loop loop
if if line_number > l_line or l_multiple_lines then
line_number > l_line or
l_multiple_lines
then
new_line new_line
end end
value := l_json_array.item value := l_json_array.item
value.accept (Current) value.accept (Current)
l_json_array.forth l_json_array.forth
if not l_json_array.after then if not l_json_array.after then
output.append (", ") l_output.append (", ")
end end
end end
exdent exdent
if if line_number > l_line or l_json_array.count >= array_count_inlining then
line_number > l_line or
l_json_array.count >= array_count_inlining
then
new_line new_line
end end
output.append ("]") l_output.append_code (93) -- ']' : 93
end end
visit_json_boolean (a_json_boolean: JSON_BOOLEAN) visit_json_boolean (a_json_boolean: JSON_BOOLEAN)
@@ -129,10 +164,12 @@ feature -- Visitor Pattern
l_pairs: HASH_TABLE [JSON_VALUE, JSON_STRING] l_pairs: HASH_TABLE [JSON_VALUE, JSON_STRING]
l_line: like line_number l_line: like line_number
l_multiple_lines: BOOLEAN l_multiple_lines: BOOLEAN
l_output: like output
do do
l_output := output
l_pairs := a_json_object.map_representation l_pairs := a_json_object.map_representation
l_multiple_lines := l_pairs.count >= object_count_inlining or across l_pairs as p some attached {JSON_OBJECT} p.item or attached {JSON_ARRAY} p.item end l_multiple_lines := l_pairs.count >= object_count_inlining or across l_pairs as p some attached {JSON_OBJECT} p.item or attached {JSON_ARRAY} p.item end
output.append ("{") l_output.append_code (123) -- '{' : 123
l_line := line_number l_line := line_number
indent indent
from from
@@ -140,36 +177,36 @@ feature -- Visitor Pattern
until until
l_pairs.off l_pairs.off
loop loop
if if line_number > l_line or l_multiple_lines then
line_number > l_line or
l_multiple_lines
then
new_line new_line
end end
l_pairs.key_for_iteration.accept (Current) l_pairs.key_for_iteration.accept (Current)
output.append (": ") l_output.append (": ")
l_pairs.item_for_iteration.accept (Current) l_pairs.item_for_iteration.accept (Current)
l_pairs.forth l_pairs.forth
if not l_pairs.after then if not l_pairs.after then
output.append (", ") l_output.append (", ")
end end
end end
exdent exdent
if if line_number > l_line or l_pairs.count >= object_count_inlining then
line_number > l_line or
l_pairs.count >= object_count_inlining
then
new_line new_line
end end
output.append ("}") l_output.append_code (125) -- '}' : 125
end end
visit_json_string (a_json_string: JSON_STRING) visit_json_string (a_json_string: JSON_STRING)
-- Visit `a_json_string'. -- Visit `a_json_string'.
local
l_output: like output
do do
output.append ("%"") l_output := output
output.append (a_json_string.item) l_output.append_code (34) -- '%"' : 34
output.append ("%"") l_output.append (a_json_string.item)
l_output.append_code (34) -- '%"' : 34
end end
note
copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json."
license: "https://github.com/eiffelhub/json/blob/master/License.txt"
end end

View File

@@ -1,8 +1,5 @@
note note
description: description: "JSON Visitor"
"JSON Visitor"
pattern: "Visitor" pattern: "Visitor"
author: "Javier Velilla" author: "Javier Velilla"
license: "MIT (see http://www.opensource.org/licenses/mit-license.php)" license: "MIT (see http://www.opensource.org/licenses/mit-license.php)"
@@ -56,4 +53,7 @@ feature -- Visitor Pattern
deferred deferred
end end
note
copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json."
license: "https://github.com/eiffelhub/json/blob/master/License.txt"
end end

View File

@@ -8,9 +8,11 @@ class
PRINT_JSON_VISITOR PRINT_JSON_VISITOR
inherit inherit
JSON_VISITOR JSON_VISITOR
create make create
make
feature -- Initialization feature -- Initialization
@@ -99,4 +101,7 @@ feature -- Visitor Pattern
to_json.append ("%"") to_json.append ("%"")
end end
note
copyright: "2010-2014, Javier Velilla and others https://github.com/eiffelhub/json."
license: "https://github.com/eiffelhub/json/blob/master/License.txt"
end end

View File

@@ -0,0 +1,16 @@
package json
project
json_safe = "library/json-safe.ecf"
json = "library/json.ecf"
json_gobo_extension = "library/json_gobo_extension.ecf"
note
title: Eiffel JSON
description: Eiffel JSON parser and visitors
tags: json,parser,text
license: MIT
copyright: Copyright (c) 2010-2014 Javier Velilla, Jocelyn Fiat and others,
link[github]: "project" https://github.com/eiffelhub/json
end

View File

@@ -7,6 +7,7 @@ class
APPLICATION APPLICATION
inherit inherit
ARGUMENTS ARGUMENTS
create create

View File

@@ -1,4 +1,5 @@
class AUTHOR class
AUTHOR
create create
make make
@@ -6,19 +7,26 @@ create
feature {NONE} -- Initialization feature {NONE} -- Initialization
make (a_name: STRING_32) make (a_name: STRING_32)
-- Create an author with `a_name' as `name'.
do do
set_name (a_name) set_name (a_name)
ensure
name_set: name = a_name
end end
feature -- Access feature -- Access
name: STRING_32 name: STRING_32
-- Author name
feature -- Status setting feature -- Change
set_name (a_name: STRING_32) set_name (a_name: STRING_32)
-- Set `name' with `a_name'.
do do
name := a_name name := a_name
ensure
name_set: name = a_name
end end
end -- class AUTHOR end -- class AUTHOR

View File

@@ -1,40 +1,59 @@
class BOOK class
BOOK
create create
make make
feature {NONE} -- Initialization feature {NONE} -- Initialization
make (a_title: STRING_32; an_author: AUTHOR; an_isbn: STRING_32) make (a_title: STRING_32; a_author: AUTHOR; a_isbn: STRING_32)
-- Create a book with `a_title' as `title',
-- `a_author' as `author', and `a_isbn' as `isbn'.
do do
set_title (a_title) set_title (a_title)
set_author (an_author) set_author (a_author)
set_isbn (an_isbn) set_isbn (a_isbn)
ensure
title_set: title = a_title
author_set: author = a_author
isbn_set: isbn = a_isbn
end end
feature -- Access feature -- Access
title: STRING_32 title: STRING_32
-- Main title.
isbn: STRING_32 isbn: STRING_32
-- ISBN.
author: AUTHOR author: AUTHOR
-- Author.
feature -- Status setting feature -- Change
set_title (a_title: STRING_32) set_title (a_title: STRING_32)
-- Set `title' with `a_title'.
do do
title := a_title title := a_title
ensure
title_set: title = a_title
end end
set_author (an_author: AUTHOR) set_author (a_author: AUTHOR)
-- Set `author' with `a_author'.
do do
author := an_author author := a_author
ensure
author_set: author = a_author
end end
set_isbn (an_isbn: STRING_32) set_isbn (a_isbn: STRING_32)
-- Set `isbn' with `a_isbn'.
do do
isbn := an_isbn isbn := a_isbn
ensure
isbn_set: isbn = a_isbn
end end
end -- class BOOK end -- class BOOK

View File

@@ -1,4 +1,5 @@
class BOOK_COLLECTION class
BOOK_COLLECTION
create create
make make
@@ -6,75 +7,76 @@ create
feature {NONE} -- Initialization feature {NONE} -- Initialization
make (a_name: STRING_32) make (a_name: STRING_32)
-- Create a book collection with `a_name' as `name'.
do do
set_name (a_name) set_name (a_name)
create book_index.make (10) create book_index.make (10)
ensure
name_set: name = a_name
end end
feature -- Access feature -- Access
name: STRING_32 name: STRING_32
-- Name.
books: LIST [BOOK] books: LIST [BOOK]
-- collection of book.
do do
from
create {LINKED_LIST [BOOK]} Result.make create {LINKED_LIST [BOOK]} Result.make
book_index.start across
until book_index as it
book_index.after
loop loop
Result.append (book_index.item_for_iteration) Result.append (it.item)
book_index.forth
end end
end end
books_by_author (an_author: STRING_32): detachable LIST [BOOK] books_by_author (a_author: STRING_32): LIST [BOOK]
-- Books wrote by `a_author' in this collection.
do do
if book_index.has (an_author) then if attached book_index [a_author] as l_result then
Result := book_index @ an_author Result := l_result
else else
create {LINKED_LIST [BOOK]} Result.make create {LINKED_LIST [BOOK]} Result.make
end end
end end
feature -- Status setting feature -- Change
set_name (a_name: STRING_32) set_name (a_name: STRING_32)
-- Set `name' with `a_name'.
do do
name := a_name name := a_name
ensure
name_set: name = a_name
end end
add_book (a_book: BOOK) add_book (a_book: BOOK)
-- Extend collection with `a_book'.
local local
l: detachable LIST [BOOK] l: detachable LIST [BOOK]
do do
if book_index.has (a_book.author.name) then
l := book_index.at (a_book.author.name) l := book_index.at (a_book.author.name)
else if l = Void then
create {LINKED_LIST [BOOK]} l.make create {LINKED_LIST [BOOK]} l.make
book_index.put (l, a_book.author.name) book_index.put (l, a_book.author.name)
end end
if attached l as la then l.force (a_book)
la.force (a_book)
end
end end
add_books (book_list: like books) add_books (book_list: like books)
-- Append collection with `book_list'.
do do
from across
book_list.start book_list as it
until
book_list.after
loop loop
add_book (book_list.item) add_book (it.item)
book_list.forth
end end
end end
feature {NONE} -- Implementation feature {NONE} -- Implementation
book_index: HASH_TABLE [LIST [BOOK], STRING_32] book_index: HASH_TABLE [LIST [BOOK], STRING_32]
-- Association of author name and its books.
end -- class BOOK_COLLECTION end -- class BOOK_COLLECTION

View File

@@ -4,9 +4,11 @@ note
date: "$Date$" date: "$Date$"
revision: "$Revision$" revision: "$Revision$"
class JSON_AUTHOR_CONVERTER class
JSON_AUTHOR_CONVERTER
inherit inherit
JSON_CONVERTER JSON_CONVERTER
create create
@@ -29,12 +31,10 @@ feature -- Access
feature -- Conversion feature -- Conversion
from_json (j: like to_json): detachable like object from_json (j: like to_json): detachable like object
local
ucs: detachable STRING_32
do do
ucs ?= json.object (j.item (name_key), Void) if attached {STRING_32} json.object (j.item (name_key), Void) as l_name then
check ucs /= Void end create Result.make (l_name)
create Result.make (ucs) end
end end
to_json (o: like object): JSON_OBJECT to_json (o: like object): JSON_OBJECT
@@ -46,8 +46,9 @@ feature -- Conversion
feature {NONE} -- Implementation feature {NONE} -- Implementation
name_key: JSON_STRING name_key: JSON_STRING
-- 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

@@ -4,9 +4,11 @@ note
date: "$Date$" date: "$Date$"
revision: "$Revision$" revision: "$Revision$"
class JSON_BOOK_COLLECTION_CONVERTER class
JSON_BOOK_COLLECTION_CONVERTER
inherit inherit
JSON_CONVERTER JSON_CONVERTER
create create
@@ -30,35 +32,35 @@ feature -- Conversion
from_json (j: like to_json): detachable like object from_json (j: like to_json): detachable like object
local local
ucs: detachable STRING_32 l_books: LINKED_LIST [BOOK]
ll: LINKED_LIST [BOOK]
b: detachable BOOK
ja: detachable JSON_ARRAY
i: INTEGER
do do
ucs ?= json.object (j.item (name_key), Void) if
check ucs /= Void end attached {STRING_32} json.object (j.item (name_key), Void) as l_name and
create Result.make (ucs) attached {JSON_ARRAY} j.item (books_key) as l_json_array
ja ?= j.item (books_key) then
check ja /= Void end create Result.make (l_name)
from create l_books.make
i := 1 across
create ll.make l_json_array as it
until until
i > ja.count Result = Void
loop loop
b ?= json.object (ja [i], "BOOK") if attached {BOOK} json.object (it.item, "BOOK") as l_book then
check b /= Void end l_books.extend (l_book)
ll.force (b) else
i := i + 1 Result := Void
-- Failed
end
end
if Result /= Void then
Result.add_books (l_books)
end
end end
check ll /= Void end
Result.add_books (ll)
end end
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
@@ -66,13 +68,15 @@ feature -- Conversion
feature {NONE} -- Implementation feature {NONE} -- Implementation
name_key: JSON_STRING name_key: JSON_STRING
-- 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.
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

@@ -4,9 +4,11 @@ note
date: "$Date$" date: "$Date$"
revision: "$Revision$" revision: "$Revision$"
class JSON_BOOK_CONVERTER class
JSON_BOOK_CONVERTER
inherit inherit
JSON_CONVERTER JSON_CONVERTER
create create
@@ -31,22 +33,19 @@ feature -- Access
feature -- Conversion feature -- Conversion
from_json (j: like to_json): detachable like object from_json (j: like to_json): detachable like object
local
ucs1, ucs2: detachable STRING_32
a: detachable AUTHOR
do do
ucs1 ?= json.object (j.item (title_key), Void) if
check ucs1 /= Void end attached {STRING_32} json.object (j.item (title_key), Void) as l_title and
ucs2 ?= json.object (j.item (isbn_key), Void) attached {STRING_32} json.object (j.item (isbn_key), Void) as l_isbn and
check ucs2 /= Void end attached {AUTHOR} json.object (j.item (author_key), "AUTHOR") as l_author
a ?= json.object (j.item (author_key), "AUTHOR") then
check a /= Void end create Result.make (l_title, l_author, l_isbn)
create Result.make (ucs1, a, ucs2) end
end end
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)
@@ -55,18 +54,21 @@ feature -- Conversion
feature {NONE} -- Implementation feature {NONE} -- Implementation
title_key: JSON_STRING title_key: JSON_STRING
-- 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.
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.
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

@@ -1,73 +1,71 @@
class TEST_DS note
description: "Linked list and hash table converters test."
date: "$Date$"
revision: "$Revision$"
class
TEST_DS
inherit inherit
SHARED_EJSON
rename default_create as shared_default_create end
EQA_TEST_SET
select default_create end
SHARED_EJSON
undefine
default_create
end
EQA_TEST_SET
feature -- Test feature -- Test
test_linked_list_converter test_linked_list_converter
-- Convert a linked list to a json value and
-- convert this one to a linked list.
local local
jc: JSON_LINKED_LIST_CONVERTER
l: LINKED_LIST [STRING] l: LINKED_LIST [STRING]
l2: detachable LINKED_LIST [detachable ANY]
s: STRING s: STRING
jv: detachable JSON_VALUE
do do
create jc.make
json.add_converter (jc)
create l.make create l.make
s := "foo" l.force ("foo")
l.force (s) l.force ("bar")
s := "bar" if attached json.value (l) as l_value then
l.force (s) s := l_value.representation
jv := json.value (l) assert ("JSON array converted to LINKED_LIST", attached {LINKED_LIST [detachable ANY]} json.object (l_value, "LINKED_LIST"))
assert ("jv /= Void", jv /= Void) else
if attached jv as l_jv then assert ("LINKED_LIST converted to a JSON value", False)
s := jv.representation
l2 ?= json.object (jv, "LINKED_LIST")
assert ("l2 /= Void", l2 /= Void)
end end
end end
test_hash_table_converter test_hash_table_converter
-- Convert a hash table to a json value and
-- convert this one to a hash table.
local local
tc: JSON_HASH_TABLE_CONVERTER
t: HASH_TABLE [STRING, STRING] t: HASH_TABLE [STRING, STRING]
t2: detachable HASH_TABLE [ANY, HASHABLE]
s: STRING s: STRING
ucs_key, ucs_value: detachable STRING_32 l_ucs_key: detachable STRING_32
jv: detachable JSON_VALUE
do do
create tc.make
json.add_converter (tc)
create t.make (2) create t.make (2)
t.put ("foo", "1") t.put ("foo", "1")
t.put ("bar", "2") t.put ("bar", "2")
jv := json.value (t) if attached json.value (t) as l_value then
assert ("jv /= Void", jv /= Void) s := l_value.representation
if attached jv as l_jv then if attached {HASH_TABLE [ANY, HASHABLE]} json.object (l_value, "HASH_TABLE") as t2 then
s := l_jv.representation create l_ucs_key.make_from_string ("1")
t2 ?= json.object (l_jv, "HASH_TABLE") if attached {STRING_32} t2 [l_ucs_key] as l_ucs_value then
assert ("t2 /= Void", t2 /= Void) assert ("ucs_value.string.is_equal (%"foo%")", l_ucs_value.same_string_general ("foo"))
else
assert ("ucs_value /= Void", False)
end end
create ucs_key.make_from_string ("1") create l_ucs_key.make_from_string ("2")
if attached t2 as l_t2 then if attached {STRING_32} t2 [l_ucs_key] as l_ucs_value then
ucs_value ?= t2 @ ucs_key assert ("ucs_value.string.is_equal (%"bar%")", l_ucs_value.same_string_general ("bar"))
assert ("ucs_value /= Void", ucs_value /= Void) else
if attached ucs_value as l_ucs_value then assert ("ucs_value /= Void", False)
assert ("ucs_value.string.is_equal (%"foo%")", l_ucs_value.string.is_equal ("foo"))
end end
create ucs_key.make_from_string ("2") else
ucs_value ?= t2 @ ucs_key assert ("JSON object converted to HASH_TABLE", False);
assert ("ucs_value /= Void", ucs_value /= Void)
if attached ucs_value as l_ucs_value then
assert ("ucs_value.string.is_equal (%"bar%")", l_ucs_value.string.is_equal ("bar"))
end end
else
assert ("HASH_TABLE converted to a JSON value", False)
end end
end end

View File

@@ -1,10 +1,19 @@
class TEST_JSON_CORE class
TEST_JSON_CORE
inherit inherit
SHARED_EJSON SHARED_EJSON
rename default_create as shared_default_create end undefine
default_create
end
EQA_TEST_SET EQA_TEST_SET
select default_create end
JSON_PARSER_ACCESS
undefine
default_create
end
feature -- Test feature -- Test
@@ -31,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
@@ -66,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
@@ -101,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
@@ -136,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
@@ -171,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
@@ -206,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
@@ -241,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
@@ -276,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
@@ -311,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
@@ -345,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
@@ -377,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
@@ -410,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
@@ -430,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
@@ -440,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
@@ -463,78 +472,72 @@ 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
test_json_null test_json_null
local local
a: detachable ANY
dummy_object: STRING
jn: detachable JSON_NULL
jrep: STRING jrep: STRING
jn: JSON_NULL
parser: JSON_PARSER parser: JSON_PARSER
do do
-- Eiffel value -> JSON value -> JSON representation -- Eiffel value -> JSON value -> JSON representation
create jn create jn
assert ("jn /= Void", jn /= Void) jrep := "null"
assert ("jn.representation.is_equal (%"%"null%"%")", jn.representation.is_equal ("null")) assert ("jn.representation.is_equal (%"%"null%"%")", jn.representation.is_equal (jrep))
-- Eiffel value -> JSON value -> JSON representation with factory -- Eiffel value -> JSON value -> JSON representation with factory
jn ?= json.value (Void) if attached {JSON_NULL} json.value (Void) as l_json_null then
assert ("jn /= Void", jn /= Void) assert ("jn.representation.is_equal (%"null%")", l_json_null.representation.is_equal ("null"))
if attached jn as l_jn then else
assert ("jn.representation.is_equal (%"null%")", l_jn.representation.is_equal ("null")) assert ("json.value (Void) /= Void", False)
end end
-- JSON representation -> JSON value -> Eiffel value -- JSON representation -> JSON value -> Eiffel value
jrep := "null" create parser.make_with_string (jrep)
create parser.make_parser (jrep) if attached parser.next_parsed_json_value as l_json_null then
jn := Void assert ("a = Void", json.object (l_json_null, Void) = Void)
jn ?= parser.parse else
assert ("jn /= Void", jn /= Void) assert ("parser.next_parsed_json_value /= Void", False)
create dummy_object.make_empty end
a := dummy_object
a ?= json.object (jn, Void)
assert ("a = Void", a = Void)
end end
test_json_string_and_character test_json_string_and_character
local local
c: CHARACTER c: CHARACTER
js: detachable JSON_STRING
jrep: STRING jrep: STRING
js: JSON_STRING
parser: JSON_PARSER parser: JSON_PARSER
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 /= Void", js /= Void)
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
js ?= json.value (c) if attached {JSON_STRING} json.value (c) as l_json_str then
assert ("js /= Void", js /= Void) assert ("js.representation.is_equal (%"%"a%"%")", l_json_str.representation.is_equal ("%"a%""))
if attached js as l_js then else
assert ("js.representation.is_equal (%"%"a%"%")", l_js.representation.is_equal ("%"a%"")) assert ("json.value (c) /= Void", False)
end end
-- 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)
js := Void if attached {JSON_STRING} parser.next_parsed_json_value as l_json_str then
js ?= parser.parse if attached {STRING_32} json.object (l_json_str, Void) as ucs then
assert ("js /= Void", js /= Void)
if attached {STRING_32} json.object (js, 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
assert ("parser.next_parsed_json_value /= Void", False)
end
end end
test_json_string_and_string test_json_string_and_string
@@ -545,25 +548,26 @@ feature -- Test
parser: JSON_PARSER parser: JSON_PARSER
do do
s := "foobar" s := "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 /= Void", js /= Void) assert ("js.representation.is_equal (%"%"foobar%"%")", js.representation.is_equal (jrep))
assert ("js.representation.is_equal (%"%"foobar%"%")", js.representation.is_equal ("%"foobar%""))
-- Eiffel value -> JSON value -> JSON representation with factory -- Eiffel value -> JSON value -> JSON representation with factory
js ?= json.value (s) if attached {JSON_STRING} json.value (s) as l_js then
assert ("js /= Void", js /= Void) assert ("js.representation.is_equal (%"%"foobar%"%")", js.representation.is_equal (jrep))
if attached js as l_js then else
assert ("js.representation.is_equal (%"%"foobar%"%")", js.representation.is_equal ("%"foobar%"")) assert ("json.value (s) /= Void", False)
end end
-- JSON representation -> JSON value -> Eiffel value -- JSON representation -> JSON value -> Eiffel value
jrep := "%"foobar%"" create parser.make_with_string (jrep)
create parser.make_parser (jrep) if attached {JSON_STRING} parser.next_parsed_json_value as l_js then
js := Void if attached {STRING_32} json.object (l_js, Void) as l_ucs then
js ?= parser.parse assert ("ucs.string.is_equal (%"foobar%")", l_ucs.string.is_equal (s))
assert ("js /= Void", js /= Void) end
if attached {STRING_32} json.object (js, Void) as l_ucs then else
assert ("ucs.string.is_equal (%"foobar%")", l_ucs.string.is_equal ("foobar")) assert ("parser.next_parsed_json_value /= Void", False)
end end
end end
@@ -571,31 +575,34 @@ feature -- Test
local local
js: detachable JSON_STRING js: detachable JSON_STRING
ucs: detachable STRING_32 ucs: detachable STRING_32
jrep: STRING jrep, s: STRING
parser: JSON_PARSER parser: JSON_PARSER
do do
create ucs.make_from_string ("foobar") s := "foobar"
jrep := "%"foobar%""
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 /= Void", js /= Void) assert ("js.representation.is_equal (%"%"foobar%"%")", js.representation.is_equal (jrep))
assert ("js.representation.is_equal (%"%"foobar%"%")", js.representation.is_equal ("%"foobar%""))
-- Eiffel value -> JSON value -> JSON representation with factory -- Eiffel value -> JSON value -> JSON representation with factory
js ?= json.value (ucs) if attached {JSON_STRING} json.value (ucs) as l_js then
assert ("js /= Void", js /= Void) assert ("js.representation.is_equal (%"%"foobar%"%")", l_js.representation.is_equal (jrep))
if attached js as l_js then else
assert ("js.representation.is_equal (%"%"foobar%"%")", l_js.representation.is_equal ("%"foobar%"")) assert ("json.value (ucs) /= Void", False)
end end
-- JSON representation -> JSON value -> Eiffel value -- JSON representation -> JSON value -> Eiffel value
jrep := "%"foobar%"" create parser.make_with_string (jrep)
create parser.make_parser (jrep) if attached {JSON_STRING} parser.next_parsed_json_value as l_js then
js := Void if attached {STRING_32} json.object (l_js, Void) as l_ucs then
js ?= parser.parse assert ("ucs.string.is_equal (%"foobar%")", l_ucs.string.is_equal (s))
assert ("js /= Void", js /= Void) else
ucs := Void assert ("json.object (js, Void) /= Void", False)
ucs ?= json.object (js, Void) end
if attached ucs as l_ucs then else
assert ("ucs.string.is_equal (%"foobar%")", l_ucs.string.is_equal ("foobar")) assert ("parser.next_parsed_json_value /= Void", False)
end end
end end
@@ -603,52 +610,103 @@ feature -- Test
local local
js: detachable JSON_STRING js: detachable JSON_STRING
s: detachable STRING_8 s: detachable STRING_8
ucs: detachable STRING_32
jrep: STRING jrep: STRING
parser: JSON_PARSER parser: JSON_PARSER
do do
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 ("%"foo\\bar%""))
-- Eiffel value -> JSON value -> JSON representation with factory -- Eiffel value -> JSON value -> JSON representation with factory
js ?= json.value (s) if attached {JSON_STRING} json.value (s) as l_js then
assert ("js /= Void", js /= Void) assert ("js.representation.is_equal (%"%"foobar%"%")", l_js.representation.same_string (jrep))
if js /= Void then else
assert ("js.representation.is_equal (%"%"foobar%"%")", js.representation.same_string ("%"foo\\bar%"")) assert ("json.value (s) /= Void", False)
end end
-- JSON representation -> JSON value -> Eiffel value -- JSON representation -> JSON value -> Eiffel value
jrep := "%"foo\\bar%"" create parser.make_with_string (jrep)
create parser.make_parser (jrep) if attached {JSON_STRING} parser.next_parsed_json_value as l_js then
js ?= parser.parse if attached {STRING_32} json.object (l_js, Void) as l_ucs then
assert ("js /= Void", js /= Void) assert ("ucs.same_string (%"foo\bar%")", l_ucs.same_string ("foo\bar"))
ucs ?= json.object (js, Void) end
if ucs /= Void then else
assert ("ucs.same_string (%"foo\bar%")", ucs.same_string ("foo\bar")) 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
assert ("parser.next_parsed_json_value /= Void", False)
end end
create js.make_from_string_32 ({STRING_32} "你好")
create js.make_json_from_string_32 ({STRING_32}"%/20320/%/22909/")
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}"%/20320/%/22909/")) assert ("same unicode string32 %"%%/20320/%%/22909/%"", jstring.unescaped_string_32.same_string ({STRING_32} "你好"))
else
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]
ll2: detachable LINKED_LIST [detachable ANY]
ja: detachable JSON_ARRAY ja: detachable JSON_ARRAY
jn: JSON_NUMBER jn: JSON_NUMBER
jrep: STRING jrep: STRING
@@ -664,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
@@ -677,11 +735,10 @@ feature -- Test
assert ("ja /= Void", ja /= Void) assert ("ja /= Void", ja /= Void)
assert ("ja.representation.is_equal (%"[0,1,1,2,3,5]%")", ja.representation.is_equal ("[0,1,1,2,3,5]")) assert ("ja.representation.is_equal (%"[0,1,1,2,3,5]%")", ja.representation.is_equal ("[0,1,1,2,3,5]"))
-- Eiffel value -> JSON value -> JSON representation with factory -- Eiffel value -> JSON value -> JSON representation with factory
ja := Void if attached {JSON_ARRAY} json.value (ll) as l_ja then
ja ?= json.value (ll)
assert ("ja /= Void", ja /= Void)
if attached ja as l_ja then
assert ("ja.representation.is_equal (%"[0,1,1,2,3,5]%")", l_ja.representation.is_equal ("[0,1,1,2,3,5]")) assert ("ja.representation.is_equal (%"[0,1,1,2,3,5]%")", l_ja.representation.is_equal ("[0,1,1,2,3,5]"))
else
assert ("json.value (ll) /= Void", False)
end end
-- JSON representation -> JSON value -> Eiffel value -- JSON representation -> JSON value -> Eiffel value
@@ -690,23 +747,21 @@ 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)
ja := Void if attached {JSON_ARRAY} parser.next_parsed_json_value as l_ja then
ja ?= parser.parse if attached {LINKED_LIST [detachable ANY]} json.object (ja, Void) as l_ll2 then
assert ("ja /= Void", ja /= Void)
ll2 ?= json.object (ja, Void)
assert ("ll2 /= Void", ll2 /= Void)
--ll.compare_objects
--ll2.compare_objects
if attached ll2 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
assert ("json.object (ja, Void) /= Void", False)
end
else
assert ("parser.next_parsed_json_value /= Void", False)
end end
end end
test_json_object test_json_object
local local
t, t2: detachable HASH_TABLE [detachable ANY, STRING_GENERAL] t: detachable HASH_TABLE [detachable ANY, STRING_GENERAL]
i: INTEGER i: INTEGER
ucs_key, ucs: STRING_32 ucs_key, ucs: STRING_32
a: ARRAY [INTEGER] a: ARRAY [INTEGER]
@@ -722,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)
@@ -745,6 +800,7 @@ feature -- Test
jo.put (ja, js_key) jo.put (ja, js_key)
assert ("jo /= Void", jo /= Void) assert ("jo /= Void", jo /= Void)
assert ("jo.representation.is_equal (%"{%"name%":%"foobar%",%"size%":42,%"contents%":[0,1,1,2,3,5]}%")", jo.representation.is_equal ("{%"name%":%"foobar%",%"size%":42,%"contents%":[0,1,1,2,3,5]}")) assert ("jo.representation.is_equal (%"{%"name%":%"foobar%",%"size%":42,%"contents%":[0,1,1,2,3,5]}%")", jo.representation.is_equal ("{%"name%":%"foobar%",%"size%":42,%"contents%":[0,1,1,2,3,5]}"))
-- Eiffel value -> JSON value -> JSON representation with factory -- Eiffel value -> JSON value -> JSON representation with factory
create t.make (3) create t.make (3)
create ucs_key.make_from_string ("name") create ucs_key.make_from_string ("name")
@@ -756,26 +812,28 @@ feature -- Test
create ucs_key.make_from_string ("contents") create ucs_key.make_from_string ("contents")
a := <<0, 1, 1, 2, 3, 5>> a := <<0, 1, 1, 2, 3, 5>>
t.put (a, ucs_key) t.put (a, ucs_key)
jo := Void if attached {JSON_OBJECT} json.value (t) as l_jo then
jo ?= json.value (t)
assert ("jo /= Void", jo /= Void)
if attached jo as l_jo then
assert ("jo.representation.is_equal (%"{%"name%":%"foobar%",%"size%":42,%"contents%":[0,1,1,2,3,5]}%")", l_jo.representation.is_equal ("{%"name%":%"foobar%",%"size%":42,%"contents%":[0,1,1,2,3,5]}")) assert ("jo.representation.is_equal (%"{%"name%":%"foobar%",%"size%":42,%"contents%":[0,1,1,2,3,5]}%")", l_jo.representation.is_equal ("{%"name%":%"foobar%",%"size%":42,%"contents%":[0,1,1,2,3,5]}"))
end else
-- JSON representation -> JSON value -> Eiffel value -> JSON value -> JSON representation assert ("json.value (t) /= Void", False)
jrep := "{%"name%":%"foobar%",%"size%":42,%"contents%":[0,1,1,2,3,5]}"
create parser.make_parser (jrep)
jo := Void
jo ?= parser.parse
assert ("jo /= Void", jo /= Void)
t2 ?= json.object (jo, Void)
assert ("t2 /= Void", t2 /= Void)
jo ?= json.value (t2)
assert ("jo /= Void", jo /= Void)
if attached jo as l_jo then
assert ("jrep.is_equal (jo.representation)", jrep.is_equal (jo.representation))
end end
-- 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_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))
else
assert ("json.value (t2) /= Void", False)
end
else
assert ("json.object (jo, Void) /= Void", False)
end
else
assert ("parser.next_parsed_json_value /= Void", jo /= Void)
end
end end
test_json_object_hash_code test_json_object_hash_code
@@ -802,7 +860,6 @@ feature -- Test
jv := json.value (gv) jv := json.value (gv)
else else
assert ("exceptions.is_developer_exception", json.is_developer_exception) assert ("exceptions.is_developer_exception", json.is_developer_exception)
-- assert ("exceptions.is_developer_exception_of_name", json.is_developer_exception_of_name ("eJSON exception: Failed to convert Eiffel object to a JSON_VALUE: OPERATING_ENVIRONMENT"))
end end
rescue rescue
exception := True exception := True
@@ -813,17 +870,15 @@ feature -- Test
-- Test converting from a JSON value to an Eiffel object based on a -- Test converting from a JSON value to an Eiffel object based on a
-- class for which no JSON converter has been registered. -- class for which no JSON converter has been registered.
local local
gv : detachable OPERATING_ENVIRONMENT gv: detachable ANY
jo: JSON_OBJECT jo: JSON_OBJECT
exception: BOOLEAN exception: BOOLEAN
do do
if not exception then if not exception then
create jo.make create jo.make
gv ?= json.object (jo, "OPERATING_ENVIRONMENT") gv := json.object (jo, "OPERATING_ENVIRONMENT")
else else
assert ("exceptions.is_developer_exception", json.is_developer_exception) assert ("exceptions.is_developer_exception", json.is_developer_exception)
-- assert ("exceptions.is_developer_exception_of_name", json.is_developer_exception_of_name ("eJSON exception: Failed to convert JSON_VALUE to an Eiffel object: JSON_OBJECT -> OPERATING_ENVIRONMENT"))
end end
rescue rescue
exception := True exception := True

View File

@@ -1,19 +1,28 @@
class TEST_JSON_CUSTOM_CLASSES note
description: "Parsing and converter of book collection test."
date: "$Date$"
revision: "$Revision$"
class
TEST_JSON_CUSTOM_CLASSES
inherit inherit
SHARED_EJSON SHARED_EJSON
rename default_create as shared_default_create end undefine
default_create
end
EQA_TEST_SET EQA_TEST_SET
select default_create end
feature -- Test feature -- Test
test_custom_classes test_custom_classes
-- Parse JSON representation to JSON_OBJECT and test book collection converter.
local local
bc: detachable BOOK_COLLECTION
jbc: JSON_BOOK_CONVERTER jbc: JSON_BOOK_CONVERTER
jbcc: JSON_BOOK_COLLECTION_CONVERTER jbcc: JSON_BOOK_COLLECTION_CONVERTER
jac: JSON_AUTHOR_CONVERTER jac: JSON_AUTHOR_CONVERTER
jo: detachable JSON_OBJECT
parser: JSON_PARSER parser: JSON_PARSER
jrep: STRING jrep: STRING
do do
@@ -25,18 +34,19 @@ feature -- Test
json.add_converter (jac) json.add_converter (jac)
jrep := "{%"name%":%"Test collection%",%"books%":[{%"title%":%"eJSON: The Definitive Guide%",%"isbn%":%"123123-413243%",%"author%":{%"name%":%"Foo Bar%"}}]}" jrep := "{%"name%":%"Test collection%",%"books%":[{%"title%":%"eJSON: The Definitive Guide%",%"isbn%":%"123123-413243%",%"author%":{%"name%":%"Foo Bar%"}}]}"
create parser.make_parser (jrep) create parser.make_parser (jrep)
jo := Void if attached {JSON_OBJECT} parser.parse as l_json_object then
jo ?= parser.parse if attached {BOOK_COLLECTION} json.object (l_json_object, "BOOK_COLLECTION") as l_collection then
assert ("jo /= Void", jo /= Void) if attached {JSON_OBJECT} json.value (l_collection) as l_json_object_2 then
bc := Void assert ("JSON representation is correct", l_json_object_2.representation.same_string (jrep))
bc ?= json.object (jo, "BOOK_COLLECTION") else
assert ("bc /= Void", bc /= Void) assert ("BOOK_COLLECTION converted to JSON_OBJECT", False)
jo ?= json.value (bc) end
assert ("jo /= Void", jo /= Void) else
if attached jo as l_jo then assert ("JSON_OBJECT converted to BOOK_COLLECTION", False)
assert ("JSON representation is correct", l_jo.representation.same_string ("{%"name%":%"Test collection%",%"books%":[{%"title%":%"eJSON: The Definitive Guide%",%"isbn%":%"123123-413243%",%"author%":{%"name%":%"Foo Bar%"}}]}")) end
else
assert ("JSON object representation to JSON_OBJECT", False)
end end
end end
end -- class TEST_JSON_CUSTOM_CLASS end -- class TEST_JSON_CUSTOM_CLASS

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.
]" ]"
@@ -33,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
@@ -45,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
@@ -57,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
@@ -68,16 +68,12 @@ 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 if attached {JSON_OBJECT} parse_json.parsed_json_value as jo and then attached {JSON_STRING} jo.item ("nihaoma") as js then
attached {JSON_OBJECT} json_value as jo and then assert ("utf8.nihaoma", js.unescaped_string_32.same_string ({STRING_32} "你好吗%T?"))
attached {JSON_STRING} jo.item ("nihaoma") as js
then
assert ("utf8.nihaoma", js.unescaped_string_32.same_string ({STRING_32} "你好吗%T?"))
else else
assert ("utf8.nihaoma", False) assert ("utf8.nihaoma", False)
end end
@@ -91,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
@@ -103,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
@@ -115,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
@@ -127,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
@@ -139,8 +135,8 @@ 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
@@ -152,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
@@ -164,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
@@ -176,8 +172,8 @@ 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
@@ -189,8 +185,8 @@ 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
@@ -202,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
@@ -214,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
@@ -226,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
@@ -238,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
@@ -250,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
@@ -262,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
@@ -274,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
@@ -286,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
@@ -298,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
@@ -310,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
@@ -322,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
@@ -334,8 +330,8 @@ 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
@@ -347,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
@@ -359,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
@@ -371,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
@@ -383,8 +379,8 @@ 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
@@ -396,8 +392,8 @@ 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
@@ -409,8 +405,8 @@ 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
@@ -422,8 +418,8 @@ 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
@@ -435,8 +431,8 @@ 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
@@ -448,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
@@ -460,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
@@ -472,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
@@ -484,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
@@ -493,20 +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)
create f.make_with_path (l_path)
l_path := test_dir + fn
create f.make_with_name (l_path)
if f.exists then if f.exists then
-- Found json file -- Found json file
else else
@@ -517,28 +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>