I wrote this with two aims, to learn XML/XSLT/XPath, and to learn SOAP. I gave up on SOAP and cheated by using the excellent Net::Amazon module :-)
The script takes an xml file as input, and produces another xml file containing additional information from amazon, including cover images where available. This is then processed for display using an XML stylesheet.
In order to use this, you will need the following sample files:-
In addition, you will need an Amazon Developer token, available at
www.amazon.com/soap/.
Right now, the script can look up information on books and dvds using amazon. The root node is <wishlist/>, which can contain <book/>, <cd/> and <dvd/> child elements. In order to gather data from Amazon, add a child element <amazonAsin/>, and possibly <amazonLocale/> if the item is contained in a different Amazon locale (not all items appear in the us locale!)
See the script
in action
Code critique, and any other feedback good or bad is most definately welcome, as my perl is a little rusty. I probably ought to use XML::DOM instead of XML::Simple.
Update 22/07/2004: Return correct detailUrl (locale-dependant)
#!/usr/bin/perl
###
### Configuration
###
# URL of wishlist source
my $wishlist_url = 'http://chaz6.com/static/content/wishlist.xml';
# Amazon developer token
my $amazon_token = '[Amazon Developer Token]';
# Default locale
# Possible values: us,uk,de,jp
my $amazon_locale = 'us';
###
### Modules
###
use strict;
use CGI;
use Cache::File;
use LWP::Simple;
use XML::Simple;
use Net::Amazon;
###
### Main
###
# Create a cache object
my $cache = Cache::File->new(
cache_root => '/tmp/mycache',
default_expires => '1 day',
);
# Fetch the wishlist
my $wishlist_src = get($wishlist_url);
# Read the wishlist into an XML object
my $wishlist = XMLin($wishlist_src, KeepRoot => 1);
# Create a Net::Amazon object
my $amazon;
my $ua = Net::Amazon->new(token => $amazon_token, cache => $cache);
$amazon->{'us'} = Net::Amazon->new(token => $amazon_token, cache => $c
+ache);
$amazon->{'uk'} = Net::Amazon->new(token => $amazon_token, cache => $c
+ache, locale => 'uk');
$amazon->{'jp'} = Net::Amazon->new(token => $amazon_token, cache => $c
+ache, locale => 'jp');
$amazon->{'de'} = Net::Amazon->new(token => $amazon_token, cache => $c
+ache, locale => 'de');
######################################################################
+#####
################################## Books #############################
+#####
######################################################################
+#####
# Process all the book nodes
my $books = $wishlist->{'wishlist'}->{'book'};
# Remove the old book nodes
$wishlist->{'wishlist'}->{'book'} = undef;
# Create the new node
my @newbooks;
foreach my $book (@{$books}){
my $bookinfo;
# Search for book information
my $locale = $book->{'amazonLocale'} || $amazon_locale;
# Prefer to use the Amazon ASIN
if($book->{'amazonAsin'}) {
$bookinfo = getBookInfo(asin => $book->{'amazonAsin'}, locale
+=> $locale);
# Fall back to ISBN
} elsif ($book->{'isbn'}) {
$bookinfo = getBookInfo(isbn => $book->{'isbn'}, locale => $lo
+cale);
}
$book->{'imageUrl'} ||= $bookinfo->{'imageUrl'};
$book->{'title'} ||= $bookinfo->{'title'};
$book->{'publisher'} ||= $bookinfo->{'publisher'};
$book->{'year'} ||= $bookinfo->{'year'};
$book->{'media'} ||= $bookinfo->{'media'};
$book->{'released'} ||= $bookinfo->{'released'};
$book->{'imageUrlLarge'} ||= $bookinfo->{'imageUrlLarge'};
$book->{'detailUrl'} ||= $bookinfo->{'detailUrl'};
# Insert the new node into the tree
push (@newbooks,$book);
}
# Insert the new book nodes into the wishlist
$wishlist->{'wishlist'}->{'book'} = [@newbooks];
######################################################################
+#####
################################## dvds ##############################
+####
######################################################################
+#####
# Process all the dvd nodes
my $dvds = $wishlist->{'wishlist'}->{'dvd'};
# Remove the old dvd nodes
$wishlist->{'wishlist'}->{'dvd'} = undef;
# Create the new node
my @newdvds;
foreach my $dvd (@{$dvds}){
my $dvdinfo;
my $locale = $dvd->{'amazonLocale'} || $amazon_locale;
# Search for dvd information
if($dvd->{'amazonAsin'}) {
$dvdinfo = getDvdInfo(asin => $dvd->{'amazonAsin'}, locale =>
+$locale);
}
if($dvdinfo){
$dvd->{'imageUrl'} ||= $dvdinfo->{'imageUrl'};
$dvd->{'title'} ||= $dvdinfo->{'title'};
$dvd->{'publisher'} ||= $dvdinfo->{'publisher'};
$dvd->{'year'} ||= $dvdinfo->{'year'};
$dvd->{'media'} ||= $dvdinfo->{'media'};
$dvd->{'released'} ||= $dvdinfo->{'released'};
$dvd->{'imageUrlLarge'} ||= $dvdinfo->{'imageUrlLarge'};
$dvd->{'detailUrl'} ||= $dvdinfo->{'detailUrl'};
}
# Insert the new node into the tree
push (@newdvds,$dvd);
}
# Insert the new book nodes into the wishlist
$wishlist->{'wishlist'}->{'dvd'} = [@newdvds];
# Send the wishlist to the client
print CGI->header(-type=>'application/xml');
print '<?xml version="1.0" standalone="yes"?>';
print "\n";
print '<?xml-stylesheet type="text/xsl" href="/static/xml/wishlist.xsl
+" media="screen"?>';
print "\n";
print XMLout($wishlist, KeepRoot => 1, NoAttr => 1);
###
### Subroutines
###
sub getBookInfo {
my %params = @_;
my $req;
if(0) {
} elsif(exists $params{asin}) {
$req = getAmazonBookByAsin(%params);
} elsif(exists $params{isbn}) {
$req = getAmazonBookByIsbn(%params);
} else {
warn "Request could not be completed";
return;
}
return $req;
}
sub getDvdInfo {
my %params = @_;
my $req;
if(0) {
} elsif(exists $params{asin}) {
$req = getAmazonDvdByAsin(@_);
} else {
warn "Request could not be completed";
return;
}
return $req;
}
sub getAmazonBookByAsin {
my %params = @_;
my $resp = $amazon->{$params{locale}}->search(asin => $params{asin
+});
if($resp->is_success()){
my $bookinfo = getAmazonBookInfo($resp);
return $bookinfo;
}
}
# Separated for future use
sub getAmazonBookByIsbn {
my %params = @_;
my $resp = $amazon->{$params{locale}}->search(asin => $params{isbn
+});
if($resp->is_success()){
my $bookinfo = getAmazonBookInfo($resp,$params{locale});
return $bookinfo;
}
}
# Takes a Net::Amazon::Search object and returns a hash
sub getAmazonBookInfo {
my ($resp,$locale) = @_;
# Get the result
my ($prop) = $resp->properties;
# Create the new node
my $info;
$info->{'imageUrl'} = $prop->ImageUrlMedium;
$info->{'title'} = $prop->title;
$info->{'publisher'} = $prop->publisher;
$info->{'year'} = $prop->year;
$info->{'media'} = $prop->Media;
$info->{'released'} = $prop->ReleaseDate;
$info->{'imageUrlLarge'} = $prop->ImageUrlLarge;
$info->{'detailUrl'} = getAmazonUrlPrefix($locale) . $prop->Asin;
return $info;
}
sub getAmazonDvdByAsin {
my %params = @_;
my $resp = $amazon->{$params{locale}}->search(asin => $params{asin
+});
if($resp->is_success()){
my $dvdinfo = getAmazonDvdInfo($resp, $params{locale});
return $dvdinfo;
}
}
sub getAmazonDvdInfo {
my ($resp, $locale) = @_;
# Get the result
my ($prop) = $resp->properties;
# Create the new node
my $info;
$info->{'imageUrl'} = $prop->ImageUrlMedium;
$info->{'title'} = $prop->title;
#$info->{'publisher'} = $prop->publisher;
$info->{'year'} = $prop->year;
$info->{'media'} = $prop->Media;
$info->{'released'} = $prop->ReleaseDate;
$info->{'imageUrlLarge'} = $prop->ImageUrlLarge;
$info->{'locale'} = $locale;
$info->{'detailUrl'} = getAmazonUrlPrefix($locale) . $prop->Asin;
return $info;
}
sub getAmazonUrlPrefix {
my $locale = shift || 'us';
my $prefix;
if($locale eq 'us'){
$prefix = 'http://www.amazon.com/exec/obidos/ASIN/';
} elsif ($locale eq 'uk'){
$prefix = 'http://www.amazon.co.uk/exec/obidos/ASIN/';
} elsif ($locale eq 'jp'){
$prefix = 'http://www.amazon.co.jp/exec/obidos/ASIN/';
} elsif ($locale eq 'de'){
$prefix = 'http://www.amazon.de/exec/obidos/ASIN/';
} else {
$prefix = 'http://www.amazon.com/exec/obidos/ASIN/';
}
return $prefix;
}