Joe Williams home
This past weekend I decided to work on another erlang project. Similar to the last one it revolves around parsing XML. This time I am using xmerl to parse Amazon wishlist data. I used a number of examples (here, here and here) and a mailing list post to figure this one out and I must say that it is much more complicated that the first. The program accepts an email address and then gives you a list of items on all of your wishlists. So here it is. First, I define the URLs we need to grab the wishlists from Amazon web services.
-module(amazon_wishlist_xmerl). -export([get_wishlist/1]). -include_lib("xmerl/include/xmerl.hrl"). -define(LIST_ID_URL, "" "Service=AWSECommerceService&Operation=ListSearch" "&SubscriptionId=YOURAWSIDHERE&" "&ListType=WishList" "&Email="). -define(LIST_URL, "" "Service=AWSECommerceService&Operation=ListLookup" "&SubscriptionId=YOURAWSIDHERE" "&ListType=WishList" "&ResponseGroup=ListItems" "&ListId=").
I then use an anonymous function to get the value that I need from the XML input using a list comprehension.
-define(Val(X), (fun() -> [ V || #xmlElement{ content = [#xmlText{value = V}|_]} <- X] end)()).
I then have two functions which first build the URL, then use http:request to get the XML, next it checks to see if the HTTP status code is good (200 rather than 404 or etc). Each function then scans the XML for the appropriate value using the above defined anonymous function. build_list_id returns the wishlist ID's to build_wishlist per the list map in get_wishlist. build_wishlist then prints each item title using a list comprehension.
build_list_id(Email_addr) -> List_id_url = ?LIST_ID_URL ++ Email_addr, { ok, { _Status, _Headers, Body }} = http:request(List_id_url), check_status(_Status), { Xml, _Rest } = xmerl_scan:string(Body), ?Val(xmerl_xpath:string("//ListId", Xml)). build_wishlist(List_id) -> List_url = ?LIST_URL ++ List_id, { ok, { _Status, _Headers, Body }} = http:request(List_url), check_status(_Status), { Xml, _Rest } = xmerl_scan:string(Body), Titles = ?Val(xmerl_xpath:string("//Title", Xml)), [ io:format("~p~n", [T]) || T <- Titles ]. check_status(_Status) -> case _Status of {"HTTP/1.1",200,"OK"} -> ok; _ -> io:format("Error! Bad Status Code. ~p ~n", [_Status]), exit(not_200_status_code) end. get_wishlist(Email_addr) -> lists:map( fun build_wishlist/1, build_list_id(Email_addr) ).
Here's what it looks like when I run it against my wishlists.
[zeusfaber@der-dieb amazon_wishlist_xmerl]$ erl Erlang (BEAM) emulator version 5.6.4 [source] [64-bit] [smp:2] [async-threads:0] [hipe] [kernel-poll:false] Eshell V5.6.4 (abort with ^G) 1> inets:start(). ok 2> c(amazon_wishlist_xmerl). {ok,amazon_wishlist_xmerl} 3> amazon_wishlist_xmerl:get_wishlist("MYEMAILADDRESS"). "Erlang Programming" "Notes on the Underground, New Edition: An Essay on Technology, Society, and the Imagination" "Programming Embedded Systems: With C and GNU Development Tools, 2nd Edition" "The Supply and Demand Paradox: A Treatise on Economics" "The Post-American World" "Building Clustered Linux Systems (HP Professional Series)" "High Performance Computing (RISC Architectures, Optimization " "Metal Gear Solid Portable Ops" "House of Bush, House of Saud: The Secret Relationship Between the World's Two Most Powerful Dynasties" "The long, lonely leap," "Playstation 3 80GB" "Clumsy Crab (Tiger Tales)" "Stuff: The Secret Lives of Everyday Things (New Report, No 4)" [[ok,ok,ok,ok,ok,ok,ok,ok,ok,ok],[ok,ok],[ok],[]]
Seems to work well. For my next project I think I will attempt to replicate the functionality of this program using erlsom's SAX parser rather than xmerl. I'll post it if/when I get it done.
Fork me on GitHub