talentdeficit / jsx Goto Github PK
View Code? Open in Web Editor NEWan erlang application for consuming, producing and manipulating json. inspired by yajl
License: MIT License
an erlang application for consuming, producing and manipulating json. inspired by yajl
License: MIT License
jsx:encode([{<<"B">>,{{1999,1,8},{4,5,6.0}}}]).
** exception error: bad argument
in function jsx_parser:value/4 (src/jsx_parser.erl, line 125)
jsx:encode([{<<"B">>,erlang:localtime()}]).
** exception error: bad argument
in function jsx_parser:value/4 (src/jsx_parser.erl, line 125)
A discussion started on erlang-questions:
http://erlang.org/pipermail/erlang-questions/2014-January/076627.html
2015-09-15 05:00:47.496 [error] emulator Error in process <0.16721.423> on node '[email protected]' with exit value: {badarg,[{jsx_parser,value,4,[{file,"src/jsx_parser.erl"},{line,129}]},{lib_syslog,handle_resourcechange_log,8,[{file,"src/lib/lib_syslog.erl"},{line,759}]}]}
I got this error in the server, but not every time, jsx:encode(maps), the maps's value is integer or string or binary.
PHP json_encode escapes forward slashes. I noticed something wasn't working with a recent change in JSX.
Not sure if I need to add a jsx flag in this case for forward slash escapes or something or if I need to hack what php returns to not be stupid.
You can see the problem and my failed attempt to solve it more clearly when running the tests for
Why doesn't jsx encode atoms in object values as string?
mochijson2:encode([{command,eval}]) produces: {"command" : "eval"}
why does jsx refuses to handle it?
Is there any ambiguity about it?
from the rfc4627:
string = quotation-mark *char quotation-mark
char = unescaped /
escape ( ... ) ; uXXXX U+XXXX
escape = %x5C ; \
quotation-mark = %x22 ; "
unescaped = %x20-21 / %x23-5B / %x5D-10FFFF
codepoints not allowed in interchange are explicitly allowed by json strings. jsx currently errors out on encountering these non-characters (unless escaped in some cases, which should also be fixed) but that might make it non-compliant? i have no idea. opening an issue so i don't forget to research it
Please provide some way to convert json objects into Erlang maps directly.
Hi!
jsx:is_json(<<"{">>)
returns {incomplete, Fun}
which is neither true
nor false
stated in documentation.
Bug or feature?
TIA,
--Vladimir
Hi,
It maybe that the merge of develop branch didn't work or something, but I got jsx 2.0, did the following line:
jsx:encode(#{<<"library">> => <<"jsx">>, <<"awesome">> => true}).
and got this
** exception error: bad argument
in function jsx_parser:value/4 (src/jsx_parser.erl, line 125)
It seems map support didn't make it correctly in the merge?
Thanks,
Hi!
jsx:encode([{foo, bar}]).
chokes. How do I make it (options i missed?) generate {"foo": "bar"}
which seems a reasonable (to me) behavior?
TIA,
--Vladimir
Is there any chance JSX could support nil
in addition to null
? nil
is very commonly used by Elixir to represent the nil/null value and it is always such a hassle to convert all the nils into nulls...
Not sure to understand clearly what will change in the coming release (aka master). Will it be still possible to stream JSON? What's the new API for that? An howto migrate would help :)
What do you think about (optionally) converting json objects into orddicts as opposed to plain proplists?
jsx:to_json([self()]) gives error:
** exception error: bad argument
in function jsx_encoder:value/3
called as jsx_encoder:value(<0.37.0>,
{jsx_to_json,{[array_start],[[],<<"[">>],{opts,0,0,0}}},
{opts,false,false,false,auto})
in call from jsx_encoder:list/3 (src/jsx_encoder.erl, line 89)
in call from jsx_encoder:start/3 (src/jsx_encoder.erl, line 53)
In a multiplayer game, I want to send process IDs from web server to browser. Process IDs are used as a way to uniquely identify players in the game. Currently, I have to manually do this:
io_lib:format("~p", [Pid])
The problem is this code is written at many places. It's very ugly. It's very sweet if jsx automatically serialize process IDs.
The spec's for encode() and decode() should show all the possible error responses.
{incomplete, Fun} is one are there any others? the Docs specify thats a valid return but the -spec does not.
Tuples are fixed size arrays and take less memory than lists:
https://github.com/eriksoe/AGttES/blob/master/DataStructures.asciidoc
in light of this noncharacter handling in jsx needs to be relaxed significantly
I came up with a minimal example which shows that Jsx doesn't like strings --as a key. I would like to show first how that works for both Maps and Properlists:
>jsx:encode([{id, 1}]).
<<"{\"id\":1}">>
>jsx:encode([#{id => 1}]).
<<"[{\"id\":1}]">>
Now, with id
as a string (list of integers)
> jsx:encode([{"id", 1}]).
** exception error: no function clause matching jsx_encoder:unzip([{"id",1}],jsx_encoder) (/app/_build/default/lib/jsx/src/jsx_encoder.erl, line 68)
in function jsx_encoder:encode_/2 (/app/_build/default/lib/jsx/src/jsx_encoder.erl, line 61)
in call from jsx_encoder:'-encoder/3-fun-0-'/2 (/app/_build/default/lib/jsx/src/jsx_encoder.erl, line 32)
>jsx:encode([#{"id" => 1}]).
** exception error: no function clause matching jsx_encoder:unpack(#{"id" => 1},["id"],jsx_encoder) (/app/_build/default/lib/jsx/src/jsx_encoder.erl, line 81)
in function jsx_encoder:encode/2 (/app/_build/default/lib/jsx/src/jsx_encoder.erl, line 50)
in call from jsx_encoder:unhitch/2 (/app/_build/default/lib/jsx/src/jsx_encoder.erl, line 74)
in call from jsx_encoder:encode_/2 (/app/_build/default/lib/jsx/src/jsx_encoder.erl, line 63)
in call from jsx_encoder:'-encoder/3-fun-0-'/2 (/app/_build/default/lib/jsx/src/jsx_encoder.erl, line 32)
I'm kind of new using Erlang, so I'm not sure whether this is an expected behavior or not.
Cheers,
Can this be done soonish? :)
Hello,
Can jxs convert a json file with as output a erlang map.
If so, how can I do this ?
Roelof
Hi!
Wonder if you could adding an option to control whether decoder should throw on errors and whether to return {error, badarg}
tuple.
The rationale is to save try/catch
for a safe decoding.
If this is not feasible, please consider posting the code snippet on how to properly cope with all cases decoder can lead to, if one wants to safely get either a full term, or an error tuple.
TIA,
--Vladimir
Any chance of a new tag soon?
Could really use fix of #71 to finally shut up my dialyzer warnings...
jsx:decode(<<"{"library": "jsx", "awesome": true}">>, [return_maps]).
[{<<"library">>,<<"jsx">>},{<<"awesome">>,true}]
Hello,
JSX has this nice feature of being able to generate ISO8601 strings from Erlang calendar:datetime() tuples. The generated string does not include a timezone, which is a problem for us because all our datetimes are based on the UTC timezone.
On a related subject, please note that interpretation of a ISO8601 string with no timezone differs between browsers and ECMAScript versions (see here).
Would it be possible to add a "Z" at the end of the timezone writer so that it is explicitely a UTC date?
Best,
Cam
On jsx.erl:
-spec format(Source::json_text()) -> json_text() | {incomplete, decoder()}.
-spec format(Source::json_text(), Config::jsx_to_json:config()) -> json_text() | {incomplete, decoder()}.
format(Source) -> format(Source, []).
format(Source, Config) -> jsx_to_json:format(Source, Config).
But jsx_to_json.erl:
-spec format(Source::binary(), Config::config()) -> binary().
So, how can jsx:format(...)
return {incomplete, decoder()}
if jsx_to_json.format
returns just binary
?
This was spotted by dialyzer while writing type spec to JSEX.
The following call generates the exception shown below. Since the term is not a valid json term, the call should return false.
jsx:is_term([{a,1},a]).
** exception error: function_clause
in function jsx_verify:is_term/2 (src/jsx_verify.erl, line 48)
Displaying json null
as an atom null
in erlang incorrectly, in Erlang null
is atom undefined
Therefore makes dialyzer real angry sometimes.
The call jsx:encode([{},...]) will never return since it differs in the 1st argument from the success typing arguments: ('end_stream' | 'false' | 'null' | 'true' | binary() | ['false' | 'null' | 'true' | binary() | [any()] | number() | {_,_}] | number())
And then a screen full of warnings which disappear should I comment the clause with jsx:encode([{}])
.
I intersected with jsx when I was frustrated with tuple-wrapping of proplists to represent json objects, wrote my own encoder to show that it would work to unwrap the proplists, and then found jsx.
I've been very happy with jsx. It lets me deal with Erlang encoded json much more naturally. However, I'm having a problem with the representation of the empty object.
Using [{}] is great for pattern matching in the encoder, but the problem is that it is not so good if you are using list functions to analyze your json. The normal proplist destructuring pattern of {Key,Value} does not like {}. There are ways around this, but you have to wonder whether that workaround is worse than the tuple wrapping? For me, jsx is great because it allows more idiomatic processing of erlang encoded json.
Wouldn't it be nice to just use [] for the empty object?
But that is the representation of an empty Array.
Arrays with one or more elements can be differentiated from an an Object, for sure, but what about the empty case?
I thought about reducing empty array and object to an empty object, since the useful distinction between them in a json object is dubious. But assuming that this is not acceptable ...
What about using Erlang arrays for Json arrays? Or plain tuples?
Both have a useful access api, and can be easily converted to lists for mapping.
Is it really worth exposing the erlang representation at all -- maybe better to have a json access api and treat all json objects as an opaque object? Much of the api would mirror Erlang native, like map, foreach, foldl, foldr, etc. This would allow the implementation to utilize the most efficient encoding, decoding and access balance. E.g. a very large document might benefit from an efficient map implementation rather than proplist for objects, etc. I've found that when the structure is exposed inside of client code it can ease initial implementation, but have unpleasant consequences down the road (Iike refactoring all your code when you change libraries.)
Thoughts?
the following piece of JSON:
{
"title": "\ub108 \ud558\ub098\ub9cc"
}
fails to parse:
{incomplete,#Fun<jsx_decoder.1.85838126>}
any ideas on how to make this parse correctly? i'm using the default options and the latest version (1.4.3).
Hello,
The application cannot be started w/o nice decimal and release package cannot be created.
e.g.
application:start(jsx).
{error,{not_started,nicedecimal}}
Should the nice decimal to be treated as an optional dependencies?
Is there any specific reason why there is no jsx:to_term/1 -> {'ok', term()} | 'error'
? This forces me to use try/catch, which I usually avoid in my code.
Counterexample:
Eshell V6.1.2 (abort with ^G)
1> jsx:encode(#{}).
<<"{}">>
2> jsx:decode(v(1)).
[{}]
3>
I would expect v(2)
to return #{}
in that shell.
is_json doesn't work with large files
<<"{\n "image" : "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",\n "question" : "",\n "user" : ""\n}">>
Hello,
A list of key/value pairs causes badarg exception if it contains an undefined value.
E.g. jsx:to_json([{key, 3},{val, undefined}]).
undefined is a common atom is Erlang to identify unset values. On JavaScript its analogy is null.
I would expect that library would understand this semantic and converts undefined into "null"
Hello,
JSX is a nice and concise library, thank you!
I would like to use the numeric format for decimal numbers, unfortunately the number representation only works with erlang floating point values.
One solution I see would be to give a binary-string representation of the decimal number, boxed in a tuplewith a special key telling JSX to format it as a number, perhaps by ways of escaping the value in a special tuple, something like:
[
{<<"my_decimal_number">>, {'_json_number', <<"23.01">>}}
]
Of course, this also poses the problem of decoding a decimal number with JSX. Again, we could choose to box the string representation of a number so the choice to actually decode it to a float is left to the user. This process could be selected by an option...
Any ideas?
Best,
Cam
iex> JSEX.encode([{"userid" , "userinfo"}])
{:error,:badarg}
iex> :jsx.encode([{"userid" , "userinfo"}])
"{\"userid\":\"userinfo\"}"
Is this expected?
:jsx.decode(<<"{} {}">>)
will throw an ArgumentError exception.
it would be more useful to return a tuple with what it could decode and the rest
{Obj, Rest}
Hi,
just found incorrect decoder behaviour on splitted float number:
([email protected])40> {incomplete, F} = jsx:decode(<<"{"library": "jsx", "awesome":0">>).
{incomplete,#Fun<jsx_decoder.37.8673461>}
([email protected])41> F(<<".21}">>).
** exception error: bad argument
in function jsx_decoder:maybe_done/4
called as jsx_decoder:maybe_done(<<".21}">>,
{jsx_to_term,{[[{<<"awesome">>,0},{<<"library">>,<<"jsx">>}],
[]],
{opts,binary,false}}},
[object],
{opts,false,false,false,false,false,false,false,false,false,
false})
When using the pre_encode option while encoding an erlang dict to a json object, I get some unexpected results. Take this example:
jsx:encode([{a,1},{b,2}], [{pre_encode, fun(X) -> io:format("~p~n", [X]), X end}]).
[{a,1},{b,2}]
{a,1}
1
2
<<"{\"a\":1,\"b\":2}">>
Why does the tuple {a,1} get passed as value, is this expected behaviour?
Here's an API draft.
Creating a new stream is something gen_server-like:
{ok, Stream} = jsx_stream:init(my_callback_module, {state, initial},
[{path, [<<"result">>,<<"items">>]}]).
Any jsx decoder options (except stream
) are accepted too. User may provide multiple path options to stream multiple arrays/objects.
Feeding data
{more, Stream1} = jsx_stream:input(Stream, Data).
Callback module handles input items or key-value pairs:
-module(my_callback_module).
% called when specified path contains an array
handle_item(Path, Index, Item, RootObj, State) ->
% Path = [<<"result">>,<<"items">>] as specified by init option
% Index is integer item index in array, 1..Length
% Item is actual array item — string, number, boolean, 'none', list or object
% RootObj is root JSON object collected so far with magic 'stream' item
% in place of configured stream path. E.g.
% RootObj = [
% {<<"foo">>, 1},
% {<<"result">>, [
% {<<"a">>, <<"z">>},
% {<<"items">>, stream}
% ]}
% ]
{ok, State#state{last_index = Index}}.
% called for each key-value pair when path contains an object
handle_kv(Path, Key, Value, RootObj, State) ->
{ok, State}.
Optionally callback module may emit some events:
handle_item(Path, Index, Item, RootObj, #state{last_index = 100} = State) ->
Event = {wow, hundred, elements},
{emit, Event, State#state{last_index = Index}};
When callback emits an event, the result of input/2 changes. User needs to input empty strings to ensure buffer is completely processed:
handle_data_from_socket(Data, Stream) ->
case jsx_stream:input(Stream, Data) of
{more, Stream1} ->
{ok, Stream1};
{emit, Event, Stream1} ->
handle_event(Event),
handle_data_from_socket(<<>>, Stream1)
end.
User may perform calls to handler module:
{ItemsProcessed, Stream1} = jsx_stream:call(Stream, items_processed).
Calls are handled by callback function:
handle_call(items_processed, RootObj, #state{last_index = Index} = State) ->
{Index, State}.
Of course, state may change when handling a call.
When JSON document ends, terminate
callback is called:
terminate(end_json, RootObj, #state{last_index = Index} = State) ->
{ok, Index}.
If the document ends before the end of data, remaining bytes are returned:
case jsx_stream:input(Stream, FinalChunk) of
{end_json, LastIndex} ->
{ok, LastIndex};
{end_json, LastIndex, BytesLeft} ->
do_something(LastIndex),
handle_next_document(BytesLeft);
{more, Stream1} ->
handle_unfinished_stream(Stream1)
end.
When I do the following I get an error, this appears to be valid json to me and the other encoders/decoders work with this.
jsx:to_term(<<"{'test':'test'}">>).
jsx seems to not like the single quote.
I installed the 2.6.1 version from hex.pm (with Elixir's MIX tool):
~/D/p/c/riffer4 git:notifications ❯❯❯ mix deps.get ✱ ◼
Running dependency resolution
Dependency resolution completed successfully
jsx: v2.6.1
Compiled src/jsx_consult.erl (etc...)
Generated jsx.app
then load my project in iex:
~/D/p/c/riffer4 git:notifications ❯❯❯ iex -S mix ⏎ ✱ ◼
then:
iex(3)> :jsx.encode(%{"aps": %{"alert": "hi", "sound": "default"}})
** (ArgumentError) argument error
(jsx) src/jsx_parser.erl:129: :jsx_parser.value/4
this DOES work if I install jsx 2.1.1 instead...
Best,
Mike
I have
{erl_opts, [debug_info]}.
{deps, [
{protobuffs, "0.8.1", {git, "https://github.com/basho/erlang_protobuffs.git", {branch, "master"}}},
{jsx, "1.4.3", {git, "https://github.com/talentdeficit/jsx.git", {branch, "master"}}}
]}.
{clean_files, ["*~", "**/*~", "**/*.beam"]}.
{eunit_opts, [
verbose,
{report, {
eunit_surefire, [{dir,"."}]
}}
]}.
I tried to write both V1.4.3 and 1.4.3. But have
Cloning into 'jsx'...
Checking connectivity... done
ERROR: Dependency dir c:/workspaces/event-listener/deps/jsx failed application validation with reason:
{version_mismatch,{"c:/workspaces//event-listener/deps/jsx/src/jsx.app.src",
{expected,"1.4.3"},
{has,"2.0.1"}}}.
It just always gets the last version. If only the release name would be without 'V' prefix I guess it would work.
Hi,
I am thinking to use jsx by default instead of jiffy in one project to increase its stability. To help the user choices I would like to provides an idea about the performances changes so they can do their own choice. Is there any recent benchmark and tool to do it that would allow me to compare both? I would indeed prefer to use an existing tool instead of providing my own benchmark :)
When encoding a ~35mb proplist using jsx:encode/1
v1.4.5 takes a couple of minutes whereas v.2.1 haven't finished after 30min.
The proplist is super simple:
[ [{<<"abcd">>, <<"1234">>}, {<<"dcba">>, <<"4321">>}]
, [{<<"abcd">>, <<"1234">>}, {<<"dcba">>, <<"4321">>}]
...
]
Hi
I am blocked by decoding UTF8 json string, so post the issue here, and hope you can help me.
jsx decoder and encoder both works fine. Here it is:
> jsx:encode([{content, "中文"}]).
<<"{\"content\":[20013,25991]}">>
> jsx:decode(<<"{\"content\":[20013,25991]}">>).
[{< <"content">>,"中文"}]
I've read the code and did not find out where the UTF8 string is encoded. And below is my try
> A = unicode:characters_to_binary("{content: \"中文\"}").
<<"{content: \"中文\"}"/utf8>>
> jsx:decode(A).
** exception error: bad argument
in function jsx_decoder:object/4 (src/jsx_decoder.erl, line 262)
Can you explain me that how can I input UTF8 string?
BR
-Jack
Hi, I am not sure how to parse a stream. Do you have any example. I am trying to figure how to parse such JSON on which line would be sent one by as one as chink by the server:
{listname, [
Line0,
...
LineN
]
}
Where each line is an object
{"key": "string", "key2": integer}
Is this possible to do this with JSX? How? Are there any example around ?
A declarative, efficient, and flexible JavaScript library for building user interfaces.
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google ❤️ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.