Git Product home page Git Product logo

jsx's Introduction

i have no good ideas for this yet

jsx's People

Contributors

arcusfelis avatar c-bik avatar dumbbell avatar eskuat avatar etrepum avatar filmor avatar fogfish avatar g-andrade avatar getong avatar hachreak avatar jeremyjh avatar kianmeng avatar kiela avatar kpy3 avatar ledest avatar liveforeverx avatar macintux avatar maxlapshin avatar mbuhot avatar okeuday avatar patrickgombert avatar paulo-ferraz-oliveira avatar philipcristiano avatar ratopi avatar sergey-ivlev avatar srstrong avatar talentdeficit avatar tjweir avatar tsloughter avatar yjh0502 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

jsx's Issues

Can`t encode datetime

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)

badarg in jsx_parse

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 Url Encodes Fail

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

http://github.com/treetopllc/ephp

json "unicode" vagueness

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

Erlang R17 has maps

Please provide some way to convert json objects into Erlang maps directly.

Map encoding broken

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,

Convert atoms to strings

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

support for `nil` atom?

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

coming changes

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 :)

orddict support?

What do you think about (optionally) converting json objects into orddicts as opposed to plain proplists?

Please support serializing process IDs

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.

Missing Return Type in Spec

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.

Jsx does not like a list of chars as the key of a map or properlist

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,

{error, badarg} instead of badarg exception wanted

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

New tag request

Any chance of a new tag soon?
Could really use fix of #71 to finally shut up my dialyzer warnings...

ISO8601 datetime generation in JSON

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

jsx:format typesec

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.

exception when calling is_term

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)

The json_term() spec is inconsistent with the README and current implementation

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([{}]).

representation of objects and arrays

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?

failure to parse multibyte value

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).

application config tweak

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?

  • Dmitry

is_json doesn't work with large files

is_json doesn't work with large files

<<"{\n "image" : "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",\n "question" : "",\n "user" : ""\n}">>

undefined causes badarg

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"

  • Dmitry

Decimal number support, or workaround

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

Weird encode issue

iex> JSEX.encode([{"userid" , "userinfo"}])
{:error,:badarg}
iex> :jsx.encode([{"userid" , "userinfo"}])
"{\"userid\":\"userinfo\"}"

Is this expected?

term strictness

I am using jsx as of 6234e4a and it works with term input that is not exactly strict,
for example, jsx:term_to_json(<<"a">>).

I tried upgrading to the latest version (ed33626) and it now would not accept an input that's neither a list nor a proplist.

Any plans on allowing old behaviour?

Bad argument on splitted float

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})

Unexpected values passed to pre_encode fun when using jsx:encode/2

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?

Implement high-level streaming API

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.

Single Quote

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.

Maps get argument error in Elixir environment

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

How to add specific version of jsx as a dependency in rebar.

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.

any recent benchmark in using jsx vs jiffy?

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 :)

v2.1 is eon times slower than v1.4.5 when encoding large proplists

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">>}]
...
]

How can I input UTF8 string when decoding json

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

how to parse a stream

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 ?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.