ごきげんよう。mです。
急遽お仕事でJAVA ServletとJSPを覚えなくてはならなくなりましたので、祝日に家で分厚い本とにらめっこしながらキーボードをカタタンタンしていましたw
どうせなのでということでウチのPHPで書いてある「TJコレクション」をJSPとJAVA Servletに書き直していました。
ですが、PHPではスムーズに終わったXMLのパース(解析)に1日かかってしまったのでメモがてら書き残しておきますw
JAVAでXMLの任意の要素の値を取得する
Amazon API(Product Advertising API)に検索のためのURLを送るとXMLで結果が帰ってきます。
こんな感じのです。
これの、本のタイトルとURL、金額が欲しいのですがPHPのように
$book_title = $Item->ItemAttributes->Title;
なんて取らせてくれません!
JAVAさんめ、意地悪しないでください><
そんなわけでして、祝日に悶絶しながら「Priceおちてこない……Priceおちてこない……ブライスほしくなってきた……」とかやっておりました。
試行錯誤して作ったコードを載せておきます。
※Amazonからxmlを持ってくるコード
package collection;
import java.io.*;
import java.net.URL;
import java.net.URLConnection;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;
public class SearchAmazon extends HttpServlet{
@Override
public void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
// リクエストのキーと値のMap
Map<String, String> keyMap = new HashMap<String, String>();
keyMap.put("AWSAccessKeyId", "ご自分のもので!");
keyMap.put("Version", "2011-08-02");
keyMap.put("Operation", "ItemSearch");
keyMap.put("ResponseGroup", "Small,Images,Offers");
keyMap.put("AssociateTag", "ご自分のもので!");
keyMap.put("Service", "AWSECommerceService");
keyMap.put("SearchIndex", "All");
keyMap.put("Keywords", "Little busters");
keyMap.put("ItemPage", "1");
//amazon apiを叩くURL作成
SignedRequestsHelper signedRequestsHelper = new SignedRequestsHelper();
String urlStr = signedRequestsHelper.sign(keyMap);
URL url = new URL(urlStr);
//テスト用。削除
PrintWriter out = response.getWriter();
System.out.println(url);
//URL接続
URLConnection con = url.openConnection();
InputStream is = con.getInputStream();
Document document= null;
//DOMを使うためのインスタンス取得
try {
document= DocumentBuilderFactory.newInstance().newDocumentBuilder().parse(is);
} catch (SAXException e) {
// TODO 自動生成された catch ブロック
e.printStackTrace();
} catch (ParserConfigurationException e) {
// TODO 自動生成された catch ブロック
e.printStackTrace();
}
//root要素取得
Element elementRoot = document.getDocumentElement(); //……①
//itemsリスト取得(日記に貼り付けたらこの部分のコードが崩れましたので注意)
NodeList localNodeList =*1.getElementsByTagName("Item");
//……②
//XMLから要素を抜き取る自作関数
CommonFunc common = new CommonFunc();//……③
//itemName取得
for (int i = 0; i < localNodeList.getLength(); i++) {
Element elementItem = (Element) localNodeList.item(i);//……④
String elementName1 = {"MediumImage","URL"};
String s = common.searchXmlValue(elementName1, 0, elementItem);
out.println("imageUrl : " + s);
String elementName2 = {"ItemAttributes","Author"};
s = common.searchXmlValue(elementName2, 0, elementItem);
out.println("Author : " + s);
String elementName3 = {"ItemAttributes","Title"};
s = common.searchXmlValue(elementName3, 0, elementItem);
out.println("Title : " + s);
String elementName4 = {"Offers","Offer","OfferListing","Price","Amount"};//……⑤
s = common.searchXmlValue(elementName4, 0, elementItem);//……⑥
out.println("price : " + s);
String elementName5 = {"DetailPageURL"};
s = common.searchXmlValue(elementName5, 0, elementItem);
out.println("Detail : " + s);
}
}
}
※XMLに対して再帰処理を行って、目的の要素から値を抜き出す関数
package collection;
import org.w3c.dom.Node;
public class CommonFunc {
/*
* XMLのターゲット要素の端まで再帰処理で値を探す
* param : 0から要素順に入った配列、配列の確認中の位置、ノード
*/
public String searchXmlValue(String targetNodeName, int nodeNo, Node node) {
String s = null;
//ノードか探索範囲がnullなら再帰から抜ける。
if(node.getNodeName() == null) return s;
if(targetNodeName[nodeNo] == null) return s;
//兄弟ノードを走査する。……⑦
for (Node ch = node.getFirstChild();ch != null;ch = ch.getNextSibling()) {
//ターゲットと一致したら値を抜いてみる
if (targetNodeName[nodeNo].equals(ch.getNodeName())) {
s = ch.getFirstChild().getNodeValue();
//もし値がnullで帰ってきたら子ノードありということで再帰……⑧
if(s == null) s = searchXmlValue(targetNodeName, nodeNo + 1, ch);
break;
}
}
return s;
}
}
///////////////////////////////////////////////////////////////
説明
兄弟ノードを走査して、オシリまで行くか何かにぶつかったら(値が入っていたら)帰ってきます。
MAPをつかっている上の部分はAmazon関連です。
こちらも今後説明しましょう~。
今日はXMLの説明です。
①まずはXMLのルート部分を取得します。
②ルートから続く子ノードをリストにしてしまいます。
③XMLから値を抜く自作関数(下の方に書いたコード)を宣言。そんな半端なところでと思っても気にしないでいましょう(ぉ
④ルート直下の子ノードをひとつずつ見ていきます。
⑤⑥XMLの親ノードから順に配列に入れていきます。
例えばPriceは
Offersの中のOfferの中のOfferListingの中のPriceの中のAmountにありますから(長いよ!)
String elementName[] = {"Offers","Offer","OfferListing","Price","Amount"};
String s = common.searchXmlValue(elementName4, 0, elementItem);
こんな感じで渡してあげると、金額が帰ってきます。
真ん中の0は再帰のときのカウント用です。
再起するたびに0番目の配列要素、1番目の配列要素……と見ていきます。
要素がなくなったらnullでも帰ってきます。
⑦⑧関数では、ひたすら兄弟ノード(レベルが同じ場所のノード)を全部検索しています。
配列で渡した要素とぶつかると、一旦入れてみます。
nullだった場合は子ノードがありますので、1レベル深くして、またノードを検索します。
さらにnullだったら……
と再帰処理で、値が出てくるかノードが尽きるか、設定した配列が尽きるかまで繰り返します。
もっとスマートな方法がありそうですが、ひとまずこれがシンプルでわかりやすいかな、といった感じで書いてみましたw
そういえばAmazon APIに送るためのURL作成を公式どおりにやっても動かずコードをイジる必要があったので、そこも今度書いてみますねw
WEB拍手レス!
たくさんの拍手をありがとうございます!
ほっぽちゃん人気っ!
やっぱりみなさんもロリなのですね(ぅぉぃ!!
何はともあれ、みなさんに喜んでもらえてmは幸せですw
*1:Element)elementRoot.getElementsByTagName("Items").item(0