2009/07/16

2009/07/16 追記
AWS認証制限に対応しました。本文中はそのままですが、デモには非公開キーを使用してアクセスするCGIに変更しています。


時代は便利になった物です。
MOONGIFT: » XMLをJSONにするXSLT「xml2json.xslt」:オープンソースを毎日紹介

xml2json.xsltを見ていたらma.la氏のAmazon最速検索を思い出した。あちらはAmazon AWS専用になるだろうが、xml2json.xsltはそれをもっと汎用的なものにしたと考えられるだろう。

http://www.moongift.jp/2009/04/xml2json-xslt/
javascriptとXSLTを使うならば、AWSサーバから見えるサーバを用意しないといけないのですがYahoo! YQLを使えばそれも要りません。
YQLといえばPipesに毛の生えた様な物だと思う方もいらっしゃるかもしれませんが、解析した結果をXMLやJSONで返す事ができJSONならばDOMツリーをJSONで表現してくれます。
例えばgithubで自分が公開したりforkしたりしているプロジェクトの一覧を作る場合、何を使って作りますか?Pipes?CGI?YQLならば簡単です。
select * from html where url = 'http://github.com/mattn' and xpath = '//li[@class="project"]'
実行結果
これだけ。ちなみに私のgithubのページではプロジェクト一覧が表示されています。適当にパクって遊んでみて下さい。 さて話を戻してYQLですが
select * from html where url = 'http://www.example.com/'
のhtmlをxmlに変えればxmlもパース出来ます。つまりAWSのレスポンスをJSON(JSONP)で受け取れるのです。
select * from xml where url = 'http://xml-jp.amznxslt.com/onca/xml?Service=AWSECommerceService&SubscriptionId=XXX&AssociateTag=YYY&Operation=ItemSearch&SearchIndex=Books&ResponseGroup=Medium,Offers,Reviews&Version=2005-10-05&Keywords=ZZZ'
jQueryならば
var Keywords = 'ZZZ';
var SubscriptionId = 'XXX';
var AssociateTag = 'YYY';
var ResponseGroup = 'Medium,Offers,Reviews';
$.ajaxSettings.cache = true;
$.getJSON('http://query.yahooapis.com/v1/public/yql?callback=?', {
    'q' : 'select * from xml where url = \'http://xml-jp.amznxslt.com/onca/xml?Service=AWSECommerceService&SubscriptionId=' + encodeURIComponent(SubscriptionId) + '&AssociateTag=' + encodeURIComponent(AssociateTag) + '&Operation=ItemSearch&SearchIndex=Books&ResponseGroup=' + encodeURIComponent(ResponseGroup) + '&Version=2005-10-05&Keywords=' + encodeURIComponent(Keywords) + '\'',
    'format' : 'json'
}, function(data) {
こんな感じに書けます。これを使えば以前書いた「XSLとjQuery/HTMLだけで作る、amazon最速検索」ももっと簡単になるのです。
さくっと以下の様に書いてみました。
$(function() {
  var unsanitize = function(text) { return (text||'').replace(/&amp;/g, '&').replace(/&gt;/g, '>').replace(/&lt;/g, '<'); }
  var quote = function(str) { return encodeURIComponent(str) };

  $('#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"/>');
    var Keywords = $('#aws-word').val();
    var SubscriptionId = '1GXPBVS13GJVA58PKVG2';
    var AssociateTag = 'bigsky-22';
    var ResponseGroup = 'Medium,Offers,Reviews';

    $.ajaxSettings.cache = true;
    $.getJSON('http://query.yahooapis.com/v1/public/yql?callback=?', {
        'q' : 'select * from xml where url = \'http://xml-jp.amznxslt.com/onca/xml?Service=AWSECommerceService&SubscriptionId=' + encodeURIComponent(SubscriptionId) + '&AssociateTag=' + encodeURIComponent(AssociateTag) + '&Operation=ItemSearch&SearchIndex=Books&ResponseGroup=' + encodeURIComponent(ResponseGroup) + '&Version=2005-10-05&Keywords=' + encodeURIComponent(Keywords) + '\'',
        'format' : 'json'
    }, function(data) {
      $('#aws').html('');
      $.each(data.query.results.ItemSearchResponse.Items.Item, function(index, item) {
        $('<div>')
          .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.DetailPageURL)
          .text(unsanitize(item.ItemAttributes.Title))
          .appendTo(c);
        var a = $('a', c);
        if (item.MediumImage) {
          $('<img/>')
            .css('vertical-align', 'top')
            .css('padding', '0.5em')
            .css('border', '0px')
            .css('float', 'left')
            .attr('title', item.ItemAttributes.Title)
            .attr('src', item.MediumImage.URL)
            .prependTo(a);
        }
        a.after('<br />');
    
        if (typeof (item.ItemAttributes.Author||'') == 'string') item.ItemAttributes.Author = [item.ItemAttributes.Author||''];
        $.each(item.ItemAttributes.Author, function(index, item) {
          $('<b>')
            .text(item)
            .appendTo(c)
            .after('<br />');
        });
        $('#aws' + index)
          .append('<span>ASIN: ' + item.ASIN + '</span>')
          .append('<br />')
          .append('<br />')
          .append(item.ItemAttributes.Publisher + '/' + (item.ItemAttributes.ListPrice ? item.ItemAttributes.ListPrice.FormattedPrice : '') + ' (' + item.ItemAttributes.PublicationDate + ')')
          .append('<br />')
          .append((item.Offers && (item.Offers.Offer||'')) ? item.Offers.Offer.OfferListing.Availability : '');
        $(c).append('<br clear="all" /><br />');
        if (item.CustomerReviews) {
          if (typeof item.CustomerReviews.Review.Summary == 'string') item.CustomerReviews.Review = [item.CustomerReviews.Review];
          $('<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.CustomerReviews.Review, 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();
      });
    });
  });
});
以下実行例


簡単ですね。これでWebサーバを持たなくてもAmazon最速検索が出来上がります。
Posted at 15:41 | WriteBacks () | Edit
Edit this entry...

wikieditish message: Ready to edit this entry.






















A quick preview will be rendered here when you click "Preview" button.