読者です 読者をやめる 読者になる 読者になる
WEB拍手ぱちぱちっと
Clap/拍手

01.MENU
Blog  / ブログ
Videos  / 動画
Pictures  / 絵
Game Materials  / 素材
SS(ShortStory)  / 小ネタ

02.MENU
Novels  / 小説
Chat  / チャット
BBS  / 掲示板
Others  / その他
Old Top  / 旧Top

Traffic Jam Products


JAVAでAmazon APIから帰ってきたXMLの任意の要素の値を取得するメソッド

ごきげんよう。mです。

 

急遽お仕事でJAVA ServletJSPを覚えなくてはならなくなりましたので、祝日に家で分厚い本とにらめっこしながらキーボードをカタタンタンしていましたw

 

どうせなのでということでウチのPHPで書いてある「TJコレクション」をJSPJAVA Servletに書き直していました。

 

ですが、PHPではスムーズに終わったXMLのパース(解析)に1日かかってしまったのでメモがてら書き残しておきますw

 

JAVAXMLの任意の要素の値を取得する

 

Amazon API(Product Advertising API)に検索のためのURLを送るとXMLで結果が帰ってきます。

こんな感じのです。

f:id:m_training:20150211224736p:plain

これの、本のタイトルと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

Official LINE Account
友だち追加
@hgf7288s