JSONP ならぬ HTMLP を Amazon XSLT で試してみた
Amazon Web Services では Style 引数に XSL ファイルの URL を指定することでレスポンスの XML を Amazon のサーバ側でパースできる。これを使って、JSONP 形式に返すサンプルが色々あった。でも単純に表示するだけなら innerHTML に HTML を流し込むだけの方が楽だろう。
ということで JSON with Padding ならぬ HTML with Padding(で合ってる??)を試しに作ってみることにした。
function awsResult(html){ document.getElementById('content').innerHTML = html; }
と定義しておいて、Script タグの Padding によって、
awsResult('<ul><li> ・・・ </ul>');
最終的に上記のように返ってくれば、<ul><li> ・・・ </ul> の部分を content に表示できる。
awshtmlp.xsl
AWS に渡す XSL ファイルの内容は次のとおり。
ポイントは Callback 引数を拡張定義することで aws:OperationRequest/aws:Arguments/aws:Argument[@Name='Callback']/@Value から引っ張って出力していること。これでコールバック関数名(前述の awsResult)は固定せずに済む。
また HTML 出力としているが結果は JavaScript であるので、インデントはさせない(改行はさせない)で、「'」で囲う。そして escape-apos でタイトルとラベルに含まれている場合はエスケープするようにしている。
<?xml version="1.0" encoding="UTF-8"?> <xsl:stylesheet version="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform" xmlns:aws="http://webservices.amazon.com/AWSECommerceService/2005-10-05" exclude-result-prefixes="aws"> <xsl:output method="html" indent="no" encoding="UTF-8"/> <xsl:template match="/aws:ItemSearchResponse"> <xsl:value-of select="aws:OperationRequest/aws:Arguments/aws:Argument[@Name='Callback']/@Value"/> <xsl:text>('</xsl:text> <xsl:apply-templates select="aws:Items"/> <xsl:text>')</xsl:text> </xsl:template> <xsl:template match="aws:Items"> <ul class="amazonList"> <xsl:apply-templates select="aws:Item"/> </ul> </xsl:template> <xsl:template match="aws:Item"> <li> <a> <xsl:attribute name="href"><xsl:value-of select="aws:DetailPageURL"/></xsl:attribute> <xsl:call-template name="escape-apos"> <xsl:with-param name="target" select="aws:ItemAttributes/aws:Title"/> </xsl:call-template> </a> <xsl:apply-templates select="aws:SmallImage"/> <span class="label"> <xsl:call-template name="escape-apos"> <xsl:with-param name="target" select="aws:ItemAttributes/aws:Label"/> </xsl:call-template> </span> <span class="price"> <xsl:value-of select="aws:ItemAttributes/aws:ListPrice/aws:FormattedPrice"/> </span> </li> </xsl:template> <xsl:template match="aws:SmallImage"> <img> <xsl:attribute name="src"><xsl:value-of select="aws:URL"/></xsl:attribute> <xsl:attribute name="width"><xsl:value-of select="aws:Width"/></xsl:attribute> <xsl:attribute name="height"><xsl:value-of select="aws:Height"/></xsl:attribute> </img> </xsl:template> <xsl:template name="escape-apos"> <xsl:param name="target"/> <xsl:variable name="m"><xsl:text>'</xsl:text></xsl:variable> <xsl:variable name="r"><xsl:text>&apos;</xsl:text></xsl:variable> <xsl:choose> <xsl:when test="contains($target, $m)"> <xsl:value-of select="substring-before($target, $m)"/> <xsl:value-of select="$r"/> <xsl:call-template name="escape-apos"> <xsl:with-param name="target" select="substring-after($target, $m)"/> </xsl:call-template> </xsl:when> <xsl:otherwise><xsl:value-of select="$target"/></xsl:otherwise> </xsl:choose> </xsl:template> </xsl:stylesheet>
サンプル HTML
下記は検索ボックスの内容を HTML with Padding(?) で投げて、結果を表示するサンプルである。
<html> <head> <meta http-equiv="content-type" content="text/html; charset=UTF-8"> <title>Amazon XSLT HTMLP Sample</title> <script type="text/javascript"> function awsResult(html){ document.getElementById('content').innerHTML = html; document.getElementById('findButton').disabled = false; document.body.removeChild(document.getElementById('sc')); } function find(){ var sc = document.createElement('script'); sc.id = "sc"; sc.src = 'http://webservices.amazon.co.jp/onca/xml?Service=AWSECommerceService' + '&AWSAccessKeyId=☆アクセスキー☆' + '&ResponseGroup=ItemAttributes,Images&Operation=ItemSearch' + '&SearchIndex=Blended' + '&Callback=awsResult' + '&Style=☆前述の XSL ファイルの URL ☆' + '&Keywords=' + encodeURIComponent(document.getElementById('query').value); document.getElementById('findButton').disabled = true; document.body.appendChild(sc); } </script> </head> <body> <form onsubmit="find(); return false;"> <input id="query" type="text" size="40"><input type="submit" id="findButton" value=" 検索 "> </form> <div id="content"></div> </body> </html>