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

tag5nh1u  于 2022-12-08  发布在  Erlang
关注(0)|答案(4)|浏览(152)

我是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>

我认为这是预期的结果,但当包含特殊字符时,此方法是否有可能出现故障,例如:<, >, & / \ " ?
我应该采取什么预防措施来使这种方法更强大?

zsohkypk

zsohkypk1#

如果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]}">>
a2mppw5e

a2mppw5e2#

I had this very same problem, searched high and low and in the end came up with my own method. This is purely just pointing people in the right directions to finding a solution for themselves. Note: I tried jiffy but as I'm using rebar3 it's not currently compatible.
Im using MS sql server so i use the Erlang odbc module: http://erlang.org/doc/man/odbc.html
The odbc:sql_query/2 gives me back {selected, Columns, Results} From here i can take the Columns which is a list of strings & the Results, a list of rows represented each as a tuple, then create a few functions to output valid Erlang code to be able to serialize correctly to Json based on a number of factors. Here's the full code:
make the initial query:

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.

Then the input function is set_json_from_sql/3 that calls the below functions:

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

So set_json_from_sql/3 gives you your Json output after matching set_json_from_sql([], [], Data) .
The key points here are that you need to call list_to_binary/1 for strings & atoms. Use jsone to encode Erlang objects to Json: https://github.com/sile/jsone
And, notice format_by_type/1 is used to match against Erlang object types, yes not ideal but works as long as you are aware of your DB's types or you can increase the extra guards to accommodate this.

omtl5h9j

omtl5h9j3#

这对我有用

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.

zsbz8rwp

zsbz8rwp4#

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.

相关问题