如何手动在Erlang中创建JSON字符串

时间:2016-06-02 16:17:42

标签: json erlang

我是Erlang的新手,并注意到没有本机函数从列表创建json字符串(或者是什么?无论如何)我使用此方法在Erlang中创建json字符串但不知道它是否会不故障 .. 这是我的方法的一个例子。

-module(index).
-export([test/0]).


test()->
    Ma = "Hello World", Mb = "Hello Erlang",
    A = "{\"Messages\" : [\"" ++ Ma ++ "\", \""++Mb++"\"], \"Usernames\" : [\"Username1\", \"Username2\"]}", A.

结果是:

388> test().
"{\"Messages\" : [\"Hello World\", \"Hello Erlang\"], \"Usernames\" : [\"Username1\", \"Username2\"]}"
389> 

我认为这是预期的结果,但是当包含特殊字符时,此方法可能会出现故障,例如“Quotes,&lt;,&gt;,&amp; / \”? < / p>

我应该采取哪些预防措施来加强这种方法?

4 个答案:

答案 0 :(得分:2)

如果MaMb包含双引号或任何控制字符,则从字符串到JSON的解析将失败。这种解析可能永远不会出现在Erlang中,因为Erlang没有内置的字符串到JSON转换。

使用二进制文件(<<"I am a binary string">>)是个好主意,因为列表会占用更多资源。

我们正在使用jiffy,它被实现为NIF因此速度相当快,它允许文档构造如下:

jiffy:decode(<<"{\"foo\": \"bar\"}">>).
{[{<<"foo">>,<<"bar">>}]}
Doc = {[{foo, [<<"bing">>, 2.3, true]}]}.
{[{foo,[<<"bing">>,2.3,true]}]}
jiffy:encode(Doc).
<<"{\"foo\":[\"bing\",2.3,true]}">>

答案 1 :(得分:1)

我遇到了同样的问题,上下搜索,最后想出了自己的方法。这纯粹是为人们指明正确的方向,以为自己找到解决方案。注意:我尝试了jiffy,但是由于我正在使用rebar3,因此目前不兼容。

我正在使用MS sql服务器,所以我使用Erlang odbc模块:http://erlang.org/doc/man/odbc.html

odbc:sql_query / 2给了我<i> // For each angular application we want to host: app.Map(new PathString("/home"), home => { if (env.IsDevelopment()) { StaticFileOptions clienthome = new StaticFileOptions() { FileProvider = new PhysicalFileProvider( Path.Combine(Directory.GetCurrentDirectory(), @"home")) }; home.UseSpaStaticFiles(clienthome); home.UseSpa(spa => { spa.Options.SourcePath = "home"; // spa.Options.StartupTimeout = new TimeSpan(0, 5, 0); spa.UseAngularCliServer(npmScript: "start"); // it will use package.json & will search for start command to run }); } else { // Each map gets its own physical path for it to map the static files to. StaticFileOptions clienthome = new StaticFileOptions() { FileProvider = new PhysicalFileProvider( Path.Combine(Directory.GetCurrentDirectory(), @"home/dist")) }; // Each map its own static files otherwise it will only ever serve index.html no matter the filename home.UseSpaStaticFiles(clienthome); // Each map will call its own UseSpa where we give its own sourcepath home.UseSpa(spa => { spa.Options.StartupTimeout = new TimeSpan(0, 1, 30); spa.Options.SourcePath = "home"; spa.Options.DefaultPageStaticFileOptions = clienthome; }); } }); </i> 从这里,我可以使用{selected, Columns, Results},它是字符串和结果的列表,行的列表分别表示为元组,然后创建一些函数以输出有效的Erlang代码,从而能够正确地序列化到基于Json的代码在许多因素上。这是完整的代码:

进行初始查询:

Columns

然后输入函数是 Sql = "SELECT * FROM alloys;", Ref = connect(), case odbc:sql_query(Ref, Sql) of {selected, Columns, Results} -> set_json_from_sql(Columns, Results, []); {error, Reason} -> {error, Reason} end. ,它将调用以下函数:

set_json_from_sql/3

因此format_by_type(Item) -> if is_list(Item) -> list_to_binary(io_lib:format("~s", [Item])); is_integer(Item) -> Item; is_boolean(Item) -> io_lib:format("~a", [Item]); is_atom(Item) -> Item end. json_by_type([H], [Hc], Data) -> NewH = format_by_type(H), set_json_flatten(Data, Hc, NewH); json_by_type([H|T], [Hc|Tc], Data) -> NewH = format_by_type(H), NewData = set_json_flatten(Data, Hc, NewH), json_by_type(T, Tc, NewData). set_json_flatten(Data, Column, Row) -> ResTuple = {list_to_binary(Column), Row}, lists:flatten(Data, [ResTuple]). set_json_from_sql([], [], Data) -> jsone:encode([{<<"data">>, lists:reverse(Data)}]); set_json_from_sql(Columns, [H], Data) -> NewData = set_json_merge(H, Columns, Data), set_json_from_sql([], [], NewData); set_json_from_sql(Columns, [H|T], Data) -> NewData = set_json_merge(H, Columns, Data), set_json_from_sql(Columns, T, NewData). set_json_merge(Row, Columns, Data) -> TupleRow = json_by_type(tuple_to_list(Row), Columns, []), lists:append([TupleRow], Data). 在匹配set_json_from_sql/3之后会给您Json输出。

这里的关键点是您需要为字符串和原子调用set_json_from_sql([], [], Data)。使用list_to_binary/1将Erlang对象编码为Json:https://github.com/sile/jsone

而且,注意jsone用于匹配Erlang对象类型,是的,不是很理想,但是只要您知道数据库的类型即可工作,或者您可以增加额外的保护措施来适应这种情况。

答案 2 :(得分:0)

这对我有用

test()->
    Ma = "Hello World", Mb = "Hello Erlang",
    A = "{\"Messages\" : {{\"Ma\":\"" ++ Ma ++ "\"}, {\"Mb\":\""++Mb++"\"}}, {\"Usernames\" : {\"Username1\":\"usrname1\"}, {\"Username2\":\"usrname2\"}}", 
    io:format("~s~n",[A]).

输出

10> io:format("~s~n",[A]).
{"Messages" : {{"Ma":Hello World"}, {"Mb":Hello Erlang"}}, {"Usernames" : {"Username1":"usrname1"}, {"Username2":"usrname2"}}
ok

或使用github上的许多库之一将erlang术语转换为json。 My Tuple to JSON module is simple but effective.

答案 3 :(得分:-1)

pro

一样
-define(JSON_WRAPPER(Proplist), {Proplist}).

-spec from_list(json_proplist()) -> object().
from_list([]) -> new();
from_list(L) when is_list(L) -> ?JSON_WRAPPER(L).

-spec to_binary(atom() | string() | binary() | integer() | float() | pid() | iolist()) -> binary().
to_binary(X) when is_float(X) -> to_binary(mochinum:digits(X));
to_binary(X) when is_integer(X) -> list_to_binary(integer_to_list(X));
to_binary(X) when is_atom(X) -> list_to_binary(atom_to_list(X));
to_binary(X) when is_list(X) -> iolist_to_binary(X);
to_binary(X) when is_pid(X) -> to_binary(pid_to_list(X));
to_binary(X) when is_binary(X) -> X.

-spec recursive_from_proplist(any()) -> object().
    recursive_from_proplist([]) -> new();
    recursive_from_proplist(List) when is_list(List) ->
        case lists:all(fun is_integer/1, List) of
            'true' -> List;
            'false' ->
                from_list([{to_binary(K) ,recursive_from_proplist(V)}
                                   || {K,V} <- List
                                  ])
        end;
    recursive_from_proplist(Other) -> Other.