我试图编写一个检索JSON文件的小应用程序(它包含一个项目列表,所有这些项都有一些属性),将其内容保存到DB中,然后稍后显示其中的一些内容。我已经启动并运行了Zotonic,生成一些HTML是没有问题的。
ATM,我想弄清楚如何定义自定义资源,以及如何从DB中的JSON获取数据。当数据存在时,我应该很好,文档似乎涵盖了这个部分。
我编写了一些独立的erlang脚本来获取数据,我注意到Zotonic有一个用于解码JSON的库,所以这部分应该可以。关于在哪里放置哪一种代码或在哪里进一步查找的提示吗?
发布于 2015-09-08 11:24:33
z_db模块允许使用以下方法创建自定义表:
z_db:create_table(Table, Cols, Context).表变量是表名,它可以是一个原子,也可以是一个包含单个原子的列表。
Cols是由记录定义的列定义列表。目前,记录定义(可以在include/zotonic.hrl中找到)是:
-record(column_def, {name, type, length, is_nullable=true, default, primary_key}).有关记录的更多信息,请参见二郎档案
我在用户/站点/站点名/模型/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使用站点的上下文变量自动调用。您也可以使用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文档。
===依赖项已被更新,因此如果您从源构建直接下面的步骤不再需要===
JSON部分要复杂一些。mochijson2包括在Zotonic中,作为次要的依赖项也包括吉菲。最新版本的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"}}},现在在z:m().中运行Zotonic壳。(您必须在代码中的每次更改之后进行此操作)。
现在,在Zotonic中签入如果有一个jiffy:decode/2可用的输入jiffy: <tab>,它将显示一个可用函数的列表和它们的可用性。
要从internet运行中检索JSON文件,请执行以下操作:
{ok, {{_, 200, _}, _, Body}} = httpc:request(get, {"url-to-JSON-here", []}, [], [])这将产生随内容而变化的体。有关此呼叫的更多信息,请参见http客户端上的Erlang文档。
接下来,使用以下方法将Body的内容转换为Erlang术语:
JsonData = jiffy:decode(Body, [return_maps]).接下来要做的事情在很大程度上取决于JSON资源的结构。记住,现在一切都是二进制UTF-8编码字符串!如果您在屏幕上打印JsonData (只需在Zotonic/Erlang中输入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.关于在转换时为什么需要元组,请参见清单/1。对m_sitename:insert_items(PropList,z:c(sitename))的调用在models/m_sitename.erl中调用z_db:insert/3,但封装在一个捕获中:
insert_items(PropList,Context) ->
(catch z_db:insert(?table, PropList, Context)).好的,很长的一篇文章,但是如果你在寻找这个答案的话,这应该会让你振作起来并运行起来。
以上是在Erlang/OTP 18上用Zotonic 0.13.2进行的。
我的post 在Zotonic开发人员组中的一个repost ( JSON部分除外)。
https://stackoverflow.com/questions/32378153
复制相似问题