2009/08/16 追記
furyu-teiさんの記事でXSLTの場合はendpointを変えないといけない事が分かったので修正。動くようになった。
2009/07/16 追記
AWS認証制限に対応しましたがXSLTの処理において正しく動きません。手元だとXSLT変換出来ていますがAmazonサーバを通すと空の処理結果が戻ってきてしまいます。とりあえずは正しく動くはずだろうコードで置いて置きますが、動作しない事をご了承下さい。
またXSLTも使わないバージョンもありますのでそちらもご覧下さい。
気付いたらAmazon Ecommerce Web Serviceのバージョン3.0が
終わっていました。
それにともないmalaさんの「
Amazon最速検索β」も動かなくなってしまっていました。
残念だったので気分だけでも...と思い作ってみました。
今回のポイントとしてはJSONではなくJSONPであること。malaさんのバージョンでは"end"というマーカーを使い、かつcallbackは指定出来ませんでしたが、以下のサンプルではcallbackパラメータを受け取りJSONPします。
AWS4では、与えられたパラメータがItemSearchResponse/OperationRequest/Arguments/Argumentに格納されるので、この属性Nameが"callback"の物を関数名となる様にしてあります。
まずXSLT
xml version="1.0" encoding="UTF-8"
<xslstylesheet version="1.0"
xmlnsxsl="http://www.w3.org/1999/XSL/Transform"
xmlnsaws="http://webservices.amazon.com/AWSECommerceService/2005-10-05"
exclude-result-prefixes="aws">
<xsloutput method="text" media-type="text/javascript" encoding="UTF-8"/>
<xslvariable name="lcletters">abcdefghijklmnopqrstuvwxyz</xslvariable>
<xslvariable name="ucletters">ABCDEFGHIJKLMNOPQRSTUVWXYZ</xslvariable>
<xsltemplate match="/aws:ItemSearchResponse">
<xslvalue-of select="aws:OperationRequest/aws:Arguments/aws:Argument[@Name='callback']/@Value"/>
<xsltext>({isvalid:</xsltext>
<xslvalue-of select="translate(aws:Items/aws:Request/aws:IsValid/text(),$ucletters,$lcletters)" />
<xsltext>,errors:[</xsltext>
<xslfor-each select="aws:Items/aws:Request/aws:Errors/aws:Error">
<xsltext>{code:'</xsltext>
<xslvalue-of select="aws:Code" />
<xsltext>',message:'</xsltext>
<xslcall-template name="sanitize-text">
<xslwith-param name="target" select="aws:Message"/>
</xslcall-template>
<xsltext>'}</xsltext>
<xslchoose>
<xslwhen test='position() < last()'>
<xsltext>,</xsltext>
</xslwhen>
</xslchoose>
</xslfor-each>
<xsltext>],result:</xsltext>
<xslapply-templates select="aws:Items"/>
<xsltext>})</xsltext>
</xsltemplate>
<xsltemplate match="aws:Items">
<xsltext>[</xsltext>
<xslfor-each select="aws:Item">
<xslapply-templates select="."/>
<xslchoose>
<xslwhen test='position() < last()'>
<xsltext>,</xsltext>
</xslwhen>
</xslchoose>
</xslfor-each>
<xsltext>]</xsltext>
</xsltemplate>
<xsltemplate match="aws:Item">
<xsltext>{</xsltext>
<xsltext>asin:'</xsltext>
<xslvalue-of select="aws:ASIN"/>
<xsltext>'</xsltext>
<xsltext>,url:'</xsltext>
<xslvalue-of select="aws:DetailPageURL"/>
<xsltext>'</xsltext>
<xsltext>,title:'</xsltext>
<xslcall-template name="sanitize-text">
<xslwith-param name="target" select="normalize-space(aws:ItemAttributes/aws:Title)"/>
</xslcall-template>
<xsltext>'</xsltext>
<xsltext>,publisher:'</xsltext>
<xslcall-template name="sanitize-text">
<xslwith-param name="target" select="normalize-space(aws:ItemAttributes/aws:Publisher)"/>
</xslcall-template>
<xsltext>'</xsltext>
<xsltext>,date:'</xsltext>
<xslcall-template name="sanitize-text">
<xslwith-param name="target" select="aws:ItemAttributes/aws:PublicationDate"/>
</xslcall-template>
<xsltext>'</xsltext>
<xsltext>,authors:[</xsltext>
<xslfor-each select="aws:ItemAttributes/aws:Author">
<xsltext>'</xsltext>
<xslcall-template name="sanitize-text">
<xslwith-param name="target" select="text()"/>
</xslcall-template>
<xsltext>'</xsltext>
<xslchoose>
<xslwhen test='position() < last()'>
<xsltext>,</xsltext>
</xslwhen>
</xslchoose>
</xslfor-each>
<xsltext>]</xsltext>
<xsltext>,label:'</xsltext>
<xslcall-template name="sanitize-text">
<xslwith-param name="target" select="aws:ItemAttributes/aws:Label"/>
</xslcall-template>
<xsltext>'</xsltext>
<xsltext>,price:'</xsltext>
<xslcall-template name="sanitize-text">
<xslwith-param name="target" select="aws:ItemAttributes/aws:ListPrice/aws:FormattedPrice"/>
</xslcall-template>
<xsltext>'</xsltext>
<xsltext>,availability:'</xsltext>
<xslcall-template name="sanitize-text">
<xslwith-param name="target" select="aws:Offers//aws:Availability"/>
</xslcall-template>
<xsltext>'</xsltext>
<xsltext>,image:{</xsltext>
<xslfor-each select="aws:*[local-name()='SmallImage' or local-name()='MediumImage' or local-name()='LargeImage']">
<xslcall-template name="image">
<xslwith-param name="type" select="substring-before(local-name(), 'Image')"/>
</xslcall-template>
<xslchoose>
<xslwhen test='position() < last()'>
<xsltext>,</xsltext>
</xslwhen>
</xslchoose>
</xslfor-each>
<xsltext>}</xsltext>
<xsltext>,reviews:[</xsltext>
<xslfor-each select="aws:CustomerReviews/aws:Review">
<xsltext>{summary:'</xsltext>
<xslcall-template name="sanitize-text">
<xslwith-param name="target" select="normalize-space(aws:Summary)"/>
</xslcall-template>
<xsltext>',content:'</xsltext>
<xslcall-template name="sanitize-text">
<xslwith-param name="target" select="normalize-space(aws:Content)"/>
</xslcall-template>
<xsltext>'}</xsltext>
<xslchoose>
<xslwhen test='position() < last()'>
<xsltext>,</xsltext>
</xslwhen>
</xslchoose>
</xslfor-each>
<xsltext>]</xsltext>
<xsltext>}</xsltext>
</xsltemplate>
<xsltemplate name="image">
<xslparam name="type"/>
<xslvalue-of select="translate($type,$ucletters,$lcletters)"/>
<xsltext>:{</xsltext>
<xsltext>src:'</xsltext>
<xslvalue-of select="aws:URL"/>
<xsltext>',</xsltext>
<xsltext>width:</xsltext>
<xslvalue-of select="aws:Width"/>
<xsltext>,</xsltext>
<xsltext>height:</xsltext>
<xslvalue-of select="aws:Height"/>
<xsltext>}</xsltext>
</xsltemplate>
<xsltemplate name="sanitize-text">
<xslparam name="target"/>
<xslchoose>
<xslwhen test="contains($target, '"')">
<xslvalue-of select="substring-before($target, '"')"/>
<xslcall-template name="sanitize-text">
<xslwith-param name="target" select="substring-after($target, '"')"/>
</xslcall-template>
</xslwhen>
<xslotherwise><xslvalue-of select="$target"/></xslotherwise>
</xslchoose>
</xsltemplate>
</xslstylesheet>
ソース:
aws2json.xmsl
ポイントとしては"apply-template"のselectを使うのではなく"xsl:for-each"を使うことで"position()"および"last()"を使った最終要素時のカンマ制御を行っている所。FirefoxではokですがIEだとエラーになっちゃいますからね。
そしてjavascript部分
$(document).ready(function() {
var unsanitize = function(text) {
return (text||'').replace(/&/g, '&').replace(/>/g, '>').replace(/</g, '<');
}
$('#aws-word').keydown(function(e) { if (e.keyCode == 13) $('#aws-search').click() });
$('#aws-search').click(function() {
if (!$('#aws-word').val()) {
$('#aws').html('');
return;
}
$('#aws').html('<img src="http://mattn.kaoriya.net/images/ajax-loader.gif"/>');
$.ajaxSettings.cache = true;
$.getJSON('http://xml-jp.amznxslt.com/onca/xml?callback=?',
{
Service: 'AWSECommerceService',
SubscriptionId: '1GXPBVS13GJVA58PKVG2',
AssociateTag: 'bigsky-22',
Operation: 'ItemSearch',
SearchIndex: $('#aws-kind').val(),
ResponseGroup: 'Medium,Offers,Reviews',
Version: '2005-10-05',
Keywords: $('#aws-word').val(),
ContentType: 'text/plain',
Style: 'http://mattn.kaoriya.net/misc/aws2json.xsl'
}, function(data) {
$('#aws').html('');
$.each(data.result, function(index, item) {
$('<div>')
.css('border', '1px dotted black')
.css('border', '1px dotted black')
.css('background-color', '#eeeeee')
.css('padding', '0.5em')
.css('margin', '0.5em')
.attr('id', 'aws' + index)
.hide()
.appendTo('#aws');
var c = $('#aws' + index);
$('<a/>')
.appendTo(c)
.attr('href', item.url)
.text(unsanitize(item.title))
.appendTo(c);
var a = $('a', c);
if (item.image.medium) {
$('<img>')
.css('vertical-align', 'top')
.css('padding', '0.5em')
.css('border', '0px')
.css('float', 'left')
.attr('title', item.title)
.attr('src', item.image.medium.src)
.prependTo(a);
}
a.after('<br />');
$.each(item.authors, function(index, item) {
$('<b>')
.text(item)
.appendTo(c)
.after('<br />');
});
$('#aws' + index)
.append('<span>ASIN: ' + item.asin + '</span>')
.append('<br />')
.append('<br />')
.append(item.publisher + '/' + item.price + ' (' + item.date + ')')
.append('<br />')
.append(item.availability);
$(c).append('<br clear="all" /><br />');
if (item.reviews.length) {
$('<a href="#">review comments</a>')
.css('font-size', 'small')
.css('color', 'blue')
.appendTo(c)
.click(function() { $('.reviews', c).toggle('slow'); return false; });
$('<div>')
.attr('class', 'reviews')
.css('display', 'none')
.css('font-size', 'small')
.appendTo(c);
$.each(item.reviews, function(index, item) {
$('.reviews', c)
.append('<span class="name"><strong>' + item.summary + '</strong></span><br />')
.append('<div class="comment">' + unsanitize(item.content) + '</div>')
.append('<br />');
$('.comment', c)
.css('border', '1px dotted gray')
.css('background-color', 'white')
.css('padding', '0.5em')
});
}
});
$('div', '#aws').fadeIn('slow', function() {
$('.reviews').hide();
});
}
);
});
});
amazon web serviceのXSLTプロセッサにcallback付きのXSLを処理させる事でjQueryのcallbackを呼び出させています。
getJSONのデータ部を弄る事である程度動きが変えられるかと思います。ただしOperationのItemSearchを変えると動かなくなりますので要注意です。
今回のサンプルとしてはレビューコメントも表示されるようになっています。"review comments"をクリックすると展開されます。
jQueryとXSLだけで動くのでCGIの動かないサーバでもokです。
あくまでサンプルですが、どなたかの参考になれば...
以下実行例
続きを読む...