【问题标题】:ERLANG with JSON带有 JSON 的 ERLANG
【发布时间】:2019-01-25 06:38:36
【问题描述】:

我在erlang 中运行以下命令,

os:cmd("curl -k -X GET http://10.210.12.154:10065/iot/get/task").

它会给出这样的 JSON 输出,

{"data":[
    {"id":1,"task":"Turn on the bulb when the temperature in greater than 28","working_condition":1,"depending_value":"Temperature","action":"123"},
    {"id":2,"task":"Trun on the second bulb when the temperature is greater than 30","working_condition":0,"depending_value":"Temperature","action":"124"}
]}

我想将此数据分类为 Id、task、depending_value、action。这就像把它们放在一张桌子上。我想轻松找到 Id=1 的依赖值、工作条件和操作。我该怎么做?

【问题讨论】:

  • {\"status\":200,\"data\":[{\"id\":1,\"task\":\"温度大于大于 28\",\"working_condition\":1,\"depending_value\":\"Temperature\",\"action\":\"123\"},{\"id\":2,\"task \":\"当温度大于30时开启第二个灯泡\",\"working_condition\":0,\"depending_value\":\"Temperature\",\"action\":\"124\ "}]}"
  • 您是否尝试过使用像jsx 这样的JSON 解析库之一?尝试一下并发布您完成的代码,然后您可以获得更具体的帮助。
  • 我试过 rfc4627。这是代码。
  • -模块(任务)。 -出口([run_forever/0])。 run_forever() -> Arg = os:cmd("curl -k -X GET 10.210.12.154:10065/iot/get/task"), io:fwrite("~p~n",[Arg]), case decode_json(Arg) of {ok, Data} -> case catch rfc4627:get_field(Data, "id") of {ok, Id} -> case catch rfc4627:get_field(Data, "working_condition") of {ok, Wc} -> io:fwrite("~p~ n",[Wc]), end end; run_forever().

标签: json rest api erlang


【解决方案1】:

它会给出这样的 JSON 输出。

{"data":[{"id":1,"t ...

高度怀疑。文档说os:cmd() 返回一个字符串,它不以{ 开头。另请注意,字符串甚至不是 erlang 数据类型,而是双引号是创建 list of integers 的快捷方式,整数列表在您的情况下并不是非常有用。

这里有两个选项:

  1. os:cmd() 返回的整数列表上调用list_to_binary() 以转换为binary

  2. 不要使用os:cmd(),而是使用erlang http 客户端,例如hackney,它将json 作为binary 返回。

您需要二进制文件的原因是因为您可以使用 erlang json 模块,例如 jsx,将二进制文件转换为 erlang 映射(这可能是您所追求的?)。

这就是它的样子:

3> Json = <<"{\"data\": [{\"x\": 1, \"y\": 2}, {\"a\": 3, \"b\": 4}] }">>. 
<<"{\"data\": [{\"x\": 1, \"y\": 2}, {\"a\": 3, \"b\": 4}] }">>

4> Map = jsx:decode(Json, [return_maps]).
#{<<"data">> =>
      [#{<<"x">> => 1,<<"y">> => 2},#{<<"a">> => 3,<<"b">> => 4}]}

5> Data = maps:get(<<"data">>, Map).     
[#{<<"x">> => 1,<<"y">> => 2},#{<<"a">> => 3,<<"b">> => 4}]

6> InnerMap1 = hd(Data).   
#{<<"x">> => 1,<<"y">> => 2}

7> maps:get(<<"x">>, InnerMap1).
1

...把它们放在桌子上。我想轻松找到 取决于 Id=1 的值、工作条件和操作。

Erlang 有多种表实现:etsdetsmnesia。这是一个ets 示例:

-module(my).
-compile(export_all).

get_tasks() ->
    Method = get,

    %See description of this awesome website below.
    URL = <<"https://my-json-server.typicode.com/7stud/json_server/db">>,

    Headers = [],
    Payload = <<>>,
    Options = [],

    {ok, 200, _RespHeaders, ClientRef} =
        hackney:request(Method, URL, Headers, Payload, Options),
    {ok, Body} = hackney:body(ClientRef),
    %{ok, Body} = file:read_file('json/json.txt'),  %Or, for testing you can paste the json in a file (without the outer quotes), and read_file() will return a binary.

    Map = jsx:decode(Body, [return_maps]),
    _Tasks = maps:get(<<"data">>, Map).

create_table(TableName, Tuples) ->
    ets:new(TableName, [set, named_table]),
    insert(TableName, Tuples).

insert(_Table, []) ->
    ok;
insert(Table, [Tuple|Tuples]) ->
    #{<<"id">> := Id} = Tuple,
    ets:insert(Table, {Id, Tuple}),
    insert(Table, Tuples).

retrieve_task(TableName, Id) ->
    [{_Id, Task}] = ets:lookup(TableName, Id), 
    Task.

默认情况下,etsset 类型表确保插入的元组中的第一个位置是唯一键(或者您可以显式指定元组中的另一个位置作为唯一键)。

** 如果你有一个 github 帐户,我发现了一个非常酷的网站,它允许你将一个 json 文件放在 github 上的一个新存储库中,该网站会将该文件作为 json 提供.查看https://my-json-server.typicode.com

如何

  1. 在 GitHub 上创建存储库(&lt;your-username&gt;/&lt;your-repo&gt;)
  2. 创建一个db.json 文件[在存储库中]。
  3. 访问https://my-json-server.typicode.com/&lt;your-username&gt;/&lt;your-repo&gt; 访问您的服务器

您可以在代码中看到我正在使用的 url,可以通过单击提供的服务器页面上的链接并在 Web 浏览器的地址栏中复制该 url 来获得。

在外壳中:

.../myapp$ rebar3 shell
===> Verifying dependencies...
===> Compiling myapp
src/my.erl:2: Warning: export_all flag enabled - all functions will be exported

Erlang/OTP 20 [erts-9.3] [source] [64-bit] [smp:4:4] [ds:4:4:10] [async-threads:1] [hipe] [kernel-poll:false]
Eshell V9.3  (abort with ^G)

1> ===> The rebar3 shell is a development tool; to deploy applications in production, consider using releases (http://www.rebar3.org/docs/releases) 
===> Booted unicode_util_compat
===> Booted idna
===> Booted mimerl
===> Booted certifi
===> Booted ssl_verify_fun
===> Booted metrics
===> Booted hackney

1> Tasks = my:get_tasks().     
[#{<<"action">> => <<"123">>,
   <<"depending_value">> => <<"Temperature">>,<<"id">> => 1,
   <<"task">> =>
       <<"Turn on the bulb when the temperature in greater than 28">>,
   <<"working_condition">> => 1},
 #{<<"action">> => <<"124">>,
   <<"depending_value">> => <<"Temperature">>,<<"id">> => 2,
   <<"task">> =>
       <<"Trun on the second bulb when the temperature is greater than 30">>,
   <<"working_condition">> => 0}]

2> my:create_table(tasks, Tasks).
ok

3> my:retrieve_task(tasks, 1).   
#{<<"action">> => <<"123">>,
  <<"depending_value">> => <<"Temperature">>,<<"id">> => 1,
  <<"task">> =>
      <<"Turn on the bulb when the temperature in greater than 28">>,
  <<"working_condition">> => 1}

4> my:retrieve_task(tasks, 2).   
#{<<"action">> => <<"124">>,
  <<"depending_value">> => <<"Temperature">>,<<"id">> => 2,
  <<"task">> =>
      <<"Trun on the second bulb when the temperature is greater than 30">>,
  <<"working_condition">> => 0}

5> my:retrieve_task(tasks, 3).
** exception error: no match of right hand side value []
     in function  my:retrieve_task/2 (/Users/7stud/erlang_programs/old/myapp/src/my.erl, line 58)

6> 

请注意,id 位于其中一行末尾的右侧。此外,如果您在 shell 中遇到任何错误,shell 将自动重新启动一个新进程,并且 ets 表将被销毁,因此您必须重新创建它。

rebar.config:

{erl_opts, [debug_info]}.
{deps, [
    {jsx, "2.8.0"},
    {hackney, ".*", {git, "git://github.com/benoitc/hackney.git", {branch, "master"}}}
]}.
{shell, [{apps, [hackney]}]}. % This causes the shell to automatically start the listed apps.  See https://stackoverflow.com/questions/40211752/how-to-get-an-erlang-app-to-run-at-starting-rebar3/45361175#comment95565011_45361175

src/myapp.app.src:

{application, 'myapp',
 [{description, "An OTP application"},
  {vsn, "0.1.0"},
  {registered, []},
  {mod, {'myapp_app', []}},
  {applications,
   [kernel,
    stdlib
   ]},
  {env,[]},
  {modules, []},

  {contributors, []},
  {licenses, []},
  {links, []}
 ]}.

但是,根据rebar3 dependencies docs

您应该将每个依赖项添加到您的应用或 app.src 文件中:

所以,我猜src/myapp.app.src 应该是这样的:

{application, 'myapp',
 [{description, "An OTP application"},
  {vsn, "0.1.0"},
  {registered, []},
  {mod, {'myapp_app', []}},
  {applications,
   [kernel,
    stdlib,
    jsx,
    hackney
   ]},
  {env,[]},
  {modules, []},

  {contributors, []},
  {licenses, []},
  {links, []}
 ]}.

【讨论】:

  • 问题中提供的字符串是 JSON 格式,当然不是 Erlang 元组。它用冒号分隔属性名称和值——在 Erlang 中没有这样的东西。
  • 我认为很明显OP包含了os:cmd返回的字符串的contents。没有什么“高度怀疑”的。
  • 现在的输出是这样的......我下一步该怎么做....... {\"status\":200,\"data\":[{\"id \":1,\"task\":\"温度大于28时打开灯泡\",\"working_condition\":1,\"depending_value\":\"Temperature\",\"action \":\"123\"},{\"id\":2,\"task\":\"温度大于30时开启第二个灯泡\",\"working_condition\":0, \"depending_value\":\"温度\",\"动作\":\"124\"}]}"
  • 我只想写一个文件来完成这项工作。有可能吗?
  • @ChathuraJayawardane,我不这么认为。您必须学习使用 rebar3 才能使用 3rd 方 erlang 应用程序,例如 hackney 和 jsx。在这里查看最简单的方式:stackoverflow.com/questions/34278982/…
猜你喜欢
  • 2012-03-26
  • 2016-02-13
  • 2023-03-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-03-01
  • 2021-06-14
相关资源
最近更新 更多