Source

iderlone / src / ide1_dirt.erl

Full commit
%%%-------------------------------------------------------------------
%%% @author orbitz <orbitz@osx.local>
%%% @copyright (C) 2011, orbitz
%%% @doc
%%% This implements the ideone SOAP calls, but not using SOAP.  I could
%%% not get detergent to work.
%%% @end
%%% Created : 18 Oct 2011 by orbitz <orbitz@osx.local>
%%%-------------------------------------------------------------------
-module(ide1_dirt).

-include_lib("xmerl/include/xmerl.hrl").

-define(WSDL_URL, "http://ideone.com/api/1/service.wsdl").
-define(SERVICES_URL, "http://ideone.com/api/1/service").

-define(MAP_TYPE, "ns2:Map").
-define(INT_TYPE, "xsd:int").
-define(STRING_TYPE, "xsd:string").
-define(FLOAT_TYPE, "xsd:float").
-define(BOOLEAN_TYPE, "xsd:boolean").

%% API
-export([call/2]).

%%%===================================================================
%%% API
%%%===================================================================

%%--------------------------------------------------------------------
%% @doc
%% @spec
%% @end
%%--------------------------------------------------------------------
call(Operation, Args) ->
    Request = envelope(body(operation(Operation, Args))),
    Url = ?SERVICES_URL ++ "#" ++ Operation,
    {ok, "200", _Headers, Body} = ibrowse:send_req(?SERVICES_URL,
                                                   [{"SOAPAction", Url}],
                                                   post,
                                                   Request),
    extract(Body).
    

extract(String) ->
    {Xml, _} = xmerl_scan:string(String),
    #xmlElement{content=[Envelope]} = Xml,
    #xmlElement{content=[Body]} = Envelope,
    #xmlElement{content=[Return]} = Body,
    #xmlElement{content=Top_level_map, attributes=[#xmlAttribute{value=?MAP_TYPE}]} = Return,
    xml_map_to_list(Top_level_map).

xml_map_to_list([]) ->
    [];
xml_map_to_list([#xmlElement{name=item, content=[Key_xml, Value_xml]} | Rest]) ->
    #xmlElement{name=key, content=[#xmlText{value=Key}]} = Key_xml,
    #xmlElement{name=value, content=Value, attributes=Attributes} = Value_xml,
    Parsed_value = case lists:keyfind('xsi:type', 2, Attributes) of
                       false ->
                           error;
                       #xmlAttribute{value=?MAP_TYPE} ->
                           xml_map_to_list(Value);
                       #xmlAttribute{value=?STRING_TYPE} ->
                           case Value of
                               [Value_text] ->
                                   Value_text#xmlText.value;
                               [] ->
                                   ""
                           end;
                       #xmlAttribute{value=?INT_TYPE} ->
                           [Value_text] = Value,
                           list_to_integer(Value_text#xmlText.value);
                       #xmlAttribute{value=?FLOAT_TYPE} ->
                           [Value_text] = Value,
                           convert_float(Value_text#xmlText.value);
                       #xmlAttribute{value=?BOOLEAN_TYPE} ->
                           [Value_text] = Value,
                           list_to_atom(Value_text#xmlText.value)
                   end,
    [{Key, Parsed_value} | xml_map_to_list(Rest)].


%%%===================================================================
%%% Internal functions
%%%===================================================================
envelope(Str) ->
    "<SOAP-ENV:Envelope SOAP-ENV:encodingStyle=\"http://schemas.xmlsoap.org/soap/encoding/\" " ++
        "xmlns:SOAP-ENC=\"http://schemas.xmlsoap.org/soap/encoding/\" " ++
        "xmlns:xsi=\"http://www.w3.org/1999/XMLSchema-instance\" " ++
        "xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" " ++
        "xmlns:xsd=\"http://www.w3.org/1999/XMLSchema\">" ++
        Str ++
        "</SOAP-ENV:Envelope>".

body(Str) ->
    "<SOAP-ENV:Body>" ++
        Str ++
        "</SOAP-ENV:Body>".


operation(Operation, Args) ->
    "<ns1:" ++ Operation ++
        " xmlns:ns1=\"http://ideone.com/api/1/service\" SOAP-ENC:root=\"1\">" ++
        arguments(Args) ++
        "</ns1:" ++ Operation ++ ">".

arguments(Args) ->
    arguments(1, Args).

arguments(_Index, []) ->
    "";
arguments(Index, [{Type, Value} | Rest]) ->
    Index_str = integer_to_list(Index),
    "<v" ++ Index_str ++
        " xsi:type=\"" ++ Type ++ "\">" ++
        Value ++
        "</v" ++ Index_str ++ ">" ++
        arguments(Index + 1, Rest).

                        
convert_float(Str) ->
    try list_to_float(Str) of
        Float ->
             Float
    catch
        _:_ ->
            list_to_integer(Str)
    end.