33.3.4 使用REST发送和接收请求
在browseNodeSearch()函数(或ASINSearch(),keywordSearch())设置了所需的类成员变量后,通过HTTP使用REST/XML还要做的就是格式化数据并发送给URL,如下所示:
$this->url="http://ecs.amazonaws.com/onca/xml?".
"Service=".$this->Service.
"&Operation=".$this->Operation.
"&AssociateTag=".$this->AssociateTag.
"&AWSAccessKeyId=".$this->AWSAccessKeyId.
"&BrowseNode=".$this->BrowseNode.
"&ResponseGroup=".$this->ResponseGroup.
"&SearchIndex=".$this->SearchIndex.
"&Sort=".$this->Sort.
"&TotalPages=".$this->TotalPages;
$this->parseXML();
来完成实际的操作。parseXML()方法如程序清单33-10所示。
程序清单33-10 parseXML()方法——分析由查询返回的XML
//Parse the XML into Product object(s)
function parseXML(){
//suppress errors because this will fail sometimes
$xml=@simplexml_load_file($this->url);
if(!$xml){
//try a second time in case just server busy
$xml=@simplexml_load_file($this->url);
if(!$xml){
return false;
}
}
$this->totalResults=(integer)$xml->TotalResults;
foreach($xml->Items->Item as$productXML){
$this->products[]=new Product($productXML);
}
simplexml_load_file()函数完成了大部分的操作。它从一个文件读入XML内容,在这个例子中,是从一个URL读入的。它为数据和XML文档中的结构提供了一个面向对象接口。对数据来说,这是一个非常有用的接口,但是由于我们希望一个接口函数集能够处理来自REST或SOAP方法的数据,所以可以为Product类示例中的相同数据创建自己的面向对象接口。请注意,在REST版本中,可以将XML中的属性转换成PHP变量类型。在PHP中,不必使用cast操作符,但是在这个例子中,如果不给出cast操作符,将看到每一个数据的对象表示,这是没有用的。
Product类包含了大多数的访问器函数,这些函数可以用来访问保存在私有成员中的数据,因此打印整个文件并没有很大意义。Product类的结构和构造函数还是值得介绍的。程序清单33-11包含了Product类的部分定义。
程序清单33-11 Product类封装了一个Amazon产品的所有信息
class Product{
private$ASIN;
private$productName;
private$releaseDate;
private$manufacturer;
private$imageUrlMedium;
private$imageUrlLarge;
private$listPrice;
private$ourPrice;
private$salesRank;
private$availability;
private$avgCustomerRating;
private$authors=array();
private$reviews=array();
private$similarProducts=array();
private$soap;//array returned by SOAP calls
function__construct($xml){
if(METHOD=='SOAP'){
$this->ASIN=$xml['ASIN'];
$this->productName=$xml['ItemAttributes']['Title'];
if(is_array($xml['ItemAttributes']['Author'])!=""){
foreach($xml['ItemAttributes']['Author']as$author){
$this->authors[]=$author;
}
}else{
$this->authors[]=$xml['ItemAttributes']['Author'];
}
$this->releaseDate=$xml['ItemAttributes']['PublicationDate'];
$this->manufacturer=$xml['ItemAttributes']['Manufacturer'];
$this->imageUrlMedium=$xml['MediumImage']['URL'];
$this->imageUrlLarge=$xml['LargeImage']['URL'];
$this->listPrice=$xml['ItemAttributes']['ListPrice']['FormattedPrice'];
$this->listPrice=str_replace('$','',$this->listPrice);
$this->listPrice=str_replace(',','',$this->listPrice);
$this->listPrice=floatval($this->listPrice);
$this->ourPrice=$xml['OfferSummary']['LowestNewPrice']['FormattedPrice'];
$this->ourPrice=str_replace('$','',$this->ourPrice);
$this->ourPrice=str_replace(',','',$this->ourPrice);
$this->ourPrice=floatval($this->ourPrice);
$this->salesRank=$xml['SalesRank'];
$this->availability=
$xml['Offers']['Offer']['OfferListing']['Availability'];
$this->avgCustomerRating=$xml['CustomerReviews']['AverageRating'];
$reviewCount=0;
if(is_array($xml['CustomerReviews']['Review'])){
foreach($xml['CustomerReviews']['Review']as$review){
$this->reviews[$reviewCount]['Rating']=$review['Rating'];
$this->reviews[$reviewCount]['Summary']=$review['Summary'];
$this->reviews[$reviewCount]['Content']=$review['Content'];
$reviewCount++;
}
}
$similarProductCount=0;
if(is_array($xml['SimilarProducts']['SimilarProduct'])){
foreach($xml['SimilarProducts']['SimilarProduct']as$similar){
$this->similarProducts[$similarProductCount]['Title']=
$similar['Title'];
$this->similarProducts[$similarProductCount]['ASIN']=
$review['ASIN'];
$similarProductCount++;
}
}
}else{
//using REST
$this->ASIN=(string)$xml->ASIN;
$this->productName=(string)$xml->ItemAttributes->Title;
if($xml->ItemAttributes->Author){
foreach($xml->ItemAttributes->Author as$author){
$this->authors[]=(string)$author;
}
}
$this->releaseDate=(string)$xml->ItemAttributes->PublicationDate;
$this->manufacturer=(string)$xml->ItemAttributes->Manufacturer;
$this->imageUrlMedium=(string)$xml->MediumImage->URL;
$this->imageUrlLarge=(string)$xml->LargeImage->URL;
$this->listPrice=(string)$xml->ItemAttributes->ListPrice->FormattedPrice;
$this->listPrice=str_replace('$','',$this->listPrice);
$this->listPrice=str_replace(',','',$this->listPrice);
$this->listPrice=floatval($this->listPrice);
$this->ourPrice=(string)$xml->OfferSummary->LowestNewPrice->
FormattedPrice;
$this->ourPrice=str_replace('$','',$this->ourPrice);
$this->ourPrice=str_replace(',','',$this->ourPrice);
$this->ourPrice=floatval($this->ourPrice);
$this->salesRank=(string)$xml->SalesRank;
$this->availability=(string)$xml->Offers->Offer->OfferListing->
Availability;
$this->avgCustomerRating=(float)$xml->CustomerReviews->AverageRating;
$reviewCount=0;
if($xml->CustomerReviews->Review){
foreach($xml->CustomerReviews->Review as$review){
$this->reviews[$reviewCount]['Rating']=(float)$review->Rating;
$this->reviews[$reviewCount]['Summary']=(string)$review->Summary;
$this->reviews[$reviewCount]['Content']=(string)$review->Content;
$reviewCount++;
}
}
$similarProductCount=0;
if($xml->SimilarProducts->SimilarProduct){
foreach($xml->SimilarProducts->SimilarProduct as$similar){
$this->similarProducts[$similarProductCount]['Title']=
(string)$similar->Title;
$this->similarProducts[$similarProductCount]['ASIN']=
(string)$similar->ASIN;
$similarProductCount++;
}
}
}
}
//most methods in this class are similar
//and just return the private variable
function similarProductCount(){
return count($this->similarProducts);
}
function similarProduct($i){
return$this->similarProducts[$i];
}
function customerReviewCount(){
return count($this->reviews);
}
function customerReviewRating($i){
return$this->reviews[$i]['Rating'];
}
function customerReviewSummary($i){
return$this->reviews[$i]['Summary'];
}
function customerReviewComment($i){
return$this->reviews[$i]['Content'];
}
function valid(){
if(isset($this->productName)&&($this->ourPrice>0.001)&&
isset($this->ASIN)){
return true;
}else{
return false;
}
}
function ASIN(){
return padASIN($this->ASIN);
}
function imageURLMedium(){
return$this->imageUrlMedium;
}
function imageURLLarge(){
return$this->imageUrlLarge;
}
function productName(){
return$this->productName;
}
function ourPrice(){
return number_format($this->ourPrice,2,'.','');
}
function listPrice(){
return number_format($this->listPrice,2,'.','');
}
function authors(){
if(isset($this->authors)){
return$this->authors;
}else{
return false;
}
}
function releaseDate(){
if(isset($this->releaseDate)){
return$this->releaseDate;
}else{
return false;
}
}
function avgCustomerRating(){
if(isset($this->avgCustomerRating)){
return$this->avgCustomerRating;
}else{
return false;
}
}
function manufacturer(){
if(isset($this->manufacturer)){
return$this->manufacturer;
}else{
return false;
}
}
function salesRank(){
if(isset($this->salesRank)){
return$this->salesRank;
}else{
return false;
}
}
function availability(){
if(isset($this->availability)){
return$this->availability;
}else{
return false;
}
}
}
这个类的构造函数需要两个不同形式的输入数据并且能够创建一个应用程序接口。请注意,虽然某些处理代码可以更普通,但是根据方法的不同,某些重要的属性,例如评价,具有不同的名称。
了解获得数据的全部步骤后,我们回到getARS()函数,接着就是showBrowseNode()。下一步是:
showSummary($ars->products(),$page,
$ars->totalResults(),$mode,
$browseNode);
showSummary()函数只显示了AmazonResultSet的信息,如程序清单33-1所示的。因此,这里我们没有再次包含该函数。