我试图编写一个小应用程序来检索JSON文件(它包含一个项目列表,它们都有一些属性),将其内容保存到数据库中,然后稍后显示其中的一些内容。我有Zotonic启动并运行,生成一些HTML是没有问题的 ATM我试图找出如何定义自定义资源以及如何从数据库中的JSON获取数据。当数据存在时,我应该没问题,文档中的部分似乎没有问题 我写了一些独立的erlang脚本来获取数据,我注意到Zotonic有一个用于解码JSON的库,因此该部分应该没问题。关于在哪里放置哪些代码或在哪里进一步查看的任何提示?
答案 0 :(得分:2)
z_db模块允许使用以下命令创建自定义表:
z_db:create_table(Table, Cols, Context).
Table变量是您的表名,可以是原子,也可以是包含单个原子的列表 Cols是列定义列表,由记录定义。目前,记录定义(您可以在include / zotonic.hrl中找到)是:
-record(column_def, {name, type, length, is_nullable=true, default, primary_key}).
有关记录的更多信息,请参阅Erlang docs on records
我放入users / sites / [sitename] / models / m_ [sitename]的示例代码.erl:
init(Context) ->
case z_db:table_exists(?table,Context) of
false ->
z_db:create_table(tablename,
[
#column_def{name=id, type="serial"},
#column_def{name=gid, type="integer", is_nullable=false},
#column_def{name=magnitude, type="real"},
#column_def{name=depth, type="real"},
#column_def{name=location, type="character varying"},
#column_def{name=time, type="integer"},
#column_def{name=date, type="integer"}
], Context);
true -> ok
end,
ok.
注意您指定的记录的哪些选项。我得到的大多数错误都是例如从指定整数字段的长度。
在网站启动时不会调用models/m_sitename:init/1
。 sitename:init/1
会被调用,所以我在那里调用init函数来确保表存在。例如:
init(Context) ->
m_sitename:init(Context).
Zotonic使用站点的Context变量自动调用它。您也可以使用z:c(sitename).
手动获取此变量。因此,如果您从其他地方拨打m_sitename:init(Context).
,您可以这样做:
m_sitename:init(z:c(sitename)).
接下来,可以使用以下命令在DB中插入:
z_db:insert(Table, PropList, Context).
其中Table又是一个原子或包含表示表名的单个原子的列表。背景与上述相同。
PropList是一个属性列表,它是一个包含由两个元素组成的元组的列表,其中第一个是原子,第二个是它的相关值/属性。例如:
PropList = [
{row, Value},
{anotherrow, AnotherValue}
].
Table = tablename.
Context = z:c(sitename).
z_db:insert(Table, PropList, Context).
有关财产清单的详情,请参阅Erlang docs on Property Lists。
===依赖关系已更新,因此如果您从源代码构建,则不再需要以下步骤===
JSON部分有点棘手。 Zotonic包含mochijson2和辅助依赖jiffy。最新版本的jiffy包含jiffy:decode / 2,它允许您将地图指定为返回类型。比标准{struct, {struct, <<"">>}}
怪物更具可读性。要更新到最新版本,请修改deps/twerl/rebar.config
中显示
{jiffy, ".*", {git, "https://github.com/davisp/jiffy.git", {tag, "0.8.3"}}},
到
{jiffy, ".*", {git, "https://github.com/davisp/jiffy.git", {tag, "0.14.3"}}},
现在在Zotonic shell中运行z:m().
。 (您必须在代码中的每次更改后执行此操作)
现在通过键入jiffy: <tab>
检查Zotonic shell是否存在jiffy:decode / 2,它将显示可用功能及其arity的列表。
从互联网运行中检索JSON文件:
{ok, {{_, 200, _}, _, Body}} = httpc:request(get, {"url-to-JSON-here", []}, [], [])
这将产生带有内容的变量Body。有关此次通话的详情,请参阅Erlang docs on http client。
接下来将Body的内容转换为Erlang术语:
JsonData = jiffy:decode(Body, [return_maps]).
接下来要做的事情很大程度上取决于JSON资源的结构。请记住,现在一切都是二进制UTF-8编码的字符串!如果您将JsonData打印到屏幕(只需在Zotonic / Erlang shell中输入JsonData.
),您会看到很多#map{<<"key"", <<"Value">>}
这个。
我的数据是嵌套的,所以我不得不提取所需的数据:
[{_,ItemList}|_] = ListData.
这给了我一张地图列表,为了将它们作为单独的项目处理,我使用了以下功能:
get_maps([]) ->
done;
get_maps([First|Rest]) ->
Map = maps:get(<<"properties">>, First),
case is_map(Map) of
true ->
map_to_proplist(Map),
get_maps(Rest);
false -> done
end,
done;
get_maps(_) ->
done.
您可能还记得,z_db:insert/3
函数需要一个属性列表来填充行,以便调用map_to_proplist/1
的内容。这个函数的外观完全取决于数据的外观,但这里的例子对我有用:
map_to_proplist(Map) ->
case is_map(Map) of
true ->
{Value1,_} = string:to_integer(binary_to_list(maps:get(<<"key1">>, Map))),
{Value2,_} = string:to_float(binary_to_list(maps:get(<<"key2">>, Map))),
{Value3,_} = string:to_float(binary_to_list(maps:get(<<"key3">>, Map))),
Value4 = binary_to_list(maps:get(<<"key4">>, Map)),
{Value5,_} = string:to_integer(binary_to_list(maps:get(<<"key5">>, Map))),
{Value6,_} = string:to_integer(binary_to_list(maps:get(<<"key6">>, Map))),
PropList = [{rowname1, Value1}, {rowname2, Value2}, {rowname3, Value3}, {rowname4, Value4}, {rowname5, Value5}, {rowname6, Value6}],
m_sitename:insert_items(PropList,z:c(sitename)),
ok;
false ->
ok
end.
请参阅documentation on string:to_list/1了解为什么在投射时需要元组。对m_sitename:insert_items(PropList,z:c(sitename))
的调用调用models/m_sitename.erl
中的z_db:insert / 3,但包含在catch中:
insert_items(PropList,Context) ->
(catch z_db:insert(?table, PropList, Context)).
好的,相当长的帖子但如果您正在寻找这个答案,这应该可以帮助您正常运行。
以上是在Erlang / OTP 18上用Zotonic 0.13.2完成的。
我的帖子in the Zotonic Developers group的重新发布(JSON部分除外)。