Erlang - convert binary readable UTF

1.1k views Asked by At

I want to translate to web by YAWS info from mnesia database. Now i have code:

-define(RECORD_TYPE,      albums).
-define(RECORD_KEY_FIELD, album_id).

-record(?RECORD_TYPE,
        {?RECORD_KEY_FIELD, artist_id, album, albumpath, image}).

convert_to_json(Lines) ->
    Data = [{obj,
             [{id,     Line#?RECORD_TYPE.album_id},
              {aid,    Line#?RECORD_TYPE.artist_id},
              {path,   Line#?RECORD_TYPE.albumpath},
              {image,  Line#?RECORD_TYPE.image},
              {album,  Line#?RECORD_TYPE.album}]}
            || Line <- Lines],
    JsonData = {obj, [{data, Data}]},
    rfc4627:encode(JsonData).

handle('GET', _Arg) ->
    io:format("~n ~p:~p GET Request ~n", [?MODULE, ?LINE]),
    Records = do(qlc:q([X || X <- mnesia:table(?RECORD_TYPE)])),
    Json = convert_to_json(Records),
    io:format("~n ~p:~p GET Request Response ~p ~n", [?MODULE, ?LINE, Json]),
    {html, Json}.

do(Q)->
    F = fun() ->
                qlc:e(Q)
        end,
    {atomic, Value} = mnesia:transaction(F),
    Value.

and test.yaws file:

<html>
<head>
  <meta charset="utf-8">
</head>
<body>
<erl>
out(Arg) ->
    Method = method(Arg) ,
    io:format("~p:~p ~p Request ~n", [?MODULE, ?LINE, Method]),
    my_json:handle(Method, Arg).

method(Arg) ->
  Rec = Arg#arg.req,
  Rec#http_request.method.
</erl>
</body>
</html>

But i get binary info in YAWS output:

{"data":[{"id":8,"aid":3,"path":[[47,114,111,111,116,47,101,114,108,97,110,103,47,116,101,115,116,108,105,115,116,47,65,114,116,105,115,116,32,78,117,109,98,101,114,51,47,65,108,98,117,109,32,78,117,109,98,101,114,32,50]],"image":[[102,114,111,110,116,46,106,112,103]],"album":[65,108,98,117,109,32,78,117,109,98,101,114,32,50]},{"id":2,"aid":1,"path":[[47,114,111,111,116,47,101,114,108,97,110,103,47,116,101,115,116,108,105,115,116,47,65,114,116,105,115,116,32,78,117,109,98,101,114,49,47,65,108,98,117,109,32,78,117,109,98,101,114,32,50]],"image":[[99,111,118,101,114,46,112,110,103]],"album":[65,108,98,117,109,32,78,117,109,98,101,114,32,50]},{"id":14,"aid":5,"path":[[47,114,111,111,116,47,101,114,108,97,110,103,47,116,101,115,116,108,105,115,116,47,65,114,116,105,115,116,32,78,117,109,98,101,114,53,47,65,108,98,117,109,32,78,117,109,98,101,114,32,50]],"image":[],"album":[65,108,98,117,109,32,78,117,109,98,101,114,32,50]},{"id":12,"aid":4,"path": ..............

How i can convert this to strings?

P.S. sorry for my english and thanks for any help.

1

There are 1 answers

1
Soup in Boots On BEST ANSWER

Strings in Erlang are ambiguous because there are two ways to represent them: as a binary (<<"foo">>), or as a list of integers ("bar" = [$b, $a, $r]).

The problem you are running into is related to that second form of string (list of integers). The JSON encoder you're using doesn't know whether the list you're giving it is meant to be a string or not.

Typically JSON encoders will decide on a particular format for strings. jiffy requires you to use binaries for strings. mochijson goes the other way, and requires you to tag arrays with a tuple/atom ({array, [1, 2, 3]}).

My guess is that the module you are using requires binaries for strings (or at least for large strings).

This should fix the output for you:

convert_to_json(Lines) ->
Data = [{obj,
         [{id,     Line#?RECORD_TYPE.album_id},
          {aid,    Line#?RECORD_TYPE.artist_id},
          {path,   unicode:characters_to_binary(Line#?RECORD_TYPE.albumpath)},
          {image,  Line#?RECORD_TYPE.image},
          {album,  Line#?RECORD_TYPE.album}]}
        || Line <- Lines],
JsonData = {obj, [{data, Data}]},
rfc4627:encode(JsonData).

Note the use of unicode:characters_to_binary. This will take an iolist (a binary or list of lists/binaries/integers meant for output on a file descriptor or socket) and convert it into a flat binary using UTF8 encoding (it also assumes utf8 for input, so be careful).

See the unicode:characters_to_binary/1,2 documentation for more information.