<div><br></div><div>I have the following problem:</div><div><br></div><div>I have  complex data structure that I want to send back and forward</div><div>between Erlang and a browser - what's the best way to do this?</div>
<div><br></div><div>This should be very simple - but the simplest solution I have found is</div><div>not entirely obvious. So I was wondering if this is the</div><div>best solution, and welcome any suggestions for improvement.</div>
<div><br></div><div>The problem is subject to the following constraints:</div><div><br></div><div>   1) I want the data structure to be the same after it has been on </div><div>      a "round-trip" from erlang -> browser -> erlang</div>
<div><br></div><div>   2) I want to use publicly available libraries that are in-use and</div><div>      maintained.</div><div><br></div><div>Here's the solution I use at the moment. I've chosen JSON for data transport,</div>
<div>jquery in the browser, the Google chrome browser, and mochiweb.</div><div><br></div><div>(( is their a better choice - should I use something other than JSON for the encoding, if so what,</div><div>Bert?, something else???) </div>
<div><br></div><div><br></div><div>Step 1</div><div>======</div><div><br></div><div>In the browser I request data from Erlang</div><div><br></div><div>I make a button in html with button id="b">click</button> and hook an event onto it with</div>
<div><br></div><div>jquery:</div><div><br></div><div>    $("#b").click(test_json);</div><div><br></div><div>    function test_json(){</div><div>    $.ajax({url:"get_term",</div><div><span class="Apple-tab-span" style="white-space:pre">   </span>    dataType:'json',</div>
<div><span class="Apple-tab-span" style="white-space:pre">      </span>    success:function(x){</div><div><span class="Apple-tab-span" style="white-space:pre">             </span>handle(x);</div><div><span class="Apple-tab-span" style="white-space:pre">           </span>}</div>
<div><span class="Apple-tab-span" style="white-space:pre">      </span>   });</div><div>    };</div><div><br></div><div>When I click the button a "get_term" messages is sent to an erlang mochiweb server.</div><div><br>
</div><div>Step 2</div><div>======</div><div><br></div><div>I make a mochiweb sevrer to reply, which looks like this:</div><div><br></div><div>start_server() -></div><div>    mochiweb_http:start([{name,?MODULE},</div><div>
<span class="Apple-tab-span" style="white-space:pre">                 </span> {loop,{?MODULE,loop}},</div><div><span class="Apple-tab-span" style="white-space:pre">                      </span> {port, 2234}]).</div><div>loop(Req) -></div><div>    handle(Req:get(path), Req).</div>
<div><br></div><div>handle("/get_term", Req) -></div><div>    X = [{struct,[{string,<<"joe">>},</div><div><span class="Apple-tab-span" style="white-space:pre">            </span>  {int,42},</div><div>
<span class="Apple-tab-span" style="white-space:pre">         </span>  {float,3.14159}]},</div><div><span class="Apple-tab-span" style="white-space:pre"> </span> 123,</div><div><span class="Apple-tab-span" style="white-space:pre">        </span> <<"a string">>],</div>
<div>    E = mochijson2:encode(X),</div><div>    Req:ok({mochiweb_mime:from_extension(".js"),[],E});</div><div><br></div><div>The complex term is in the variable X. This is encoded with </div><div>mochijson2:encode(X)</div>
<div><br></div><div>Step 3</div><div>======</div><div><br></div><div>handle(x) is called in the browser - remember step 1? - handle is defined like this:</div><div><br></div><div>function handle(x){</div><div>    console.log('got',x);</div>
<div>    $.ajax({url:'echo',</div><div><span class="Apple-tab-span" style="white-space:pre">        </span>    data:JSON.stringify(x), </div><div><span class="Apple-tab-span" style="white-space:pre"> </span>    success:function(y){</div>
<div><span class="Apple-tab-span" style="white-space:pre">              </span>$("#ret").html(y);</div><div><span class="Apple-tab-span" style="white-space:pre"> </span>    }});</div><div>};</div><div><br></div><div>This prints the reply on the console and sends it back to Erlang.</div>
<div>To do this I call JSON.stringify(x). This seems to work correctly.</div><div><br></div><div>Step 4</div><div>======</div><div><br></div><div>Receive the reply in Erlang. I add an addition clause to handle/2,</div><div>
<br></div><div>handle("/echo", Req) -></div><div>    X = json_to_erl(Req),</div><div>    io:format("~p~n",[X]),</div><div>    ...</div><div><br></div><div>where:</div><div><br></div><div>json_to_erl(Req) -></div>
<div>    [{Str,[]}] = Req:parse_qs(),</div><div>    mochijson2:decode(Str).</div><div><br></div><div>This however is not quite right. The decoded version has changed</div><div>all the keys in the hashmap from atoms to binaries.</div>
<div><br></div><div>So when I send {struct, [{a,123}]} I get back {struct,[{<<"a">>,123}]}</div><div><br></div><div>This is easy to fix with:</div><div><br></div><div>munge({struct,L}) -></div><div>
    {struct,[{list_to_atom(binary_to_list(I)), munge(J)} || {I,J}<-L]};</div><div>munge(L) when is_list(L) -></div><div>    [munge(I) || I <- L];</div><div>munge(X) -> X.</div><div><br></div><div>so  the final version is:</div>
<div><br></div><div>json_to_erl(Req) -></div><div>    [{Str,[]}] = Req:parse_qs(),</div><div>    munge(mochijson2:decode(Str)).</div><div><br></div><div>and amazingly the round trip succeeds. Why am I amazed? - the float</div>
<div>got reconstructed with full precision, and the order of the keys in</div><div>the hashmap was preserved.</div><div><br></div><div>To summarize:</div><div><br></div><div>    1) mochijson2:encode(X) to term an erlang term to JSON</div>
<div><br></div><div>    2) use the jquery function ajax to receive the term</div><div>       called like this:</div><div><br></div><div>       $.ajax({url:..., </div><div>               dataType:'json',</div><div>
               success:function(x){ ...}</div><div>              }).</div><div><br></div><div>    3) use the jquery function ajax to send a javascript object x like this:</div><div>       </div><div>       $.ajax({url:...</div>
<div>               data:JSON.stringify(x),</div><div>               ...})</div><div><br></div><div>     4) decode the object in erlang with (assuming Str is the return value of</div><div>        JSON.stringify(x))</div><div>
 </div><div>          munge(mochijson2:decode(Str))</div><div><br></div><div>So far my Erlang strings only contain simple english alphabetic characters, </div><div>so I don't really know what will happen if we get into utf8 encoded unicode</div>
<div>strings.</div><div><br></div>