Libraries: JSON Parser - page 3

To add comments, please log in or register
Marco vd Heijden
Moderator
9528
Marco vd Heijden  
winloosewin:

Update:

I added the following features to json.mqh:

*** In the JSONParser class I added counters for the line and column number of the current parse position.
In case of a parse error one can get these positions with JSONParser::get_line() and JSONParse::get_column().
This is the position where the parse error occured.

*** When parsing had no errors, the user will traverse the data structure delivered by JSONParse::parse().
There may be errors that came from a syntactically valid, but semantically invalid JSON file, e.g. if a positive number is expected but
a negative is detected - or if an integer is expected but a double-non-integer number is found.
In this case one wants also information about the position of the erroneous object in the JSON file. For this,
I have added line and column information in every JSONValue class that can be got by JSONValue::get_line() and JSONValue::get_column().

*** I added the functions isInt(), isIntType(), isLong(), isLongType(),isDouble() to the JSONValue class. The isLongType() delivers
only true if the JSONNumber was really created as an integer and not as a double that is convertible lossless to an integer.
In contrast, the isLong() function delivers also true if the JSONNumber has internally the is_double-flag set but is convertible lossless to
a long integer.

*** In JSONArray and JSONObject I added some convenience functions for type checking (and in JSONObject checking the existence of an object
with the specified key). The functions are e.g. JSONArray::isString(int index) and JSONObject::isString(string key).

Thank you so much.

F0RC3
14
F0RC3  

I need to handle oanda rest api data, so, I needed a json parser for mql4/5. I tried this one here, dl the most recent version (i.e. from winloosewin). Unfortunately it does not work right.

My json string would look like so (but in reality it is like 100kb):

string s = {\"1531735201\":{\"rate\":1.1706,\"price_points\":{\"1.138\":{\"ol\":0.0403,\"pl\":0,\"ps\":0,\"os\":0.0201},\"1.1395\":{\"ol\":0.0201,\"pl\":0,\"ps\":0,\"os\":0.0134}}},\"1531735202\":{\"rate\":1.1706,\"price_points\":{\"1.138\":{\"ol\":0.0403,\"pl\":0,\"ps\":0,\"os\":0.0201},\"1.1395\":{\"ol\":0.0201,\"pl\":0,\"ps\":0,\"os\":0.0134}}}};

The output* is reversed, and parts from inbetween are picked first, instead from the start. Basically, instead of the beginning one gets keys/values from somewhere in the middle or so:

PARSED: {"1531735202" : {"price_points" : {"1.1395" : {"os" : 0.0134,"ps" : 0,"ol" : 0.0201,"pl" : 0},"1.138" : {"os" : 0.0201,"ps" : 0,"ol" : 0.0403,"pl" : 0}},"rate" : 1.1706},"1531735201" : {"price_points" : {"1.1395" : {"os" : 0.0134,"ps" : 0,"ol" : 0.0201,"pl" : 0},"1.138" : {"os" : 0.0201,"ps" : 0,"ol" : 0.0403,"pl" : 0}},"rate" : 1.1706}}

* Just doing:

JSONParser *parser = new JSONParser();
JSONValue *jv = parser.parse(s2);
if (jv == NULL) {
  Print("error:"+(string)parser.getErrorCode()+parser.getErrorMessage());
} else {
  Print("PARSED: "+jv.toString());
}
delete jv;
delete parser;
winloosewin
54
winloosewin  
F0RC3:

I need to handle oanda rest api data, so, I needed a json parser for mql4/5. I tried this one here, dl the most recent version (i.e. from winloosewin). Unfortunately it does not work right.

My json string would look like so (but in reality it is like 100kb):

string s = {\"1531735201\":{\"rate\":1.1706,\"price_points\":{\"1.138\":{\"ol\":0.0403,\"pl\":0,\"ps\":0,\"os\":0.0201},\"1.1395\":{\"ol\":0.0201,\"pl\":0,\"ps\":0,\"os\":0.0134}}},\"1531735202\":{\"rate\":1.1706,\"price_points\":{\"1.138\":{\"ol\":0.0403,\"pl\":0,\"ps\":0,\"os\":0.0201},\"1.1395\":{\"ol\":0.0201,\"pl\":0,\"ps\":0,\"os\":0.0134}}}};

The output* is reversed, and parts from inbetween are picked first, instead from the start. Basically, instead of the beginning one gets keys/values from somewhere in the middle or so:

PARSED: {"1531735202" : {"price_points" : {"1.1395" : {"os" : 0.0134,"ps" : 0,"ol" : 0.0201,"pl" : 0},"1.138" : {"os" : 0.0201,"ps" : 0,"ol" : 0.0403,"pl" : 0}},"rate" : 1.1706},"1531735201" : {"price_points" : {"1.1395" : {"os" : 0.0134,"ps" : 0,"ol" : 0.0201,"pl" : 0},"1.138" : {"os" : 0.0201,"ps" : 0,"ol" : 0.0403,"pl" : 0}},"rate" : 1.1706}}

* Just doing:

In the current parser implementation it is assumed that the order of the different key-value pairs in a JSONObject is not relevant. This is e.g. true if an MQL4 struct is serialized
(the member variable names of the struct are the keys and the actual values of the member variables of a struct object are the values corresponding to the keys).
In a struct the order of the member variables doesn't play a role.
The reason why the parser mixes the order is due to the fact that the key-value lookup is realized via a hash table. If it's important that
the order is not changed one could realize the key-value-lookup via a list; each list element contains one key-value pair. The drawdown
would be that for JSONObjects with a large number of key-value-pairs the time to search a specific key would be larger. But if you have
only a few key-value-pairs in each JSONValue object, the list-approach can possibly even be more time-efficient.


**** I have a little update of the JSON.mqh file: A little bug in the unicode parsing in strings was removed (setting the _pos variable
correctly in case of a parse error so that the user gets the correct position where the error occured).
Further more, I added the possibility to set the

#define TOLERATE_TAB_CR_NL_IN_STRINGS

before including JSON.mqh. If the #define is set, control characters like \r, \n, \t are tolerated inside of JSON strings like in the previous versions
of JSON.mqh - although the JSON standard forbids these control characters inside of strings. If the #define is not set,
control characters lead to a parse error.

Files:
json.mqh 49 kb
F0RC3
14
F0RC3  
winloosewin:

In the current parser implementation it is assumed that the order of the different key-value pairs in a JSONObject is not relevant.

I see. I got stuff to work for me. So, thanks for the parser (updates).

winloosewin
54
winloosewin  

I found a bug in the file hash.mqh that occured when deleting a hash element
with the function hDel() that was stored at the first position of a bucket and when
there was another element in this bucket after it. On calling the destructor of the hash,
it crashed. However, in the JSON.mqh, the function hDel() is not called and so the bug didn't occur when
using only the JSON Parser.

Apart from removing this bug, I decided to modify the hash.mqh so that there is used both a hash table and a
double-linked list to store the objects. So when iterating through the elements of a hash, the order is the same
as the insertion order. So, when iterating through a JSONObject,
the order of the key-value-pairs is now the same as in the JSON-file. But the key-value lookup
is still time-efficient.

Files:
hash.mqh 25 kb
Marco vd Heijden
Moderator
9528
Marco vd Heijden  
Thanks again.
winloosewin
54
winloosewin  
Marco vd Heijden:
Thanks again.

You're welcome!

I use these libraries for an EA that I am developing,

so I'm interested to optimize them.

Marco vd Heijden
Moderator
9528
Marco vd Heijden  

I somehow feel that these will become very important in the near future.

Like Instant messaging queries and things like Crypto / instant payments etc.

It's a very fine technique to exchange data.

Boyan Taksirov
3451
Boyan Taksirov  

This parser helped me a lot!

Thank you!

winloosewin
54
winloosewin  

Happy new year to all !

I have some minor improvements for json.mqh:

** When there is an error in the JSON file, the error message consisted sometimes of several lines. But only the first one or two were meaningful. I fixed it.


** Added the function bool JSONIterator::isValid() . It's the same as JSONIterator::hasNext(), which should be considered as
deprecated since the name hasNext is misleading here (JSONIterator::hasNext() returns true if the current item is valid, not the next).

** Added the initialization _size = 0 in the constructor JSONArray::JSONArray() and _hash = NULL in JSONObject::JSONObject().
Maybe MQL4 would initialize it automatically. But doing the initialization explicitely simplifies a possible port of the code to other languages like pure C++.

** Also for simplifying a possible port of the code to MQL5 or pure C++ I replaced all calls of StringConcatenate() by the + operator.

Files:
json.mqh 49 kb
123
To add comments, please log in or register