Hatena::ブログ(Diary)

放浪するエンジニアの覚え書き このページをアンテナに追加 RSSフィード

2009-10-08

GAE/JのURL FetchでYAHOO! Web Search APIを使う

| 09:06 |  GAE/JのURL FetchでYAHOO! Web Search APIを使う - 放浪するエンジニアの覚え書き のブックマークコメント

YUI(先月v3がリリースされましたねぇ。v2も2.8.0rになってます)にはクロスドメインJavascriptライブラリー「Getツール」があるのだが、GAE/JのURL FetchをつかってProxyとなるプログラムを作成してみた。

Fetchしたのは、YAHOO Web Search API。たとえば、「YAHOO」というキーワードで検索した場合、以下のようなXMLが戻ってくる。

appidには、自分のapplication idが入ってくる。

<?xml version="1.0" encoding="UTF-8"?>
<ResultSet xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns="urn:yahoo:jp:srch" xsi:schemaLocation="urn:yahoo:jp:srch http://search.yahooapis.jp/WebSearchService/V1/WebSearchResponse.xsd" totalResultsAvailable="5920000000" totalResultsReturned="10" firstResultPosition="1" pgr="278352159">

<Result>
<Title>Yahoo! JAPANホームページ</Title>
<Summary>ポータルサイト。検索、オークション、ショッピング、トピックス、ファイナンス、ブログ、メール、モバイル、きっず等のサービス。 ... Yahoo!カテゴリ登録審査 ... どこでもYahoo! JAPAN. 無料で遊べるイケメン育成ゲーム「きらぷろ」が登場 ...</Summary>
<Url>http://www.yahoo.co.jp/</Url>
<ClickUrl>http://wrs.search.yahoo.co.jp/l=WS1/R=1/wdm=0/IPC=jp/ln=ja/H=0/;_ylt=A8vY5mtzacJKZ54AgV0DUAx.;_ylu=X3oDMTB2cXVjNTM5BGNvbG8DdwRsA1dTMQRwb3MDMQRzZWMDc3IEdnRpZAM-/SIG=11bdqoiti/EXP=1254341363/*-http%3A//www.yahoo.co.jp/</ClickUrl>
<ModificationDate>1254150000</ModificationDate>
<MimeType>text/html</MimeType>
<Cache>
<Url>http://wrs.search.yahoo.co.jp/l=WS5/R=1/;_ylt=A8vY5mtzacJKZ54Agl0DUAx.;_ylu=X3oDMTBwOHA5a2tvBGNvbG8DdwRwb3MDMQRzZWMDc3IEdnRpZAM-/SIG=175hp3ksr/EXP=1254341363/*-http%3A//cache.yahoofs.jp/search/cache?ei=UTF-8&amp;appid=[your appid]&amp;query=YAHOO&amp;results=10&amp;u=www.yahoo.co.jp/&amp;w=yahoo+yahoo%21&amp;d=IVojrd29TjVK&amp;icp=1&amp;.intl=jp</Url>
<Size>80115</Size>
</Cache>
</Result>

<Result>
<Title>Yahoo!</Title>
<Summary>アメリカのYahoo! ... Yahoo! Search ... oneSearch. Get up-to-the-minute flight info and more with Yahoo! oneSearch on your phone. ...</Summary>
<Url>http://www.yahoo.com/</Url>
<ClickUrl>http://wrs.search.yahoo.co.jp/l=WS1/R=2/wdm=0/IPC=jp/ln=en/H=0/;_ylt=A8vY5mtzacJKZ54Ag10DUAx.;_ylu=X3oDMTB2ZjQ4dDExBGNvbG8DdwRsA1dTMQRwb3MDMgRzZWMDc3IEdnRpZAM-/SIG=119omo837/EXP=1254341363/*-http%3A//www.yahoo.com/</ClickUrl><ModificationDate>1254063600</ModificationDate>
<MimeType>text/html</MimeType>
</Result>

<Result>
<Title>Yahoo!メール</Title>
<Summary>ブラウザ上から利用できる無料メールサービス。メールソフトによる送受信や外部メールの確認、フィルター、アドレスブック機能、ウイルスチェック機能も。</Summary>
<Url>http://mail.yahoo.co.jp/</Url>
<ClickUrl>http://wrs.search.yahoo.co.jp/l=WS1/R=3/wdm=0/IPC=jp/ln=ja/H=0/;_ylt=A8vY5mtzacJKZ54AhF0DUAx.;_ylu=X3oDMTB2M3MzdmZoBGNvbG8DdwRsA1dTMQRwb3MDMwRzZWMDc3IEdnRpZAM-/SIG=11civb7nv/EXP=1254341363/*-http%3A//mail.yahoo.co.jp/</ClickUrl>
<ModificationDate>1254063600</ModificationDate>
<MimeType>text/html</MimeType>
<Cache>
<Url>http://wrs.search.yahoo.co.jp/l=WS5/R=3/;_ylt=A8vY5mtzacJKZ54AhV0DUAx.;_ylu=X3oDMTBwZ2dpZ2ZkBGNvbG8DdwRwb3MDMwRzZWMDc3IEdnRpZAM-/SIG=1761m6buk/EXP=1254341363/*-http%3A//cache.yahoofs.jp/search/cache?ei=UTF-8&amp;appid=[your appid]&amp;query=YAHOO&amp;results=10&amp;u=mail.yahoo.co.jp/&amp;w=yahoo+yahoo%21&amp;d=F-VRW929TjKa&amp;icp=1&amp;.intl=jp</Url>
<Size>13011</Size>
</Cache>
</Result>

<Result>
<Title>Yahoo!きっず</Title>
<Summary>小中学生のためのインターネットガイド。 ... Yahoo!きっずの特長やイベントの紹介、インターネットに潜む危険から子どもを守るためのヒント、 ... 子どもと一緒にインターネットをするなら、Yahoo! あんしんねっと(無料) ...</Summary>
<Url>http://kids.yahoo.co.jp/</Url>
<ClickUrl>http://wrs.search.yahoo.co.jp/l=WS1/R=4/wdm=0/IPC=jp/ln=ja/H=0/;_ylt=A8vY5mtzacJKZ54Ahl0DUAx.;_ylu=X3oDMTB2OWM1MXQ5BGNvbG8DdwRsA1dTMQRwb3MDNARzZWMDc3IEdnRpZAM-/SIG=11c0dna4c/EXP=1254341363/*-http%3A//kids.yahoo.co.jp/</ClickUrl>
<ModificationDate>1254150000</ModificationDate><MimeType>text/html</MimeType>
<Cache>
<Url>http://wrs.search.yahoo.co.jp/l=WS5/R=4/;_ylt=A8vY5mtzacJKZ54Ah10DUAx.;_ylu=X3oDMTBwYzFnNmkxBGNvbG8DdwRwb3MDNARzZWMDc3IEdnRpZAM-/SIG=1766325hg/EXP=1254341363/*-http%3A//cache.yahoofs.jp/search/cache?ei=UTF-8&amp;appid=[your appid]&amp;query=YAHOO&amp;results=10&amp;u=kids.yahoo.co.jp/&amp;w=yahoo+yahoo%21&amp;d=DheCcN29TjT3&amp;icp=1&amp;.intl=jp</Url>
<Size>64484</Size>
</Cache>
</Result>

<Result>
<Title>Yahoo!知恵袋</Title>
<Summary>ジャンル別の質問、回答サービス。回答数ランキング、質問、回答の履歴を確認できる「My知恵袋」、知恵コレクション等。</Summary>
<Url>http://chiebukuro.yahoo.co.jp/</Url>
<ClickUrl>http://wrs.search.yahoo.co.jp/l=WS1/R=5/wdm=0/IPC=jp/ln=ja/H=0/;_ylt=A8vY5mtzacJKZ54AiF0DUAx.;_ylu=X3oDMTB2NW50aG1hBGNvbG8DdwRsA1dTMQRwb3MDNQRzZWMDc3IEdnRpZAM-/SIG=11ivfjb6d/EXP=1254341363/*-http%3A//chiebukuro.yahoo.co.jp/</ClickUrl>
<ModificationDate>1254150000</ModificationDate>
<MimeType>text/html</MimeType>
<Cache>
<Url>http://wrs.search.yahoo.co.jp/l=WS5/R=5/;_ylt=A8vY5mtzacJKZ54AiV0DUAx.;_ylu=X3oDMTBwdDJ0dDBoBGNvbG8DdwRwb3MDNQRzZWMDc3IEdnRpZAM-/SIG=17cjbh1pk/EXP=1254341363/*-http%3A//cache.yahoofs.jp/search/cache?ei=UTF-8&amp;appid=[your appid]&amp;query=YAHOO&amp;results=10&amp;u=chiebukuro.yahoo.co.jp/&amp;w=yahoo+yahoo%21&amp;d=M-x60t29TjPe&amp;icp=1&amp;.intl=jp</Url>
<Size>82791</Size>
</Cache>
</Result>

<Result>
<Title>Yahoo!オークションホームページ</Title>
<Summary>不要品をユーザー間で自由売買。チャリティーオークション、エスクローサービス等も。 ... Yahoo! JAPAN - オークション利用登録 - ヘルプ ... 「品川女子学院×Yahoo!オークション」夏休みの課題選考. 最近よく届きます ...</Summary>
<Url>http://auctions.yahoo.co.jp/</Url>
<ClickUrl>http://wrs.search.yahoo.co.jp/l=WS1/R=6/wdm=0/IPC=jp/ln=ja/H=0/;_ylt=A8vY5mtzacJKZ54Ail0DUAx.;_ylu=X3oDMTB2azJrdmpwBGNvbG8DdwRsA1dTMQRwb3MDNgRzZWMDc3IEdnRpZAM-/SIG=11g1gugog/EXP=1254341363/*-http%3A//auctions.yahoo.co.jp/</ClickUrl>
<ModificationDate>1254150000</ModificationDate>
<MimeType>text/html</MimeType>

<Cache>
<Url>http://wrs.search.yahoo.co.jp/l=WS5/R=6/;_ylt=A8vY5mtzacJKZ54Ai10DUAx.;_ylu=X3oDMTBwYmwxdWo4BGNvbG8DdwRwb3MDNgRzZWMDc3IEdnRpZAM-/SIG=17a22mbm0/EXP=1254341363/*-http%3A//cache.yahoofs.jp/search/cache?ei=UTF-8&amp;appid=[your appid]&amp;query=YAHOO&amp;results=10&amp;u=auctions.yahoo.co.jp/&amp;w=yahoo+yahoo%21&amp;d=RMH9It29TjTh&amp;icp=1&amp;.intl=jp</Url>
<Size>82398</Size>
</Cache>
</Result>

<Result>
<Title>Yahoo!路線情報</Title>
<Summary>出発地、目的地から、鉄道、航空便等を対象に路線経路、電車運賃、定期代、最終電車時刻表を検索。全国のJR、私鉄、地下鉄の運行情報も。 ... Yahoo!JAPAN IDでログインすると、「運行情報の設定」から、よく使う路線を登録し、 ...</Summary>
<Url>http://transit.map.yahoo.co.jp/</Url>
<ClickUrl>http://wrs.search.yahoo.co.jp/l=WS1/R=7/wdm=0/IPC=jp/ln=ja/H=0/;_ylt=A8vY5mtzacJKZ54AjF0DUAx.;_ylu=X3oDMTB2bDEyNXM5BGNvbG8DdwRsA1dTMQRwb3MDNwRzZWMDc3IEdnRpZAM-/SIG=11j83nkgs/EXP=1254341363/*-http%3A//transit.map.yahoo.co.jp/</ClickUrl>
<ModificationDate>1254063600</ModificationDate>
<MimeType>text/html</MimeType>
<Cache>
<Url>http://wrs.search.yahoo.co.jp/l=WS5/R=7/;_ylt=A8vY5mtzacJKZ54AjV0DUAx.;_ylu=X3oDMTBwMTB0ZWFoBGNvbG8DdwRwb3MDNwRzZWMDc3IEdnRpZAM-/SIG=17du41g9i/EXP=1254341363/*-http%3A//cache.yahoofs.jp/search/cache?ei=UTF-8&amp;appid=[your appid]&amp;query=YAHOO&amp;results=10&amp;u=transit.map.yahoo.co.jp/&amp;w=yahoo+yahoo%21&amp;d=aJop8N29TjMQ&amp;icp=1&amp;.intl=jp</Url>
<Size>71645</Size>
</Cache>
</Result>

<Result>
<Title>Yahoo!グループ - 無料でメーリングリストを作成</Title>
<Summary>無料で開設できるメーリングリストサービス。予定表や共有フォルダ機能も。 ... Yahoo!グループニュースレターに連載されているシリーズ「管理人に聞け! ... Yahoo!グループひろば. 多くのグループが紹介を行っているグループです。 ...</Summary>
<Url>http://groups.yahoo.co.jp/</Url>
<ClickUrl>http://wrs.search.yahoo.co.jp/l=WS1/R=8/wdm=0/IPC=jp/ln=ja/H=0/;_ylt=A8vY5mtzacJKZ54Ajl0DUAx.;_ylu=X3oDMTB2bTU4Zm85BGNvbG8DdwRsA1dTMQRwb3MDOARzZWMDc3IEdnRpZAM-/SIG=11ep5jjua/EXP=1254341363/*-http%3A//groups.yahoo.co.jp/</ClickUrl>
<ModificationDate>1254150000</ModificationDate>
<MimeType>text/html</MimeType>
<Cache>
<Url>http://wrs.search.yahoo.co.jp/l=WS5/R=8/;_ylt=A8vY5mtzacJKZ54Aj10DUAx.;_ylu=X3oDMTBwYTZ1aGtmBGNvbG8DdwRwb3MDOARzZWMDc3IEdnRpZAM-/SIG=178nttjuq/EXP=1254341363/*-http%3A//cache.yahoofs.jp/search/cache?ei=UTF-8&amp;appid=[your appid]&amp;query=YAHOO&amp;results=10&amp;u=groups.yahoo.co.jp/&amp;w=yahoo+yahoo%21&amp;d=XMKwGN29TjTL&amp;icp=1&amp;.intl=jp</Url>
<Size>27815</Size>
</Cache>
</Result>

<Result>
<Title>Yahoo!ブログ</Title>
<Summary>無料ブログサービス。容量無制限。 ... Yahoo!ブログでは、インターネット全体に公開されている投稿記事、投稿日時などの投稿に関する情報を、研究目的利用に限定して大学、独立行政法人等の研究機関に提供します。 ...</Summary>
<Url>http://blogs.yahoo.co.jp/</Url>
<ClickUrl>http://wrs.search.yahoo.co.jp/l=WS1/R=9/wdm=0/IPC=jp/ln=ja/H=0/;_ylt=A8vY5mtzacJKZ54AkF0DUAx.;_ylu=X3oDMTB2dW8yNmN0BGNvbG8DdwRsA1dTMQRwb3MDOQRzZWMDc3IEdnRpZAM-/SIG=11dihhg5k/EXP=1254341363/*-http%3A//blogs.yahoo.co.jp/</ClickUrl>
<ModificationDate>1254150000</ModificationDate>
<MimeType>text/html</MimeType>
<Cache>
<Url>http://wrs.search.yahoo.co.jp/l=WS5/R=9/;_ylt=A8vY5mtzacJKZ54AkV0DUAx.;_ylu=X3oDMTBwOTRzYmZlBGNvbG8DdwRwb3MDOQRzZWMDc3IEdnRpZAM-/SIG=177hm12tf/EXP=1254341363/*-http%3A//cache.yahoofs.jp/search/cache?ei=UTF-8&amp;appid=[your appid]&amp;query=YAHOO&amp;results=10&amp;u=blogs.yahoo.co.jp/&amp;w=yahoo+yahoo%21&amp;d=DgNm1N29TjTN&amp;icp=1&amp;.intl=jp</Url>
<Size>59707</Size>
</Cache>
</Result>

<Result>
<Title>Yahoo!メール - 無料なのに充実! ずっと使い続けられるメール</Title><Summary>1つのYahoo! JAPAN IDにつき1人の利用者とした場合。( 2009年5月現在) ... サービス連携 - 一緒に使うとさらに便利なYahoo! JAPANのサービス. 新着メールをすぐに確認できるYahoo!ツールバーなど 詳細はこちら ...</Summary>
<Url>http://promo.mail.yahoo.co.jp/</Url>
<ClickUrl>http://wrs.search.yahoo.co.jp/l=WS1/R=10/wdm=0/IPC=jp/ln=ja/H=0/;_ylt=A8vY5mtzacJKZ54Akl0DUAx.;_ylu=X3oDMTEwc3RuNTk4BGNvbG8DdwRsA1dTMQRwb3MDMTAEc2VjA3NyBHZ0aWQD/SIG=11if69e2n/EXP=1254341363/*-http%3A//promo.mail.yahoo.co.jp/</ClickUrl>
<ModificationDate>1254063600</ModificationDate>
<MimeType>text/html</MimeType>
<Cache>
<Url>http://wrs.search.yahoo.co.jp/l=WS5/R=10/;_ylt=A8vY5mtzacJKZ54Ak10DUAx.;_ylu=X3oDMTBxNTUzbTg4BGNvbG8DdwRwb3MDMTAEc2VjA3NyBHZ0aWQD/SIG=17cl635r9/EXP=1254341363/*-http%3A//cache.yahoofs.jp/search/cache?ei=UTF-8&amp;appid=[your appid]&amp;query=YAHOO&amp;results=10&amp;u=promo.mail.yahoo.co.jp/&amp;w=yahoo+yahoo%21&amp;d=ATIFJd29Ti6F&amp;icp=1&amp;.intl=jp</Url>
<Size>7647</Size>
</Cache>
</Result>
</ResultSet>

GAE/Jではファイルシステムへの書き出しができないので、取得した上記のデータはXPathで解析して、CSV(Text)形式でクライアントに渡すことにした。

URL FetchのトリガーはjspからのXHRで発生させ、< Title >と< Url >下のテキストノードを、YUIのData Tableに表示した。

f:id:tetsuya_odaka:20091003161530p:image

いつものことであるが、JavaXMLをParseするのはやりにくいし、PHPと比較して大仰な感が否めない(mezawa氏が、同じようなことをいっていたが、その通りだと思う)。とりあえずは、メモとして残しておこう。

以下の作業は、GAE/JのプラグインインストールされたGanymedeで行った。


プロジェクトの作成

YUI2.7.0とStruts1.3を使うので、先のログ「GAE/Jの認証をタイムアウトさせる」からプロジェクトをコピーする。HttpClientが必要になるので、apache.orgからダウンロードする(HttpClient v4.0を用いた)。


log4j.propertiesの修正

log4j.logger.httpclient.wire.header=WARN,A2

の一文を追加する。以下に全文を示す。

# Configure the console as our one appender
log4j.appender.A1=org.apache.log4j.ConsoleAppender
log4j.appender.A1.layout=org.apache.log4j.PatternLayout
log4j.appender.A1.layout.ConversionPattern=%d{HH:mm:ss,SSS} %-5p [%c] - %m%n

# tighten logging on the DataNucleus Categories
log4j.category.DataNucleus.JDO=WARN, A1
log4j.category.DataNucleus.Persistence=WARN, A1
log4j.category.DataNucleus.Cache=WARN, A1
log4j.category.DataNucleus.MetaData=WARN, A1
log4j.category.DataNucleus.General=WARN, A1
log4j.category.DataNucleus.Utility=WARN, A1
log4j.category.DataNucleus.Transaction=WARN, A1
log4j.category.DataNucleus.Datastore=WARN, A1
log4j.category.DataNucleus.ClassLoading=WARN, A1
log4j.category.DataNucleus.Plugin=WARN, A1
log4j.category.DataNucleus.ValueGeneration=WARN, A1
log4j.category.DataNucleus.Enhancer=WARN, A1
log4j.category.DataNucleus.SchemaTool=WARN, A1

log4j.rootLogger=DEBUG,A2
log4j.appender.A2=org.apache.log4j.ConsoleAppender
log4j.appender.A2.layout=org.apache.log4j.PatternLayout
log4j.appender.A2.layout.ConversionPattern=%d{HH:mm:ss,SSS} %-5p [%c] - %m%n
log4j.logger.org.apache.struts=WARN,A2
log4j.logger.org.apache.commons=WARN,A2
log4j.logger.httpclient.wire.header=WARN,A2

Actionの作成

コピーしてきた.javaファイル(javaプログラム)は不要なので破棄し、次のActionクラスを作成する。このサンプルでは、URL Fetchをする際のキーワードを「Yahoo(英半角)」とした。日本語を利用する際には、urlエンコーディングをしなければならない。また、XMLをParseするに際してはIBMのサイトを参考にした。Yahoo! Web Searchから得られる結果には、name spaceが定義されているので、それを意識しなくてはならない(name spaceが定義されている場合のXPathの利用については、こちらのサイトを参考にした。)。

package test;

import java.io.BufferedReader;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;

import java.net.MalformedURLException;
import java.net.URL;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.struts.action.Action;
import org.apache.struts.action.ActionForm;
import org.apache.struts.action.ActionForward;
import org.apache.struts.action.ActionMapping;

import org.w3c.dom.Document;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathExpressionException;
import javax.xml.xpath.XPathFactory;

public class YahooSearchAction extends Action {
      private static final Log log = LogFactory.getLog(YahooSearchAction.class);

	private static final String YAHOO_SEARCH_URL=
		"http://search.yahooapis.jp/WebSearchService/V1/webSearch?appid=WNislC2xg657Ewox0C7K8jehGPbPyM3vrmx99lgvZPkjr8I.GQ6gnLfTwtdmmcg7Jrg-&query=yahoo&results=10";
	
	private static final String PATH_TITLE 
    	= "/urn:yahoo:jp:srch:ResultSet/urn:yahoo:jp:srch:Result/urn:yahoo:jp:srch:Title/text()";
      private static final String PATH_URL 
    	= "/urn:yahoo:jp:srch:ResultSet/urn:yahoo:jp:srch:Result/urn:yahoo:jp:srch:Url/text()";

    public ActionForward execute(
    	ActionMapping mapping,
        ActionForm form,
        HttpServletRequest request,
        HttpServletResponse response) throws IOException
    {
    	
    	String searchedResult = null;
    	InputStream is = null;
    	
    	try {
             URL url = new URL(YAHOO_SEARCH_URL);
             BufferedReader reader = new BufferedReader(new InputStreamReader(url.openStream(),"utf-8"));
             String line;
             StringBuffer sb = new StringBuffer();

             while ((line = reader.readLine()) != null) {
            	 sb.append(line);
             }
             reader.close();
             
             searchedResult = sb.toString();
             is = new ByteArrayInputStream(searchedResult.getBytes("utf-8"));              

         } catch (MalformedURLException e) {
 			e.printStackTrace();
         } catch (IOException e) {
 			e.printStackTrace();
         }
    	
    	/*
    	 * Java XPath APIを参考
    	 * http://www.ibm.com/developerworks/jp/xml/library/x-javaxpathapi.html
    	 */
    	DocumentBuilderFactory domFactory = DocumentBuilderFactory.newInstance();
        domFactory.setNamespaceAware(true); // never forget this!
        DocumentBuilder builder;
	try {
		// Documentオブジェクトの作成
		builder = domFactory.newDocumentBuilder();
		Document doc = builder.parse(is);
	        
	        // XPath式の作成と評価
	        XPathFactory factory = XPathFactory.newInstance();
	        XPath xpath = factory.newXPath();
	        XPathExpression expr 
	         = xpath.compile(PATH_TITLE);
	        XPathExpression expr2 
	         = xpath.compile(PATH_URL);

	        // XPath式で、Documentオブジェクトを検索する
	        Object result 	= expr.evaluate(doc, XPathConstants.NODESET);
	        Object result2 	= expr2.evaluate(doc, XPathConstants.NODESET);
	        // NodeListの取得
	        NodeList nodes 	= (NodeList) result;
	        NodeList nodes2 = (NodeList) result2;
	        log.debug("number of nodes; "+nodes.getLength());
	        
	        StringBuffer sb = new StringBuffer();
	        byte[] bStr;
	        
	        for (int i = 0; i < nodes.getLength(); i++) {
	        	sb.append(nodes.item(i).getNodeValue());
	        	sb.append(",");
	        	sb.append(nodes2.item(i).getNodeValue());
	        	sb.append("\n");
	        }
	        
        	bStr = sb.toString().getBytes("UTF-8");
              response.setContentType("text/html; charset=UTF-8"); 
              ServletOutputStream outputStream;
              outputStream = response.getOutputStream();
              outputStream.write(bStr);
              outputStream.flush();
	        
	} catch (ParserConfigurationException e) {
		e.printStackTrace();
	} catch (SAXException e) {
		e.printStackTrace();
	} catch (XPathExpressionException e) {
		e.printStackTrace();
	}

	return null;
    }
}

struts-config.xml

以下のように定義する。このサンプルでは、index.html表示の際に、JavascriptでActionにフォワードして、表を形成するjsp(searchResultList.jsp)を表示する。この際、ForwardActionを利用した。

<?xml version="1.0" encoding="utf-8" ?>


<!DOCTYPE struts-config PUBLIC
          "-//Apache Software Foundation//DTD Struts Configuration 1.3//EN"
          "http://struts.apache.org/dtds/struts-config_1_3.dtd">

<struts-config>


<form-beans>
    <form-bean
		name="dummyForm"
		type="org.apache.struts.action.DynaActionForm" >
	</form-bean>
</form-beans>


    <global-exceptions>
    </global-exceptions>


    <global-forwards>
        
        <forward
            name="welcome"
            path="/index.hml"/>
    </global-forwards>


    <action-mappings>
		<action path="/getYahooSearch"
			type="test.YahooSearchsAction"
			name="dummyForm"
			scope="request">
		</action>
		
	   <action path="/index"
      		type="org.apache.struts.actions.ForwardAction"
   		  	parameter="/searchResultList.jsp"/>

    </action-mappings>

    <message-resources parameter="MessageResources" />



  

  
   
</struts-config>


表を形成するjsp

YUIのData Tableを形成するjspを以下のように作成する。このjspDOM Readyのタイミングで、Actionを呼び出し、XHRでデータを取得後、Data Tableを生成する。

<%@ page contentType="text/html;charset=UTF-8" language="java" %>
<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>YUI+Strutsのサンプル</title>
<link rel="shortcut icon" href="/images/egp-favicon.ico" >

<style type="text/css"> 
body {
	margin: 2px;
	padding: 3px;
}
</style> 
 
<link rel="stylesheet" type="text/css" href="./scripts/lib/yui/build/fonts/fonts-min.css" /> 
<link rel="stylesheet" type="text/css" href="./scripts/lib/yui/build/paginator/assets/skins/sam/paginator.css" /> 
<link rel="stylesheet" type="text/css" href="./scripts/lib/yui/build/datatable/assets/skins/sam/datatable.css" /> 
<script type="text/javascript" src="./scripts/lib/yui/build/utilities/utilities.js"></script> 
<script type="text/javascript" src="./scripts/lib/yui/build/paginator/paginator-min.js"></script> 
<script type="text/javascript" src="./scripts/lib/yui/build/datasource/datasource-min.js"></script> 
<script type="text/javascript" src="./scripts/lib/yui/build/datatable/datatable-min.js"></script> 

<script>
XHRDataTableSample = function() {
	var myDataSource;
	var myDataTable;

	return{
		init:function() {

			// DataTable用:列定義
    		var myColumnDefs = [
             	{	key:"title",
                 	label:"Title",
             		parser:"text",
                 	width:250,
                 	resizeable:true,
                 	sortable:true},
                {	key:"url",
                    label:"URL",
             		parser:"text",
                    width:250,
                    resizeable:true,
                    sortable:true}
    		];

 		   	// DataTable用:コンフィグ属性
    		var myConfigs = {
            paginator: 
                new YAHOO.widget.Paginator({
                	rowsPerPage: 5,
                	template: YAHOO.widget.Paginator.TEMPLATE_ROWS_PER_PAGE,
                	rowsPerPageOptions: [10,25,50,100],
                	pageLinks: 5
            	}),
           	caption:"Yahoo Search API",
			// 列のDrag and Drop
           	draggableColumns:true,
           	// 行の選択は1つだけ
           	selectionMode:"single"
    		};

    		// DataSourceのインスタンス化;struts actionを呼ぶ
        	myDataSource = new YAHOO.util.DataSource('/getYahooSearch.do');
	        	myDataSource.responseType = YAHOO.util.DataSource.TYPE_TEXT;
    		myDataSource.responseSchema = {
   			// 行区切り
            	recordDelim: '\n',
            	// フィールド区切り
            	fieldDelim: ',',
        		fields: ['title','url']
    		};

        	// DataTableのインスタンス化
	        myDataTable = new YAHOO.widget.DataTable("output", 
	    	    myColumnDefs, myDataSource, myConfigs);

			/*
			* 行の選択補助。
			*/
			// クリックでハイライトするようにハンドラを設定
        	myDataTable.subscribe("rowClickEvent",
            	myDataTable.onEventSelectRow);
        	myDataTable.subscribe("rowMouseoverEvent", 
       			myDataTable.onEventHighlightRow);
        	myDataTable.subscribe("rowMouseoutEvent", 
       			myDataTable.onEventUnhighlightRow);

		}, // initの終わり
	   	oDS: myDataSource,
   		oDT: myDataTable
	};
}();


//DOMが完全にloadされたら、サンプルを初期化する。
YAHOO.util.Event.onDOMReady(
	//DomReadyイベントで発火するハンドラ
	XHRDataTableSample.init,
	//ハンドラに渡すオブジェクト(関数)
	XHRDataTableSample,
	//ハンドラは、上記のオブジェクトのスコープをもつ。   
	true
);

</script>
</head> 
 
<body class="yui-skin-sam"> 

<h2>Example of URL Fetch</h2>

YAHOO! JapanのWebサービスで「Yahoo」について検索した結果です。
<br>
<br>

<div id="output">
</div>

</body>
</html>

index.html

index.htmlは、以下のように簡易なものである。

<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=UTF-8">
<title>YUI+Strutsのサンプル</title>
<link rel="shortcut icon" href="../images/egp-favicon.ico" >
<script>
document.location="./index.do";
</script>
</head> 
 
<body>
</body>
</html>

web.xml

<?xml version="1.0" encoding="utf-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">

  <display-name>GAE/J Sample Application</display-name>

  	
  	<servlet>
    	<servlet-name>action</servlet-name>
    	<servlet-class>org.apache.struts.action.ActionServlet</servlet-class>
    	<init-param>
      	<param-name>config</param-name>
      	<param-value>/WEB-INF/struts-config.xml</param-value>
    	</init-param>
    	<load-on-startup>1</load-on-startup>
  	</servlet>

  	
  	<servlet-mapping>
    	<servlet-name>action</servlet-name>
    	<url-pattern>*.do</url-pattern>
  	</servlet-mapping>

  	
 	<session-config>
	  	<session-timeout>5</session-timeout>
	</session-config>

  	
  	<welcome-file-list>
    	<welcome-file>index.html</welcome-file>
  	</welcome-file-list>

</web-app>

やっぱり

ここまで書いてきて、やっぱり、「こんなに大仰なことする必要あんの?」と思ってしまった。

XMLをFetchする場合、どうしても「動的な操作」がしたいと思ってしまう。そうすると、この気持ちと、「コンパイルという行為」そのものがしっくりこない。PHPでも、Javascriptでも、スクリプト言語で処理した方がさっぱりするのだろうなあ。mezawa氏が正しいと思った。