【问题标题】:how to create JSON string in Erlang manually如何在 Erlang 中手动创建 JSON 字符串
【发布时间】:2021-01-04 00:54:57
【问题描述】:

我是 Erlang 的新手,注意到没有从列表创建 json 字符串的本机函数(或者有吗?)。我用这个方法在 Erlang 中创建 json 字符串,但不知道会不会ma​​lfunction

这是我的方法的一个例子:

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

我认为这是预期的结果,但是当包含特殊字符时,此方法是否有可能出现故障,例如:<, >, & / \ " ?

我应该采取什么预防措施来使这种方法更强大?

【问题讨论】:

标签: json erlang


【解决方案1】:

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

【讨论】:

  • 这是一个非常令人印象深刻的高性能纯 Erlang JSON 库jsone
  • @Hynek-Pichi-Vychodil jsone 是纯 erlang,因此根据定义比 NIF 慢!
  • @ElvinArens:是的,但有一点点差距。这就是我写令人印象深刻的原因。
【解决方案2】:

我也遇到了同样的问题,四处寻找,最后想出了自己的方法。这纯粹只是为人们指出正确的方向,为自己找到解决方案。注意:我尝试过 jiffy,但由于我使用的是 rebar3,它目前不兼容。

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

odbc:sql_query/2 还给我{selected, Columns, Results} 从这里我可以获取Columns,它是一个字符串列表和结果,一个行列表表示为一个元组,然后创建一些函数来输出有效的 Erlang 代码,以便能够基于一个正确序列化到 Json因素的数量。这是完整的代码:

进行初始查询:

  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 在匹配 set_json_from_sql([], [], Data) 后会为您提供 Json 输出。

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

并且,注意format_by_type/1 用于匹配 Erlang 对象类型,是的,并不理想,但只要您知道数据库的类型,或者您可以增加额外的防护来适应这种情况,它就可以工作。

【讨论】:

    【解决方案3】:

    这对我有用

    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.

    【讨论】:

      【解决方案4】:

      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.
      

      【讨论】:

      • 因此,您建议不要使用编写良好、经过测试和性能优化的 JSON 库,而是推荐具有奇怪依赖关系的半生不熟的临时代码 (mochinum)。不,谢谢。
      猜你喜欢
      • 1970-01-01
      • 2010-11-06
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-02-12
      相关资源
      最近更新 更多