Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Brakets missing on singelton cells #8

Closed
hesstobi opened this issue Sep 3, 2015 · 9 comments
Closed

Brakets missing on singelton cells #8

hesstobi opened this issue Sep 3, 2015 · 9 comments

Comments

@hesstobi
Copy link

hesstobi commented Sep 3, 2015

I have a related Issue to #1.
I want to convert a cell array of strings to json and transfer it to an external api which expect an array. If the cell is not singelton everything works fine. But if i have a singelton cell it is convertet to string data
e.g:

 >> savejson({'A'})
 ans =
 {
      "root": "A"
 } 

But the external API expecting

 ans =
 {
      "root": [
    "A"
]
 } 

There is the option 'NoRowBracket' for numeric arrays and I think a second option for cell arrays will be needed, e.g. 'NoSingeltonCellBracket'. The default value should be 0, because if you use a cell array in matlab is more likely that you realy want a array.

@fangq fangq self-assigned this Sep 3, 2015
@fangq
Copy link
Member

fangq commented Sep 3, 2015

This has been requested more than one time, let's add that support. will work on it in the next few days.

@scottjm-user
Copy link

I would also like to request this feature if you have not implemented it already. It would be very valuable.

@fangq
Copy link
Member

fangq commented Dec 11, 2015

Here is my fix to this issue

https://github.com/fangq/jsonlab/commit/7dd018bdd9e6edc29985c42ffa49382725c887ab

Basically, I added an option called "SingletCell". By default, it is 1, which force printing [] even a cell has only one element.

I also retired NoRowBracket, and replaced it with SingletArray. SingletArray is set as not(NoRowBracket). By default, SingletArray is 0, which removes [] for a single scalar.

Now, the remaining question is how to deal with struct arrays. Currently, I am using SingletArray flag to control the behavior, as if a struct array is a numerical array - i.e. a 1x1 struct will be printed as

"astruct": { "field1": value1, "field2":value2,...}

instead of

"astruct": {[ "field1": value1, "field2":value2,...]}

What do you think?

@jpaasen
Copy link

jpaasen commented Dec 12, 2015

Thank you for your effort Qianqian.

Will this preserve the first example file in #15 if you load and save it? In that example you have both a single struct and a single struct within an array. In that issue there is also an example of a file which contains both a key with a scalar value and a key with a scalar value inside an array.

My issue is that the json files saved by savejson is going to be used as input to another system (C++/python) where there is a difference between a single value and and single value in an array, in addition to a single map/struct and a single map/struct in an array. Therefore it can be some situations where I do not want brackets on all single elements, hence a global flag will not do the job. If for instance a json file is generated by some python or C++ software, and I want to load it in Matlab, change something and write it back, I need load-/save-json to not alter the layout.

It might be to tedious, but currently loadjson is differentiating between a single struct and a single struct in an array by placing the latter 1x1 struct-array inside a cell-array. Could one do the same with a single value in an array to?

So,

{
    "a":[0],
    "b":1,
    "c":[2, 3]
}

will in Matlab look like

a : {[1x1 array]}
b : [1x1 array]
c : [2x1 array]

I'm not sure if this is a good solution, but somehow I need the information about which elements who was originally scalar values (or struct/map) or a value (or struct/map) inside an array to be preserved. So that savejson can store it in the correct way.

My suggestion is that the save json functions automatically adds square brackets to single elements matlab arrays which are contained within a cell-array. It should probably not be the default behaviour, but rater a compliant-mode if the load/save functions are used in combination with other programming languages.

If you have another solution that accomplish the same I'll be fine with that. ;-)

@fangq
Copy link
Member

fangq commented Dec 12, 2015

@jpaasen

Will this preserve the first example file in #15 if you load and save it?

try it, it works on my end

My issue is that the json files saved by savejson is going to be used as input to another system (C++/python) where there is a difference between a single value and and single value in an array,

if you have access to the C/C++/python source code, you can make your code more flexible to deal with situations like this. For example, I did the same for a C code I wrote to handle single element with or without bracket

fangq/mmc@08da9f9

I used cJSON library to access the JSON structure. If you can implement something like mine, I am sure you can deal with situations like this

{
    "a":[0],
    "b":1,
    "c":[2, 3]
}

however, at this point, JSONLab can not preserve the above form with loadjson/savejson because SingletArray flag will force "a" and "b" to use a consistent format, either with bracket, or not, but not mixed.

@jpaasen
Copy link

jpaasen commented Dec 14, 2015

@fangq

try it, it works on my end

Good. I'll test it.

if you have access to the C/C++/python source code, you can make your code more flexible to deal with situations like this. For example, I did the same for a C code I wrote to handle single element with or without bracket

Sure, but in my opinion it makes much more sense to handle, what is basically a Matlab issue, within the Matlab json load/save functions instead of everywhere else. Sometimes you have access to the other source code, but sometimes you don't.

I still wish for a mixed bracket mode for single arrays which can be turned on if needed ;-)

@fangq
Copy link
Member

fangq commented Dec 14, 2015

here is a workaround. first download the latest version with my above patch. then, try below commands

>> ! cat test.json
{
    "a":[0],
    "b":1,
    "c":[2, 3]
}

>> tt=loadjson('test.json','FastArrayParser',0)

tt = 

    a: {[0]}
    b: 1
    c: {[2]  [3]}

>> savejson('',tt)

ans =

{
    "a": [
        0
    ],
    "b": 1,
    "c": [
        2,
        3
    ]
}

>> loadjson(savejson('',tt),'FastArrayParser',0)

ans = 

    a: {[0]}
    b: 1
    c: {[2]  [3]}

The original version of loadjson, derived from below upstream works

http://www.mathworks.com/matlabcentral/fileexchange/20565-json-parser
http://www.mathworks.com/matlabcentral/fileexchange/23393--another--json-parser
http://www.mathworks.com/matlabcentral/fileexchange/25713-highly-portable-json-input-parser

parses any array into a cell array with each array element into a cell element. I added something I called "fast array parser" (https://github.com/fangq/jsonlab/commit/5b82753c0ffe8dba0ed72125beee0495c1b66e62), which groups array elements as much as possible into an array instead of a cell. This alone accelerated the parsing process by 50-80 fold.

Later on, I added an option "FastArrayParser" to set the min dimension beyond which the grouping happens (https://github.com/fangq/jsonlab/commit/9b4c3ba254cb4d9bd5a6fe0cba56538252e8e1ca). Setting it to 0 disables the fast parser entirely.

The difference between [0] and 0 is only distinguishable when you disable the fast array parser.

If you deal only with small JSON objects and wants to keep the depth level of all elements, you may consider setting FastArrayParser to 0 as in the above example. Just be aware that you will have a performance penalty when dealing with large JSON inputs.

@fangq
Copy link
Member

fangq commented Dec 14, 2015

I still wish for a mixed bracket mode for single arrays which can be turned on if needed ;-)

of course I open to ideas for generating consistent output. currently, the nature of the difficulty comes from the ambiguity of the data mapping between JSON data structure (numbers, arrays and objects) to MATLAB data structures (scalars, arrays, structs, struct arrays, cells, cell arrays, classes, and objects). Unless we define a mapping that uniquely label the input data, to reproduce any JSON input is going to be difficult.

As I suggested in this reply (https://github.com/fangq/jsonlab/issues/1#issuecomment-63371585), the current goal is to do round-trip convergence after one or two iterations into the loadjson/savejson loop.

@fangq
Copy link
Member

fangq commented Jan 22, 2016

Closing this bug for now. please reopen if something comes up.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants