年末からちょっとヒマだったので、少しXMLについて調べていました。と言ってもXMLというよりはAmazon Web サービス(以下AWS)の研究というか、そんな感じで。
面倒なのでAWSについての説明は省いてしまいますが(必要な場合はコメントで「書けよコラ!ジャンプしてみろよ!持ってんじゃねえか!」とか書いてみてください)webservices.amazon.co.jpにリクエストを投げると、必要なデータを返してくれるサービスです。
とりあえずやりたいことは、いまぽぴンち。でやっている、アソシエイト付のAmazonへのリンクを自動化したい。自動化というか動的に作成するまではしなくていいのだけど(どちらにしてもCGIは動かせないサーバなので)、現在手動でやっているHTML構築作業をプログラムにやらせたいなーと思って。
で、とりあえず組んでみたのが以下のコード。HttpWebRequestのサンプルまんまでちょっと恥ずかしいですが(エラーチェックもぜんぜんしてないし)AWSにアクセスしてXMLを取得、そこからDOM(Document Object Model)を作成するところまでなんとかできました。
List<string> query = new List<string>();
query.Add("AWSAccessKeyId=[この辺は表向きは書かないほうがいいかも]");
query.Add("AssociateTag=popinchi-22");
query.Add("Service=AWSECommerceService");
query.Add("ResponseGroup=ItemAttributes%2CImages");
query.Add("ItemPage=1");
query.Add("Operation=ItemLookup");
query.Add("ContentType=text%2Fxml");
query.Add("IdType=ASIN");
query.Add("Version=2005-10-05");
query.Add("ItemId=" + textBox1.Text.Trim());
System.Net.HttpWebRequest req =
(System.Net.HttpWebRequest)System.Net.HttpWebRequest.Create(
"http://webservices.amazon.co.jp/onca/xml?" +
string.Join("&", query.ToArray()));
System.Net.HttpWebResponse res = (HttpWebResponse)req.GetResponse();
Stream st = res.GetResponseStream();
StreamReader sr = new StreamReader(st, Encoding.UTF8);
string html = sr.ReadToEnd();
sr.Close();
st.Close();
System.Xml.XmlDocument doc = new System.Xml.XmlDocument();
doc.LoadXml(html);
ちなみにAWSからはこんな感じでXMLが返ってきます。ネタにするのは赤間本です(笑)。
<?xml version="1.0" encoding="UTF-8"?>
<ItemLookupResponse xmlns="http://webservices.amazon.com/AWSECommerceService/2005-10-05">
<OperationRequest>
<HTTPHeaders>
<Header Name="UserAgent"></Header>
</HTTPHeaders>
<RequestId>1ETT01ZG824EZ6F9CG7K</RequestId>
<Arguments>
<Argument Name="AssociateTag" Value="popinchi-22"></Argument>
<Argument Name="ItemId" Value="4891005157"></Argument>
<Argument Name="ContentType" Value="text/xml"></Argument>
<Argument Name="IdType" Value="ASIN"></Argument>
<Argument Name="ItemPage" Value="1"></Argument>
<Argument Name="Service" Value="AWSECommerceService"></Argument>
<Argument Name="AWSAccessKeyId" Value="な・い・しょ"></Argument>
<Argument Name="Version" Value="2005-10-05"></Argument>
<Argument Name="ResponseGroup" Value="ItemAttributes,Images"></Argument>
<Argument Name="Operation" Value="ItemLookup"></Argument>
</Arguments>
<RequestProcessingTime>0.0263030529022217</RequestProcessingTime>
</OperationRequest>
<Items>
<Request>
<IsValid>True</IsValid>
<ItemLookupRequest>
<IdType>ASIN</IdType>
<ItemId>4891005157</ItemId>
<ResponseGroup>ItemAttributes</ResponseGroup>
<ResponseGroup>Images</ResponseGroup>
</ItemLookupRequest>
</Request>
<Item>
<ASIN>4891005157</ASIN>
<DetailPageURL>http://www.amazon.co.jp/gp/(略)</DetailPageURL>
<SmallImage>
<URL>
http://ec2.images-amazon.com/images/P/4891005157.01._SCTHUMBZZZ_V51803122_.jpg
</URL>
<Height Units="pixels">75</Height>
<Width Units="pixels">58</Width>
</SmallImage>
<MediumImage>
<URL>
http://ec2.images-amazon.com/images/P/4891005157.01._SCMZZZZZZZ_V51803122_.jpg
</URL>
<Height Units="pixels">160</Height>
<Width Units="pixels">123</Width>
</MediumImage>
<LargeImage>
<URL>
http://ec2.images-amazon.com/images/P/4891005157.01._SCLZZZZZZZ_V51803122_.jpg
</URL>
<Height Units="pixels">500</Height>
<Width Units="pixels">383</Width>
</LargeImage>
<ImageSets>
<ImageSet Category="primary">
(上記SmallImage~LargeImageと同内容なので省略)
</ImageSet>
</ImageSets>
<ItemAttributes>
<Author>赤間 信幸</Author>
<Binding>大型本</Binding>
<Creator Role="著">赤間 信幸</Creator>
<Label>日経BPソフトプレス</Label>
<ListPrice>
<Amount>3990</Amount>
<CurrencyCode>JPY</CurrencyCode>
<FormattedPrice>¥ 3,990</FormattedPrice>
</ListPrice>
<Manufacturer>日経BPソフトプレス</Manufacturer>
<NumberOfPages>416</NumberOfPages>
<PackageDimensions>
<Length Units="cm">24</Length>
</PackageDimensions>
<ProductGroup>Book</ProductGroup>
<PublicationDate>2006-05-18</PublicationDate>
<Publisher>日経BPソフトプレス</Publisher>
<Studio>日経BPソフトプレス</Studio>
<Title>Microsoft Visual Studio 2005によるWebアプリケーション構築技法</Title>
</ItemAttributes>
</Item>
</Items>
</ItemLookupResponse>
このXMLからこんな感じのイメージを出力したいわけです。こらそこっ、はてなダイアリーみたいとかいうなー!
ここまではなんとかなったのだけど、ここから先をどうするかというところでいろいろ考えていたり。
XmlDocument.LoadXmlメソッドでもってDOMツリーは構築できているのだけど、そのノードにそれぞれアクセスするのはどうするかニャーとか。とりあえずこういうコードを書いてみたけど、あまりにベタすぎて目から汗が出た orz
System.Xml.XmlNode nodeItemLookupResponse = doc.ChildNodes[1];
System.Xml.XmlNode nodeItems = nodeItemLookupResponse.ChildNodes[1];
System.Xml.XmlNode nodeItem = nodeItems.ChildNodes[1];
System.Xml.XmlNode nodeMediumImage = null;
foreach (System.Xml.XmlNode node in nodeItem.ChildNodes)
{
if (node.Name == "MediumImage")
{
nodeMediumImage = node;
break;
}
}
if (nodeMediumImage != null)
{
System.Diagnostics.Debug.Print("URL:{0}", nodeMediumImage.ChildNodes[0].InnerText);
System.Diagnostics.Debug.Print("Height:{0}", nodeMediumImage.ChildNodes[1].InnerText);
System.Diagnostics.Debug.Print("Width:{0}", nodeMediumImage.ChildNodes[2].InnerText);
}
これじゃあァァァんまりだァァアァ(エシディシ)ということで、ちょっと調査。SelectNodes/SelectSingleNodeメソッドを使うとXPathからノードが取れるとな!よーしよーしよし(ムツゴロウさん)なんとかなりそうだぜ…とこんなコードを書いてみた。
System.Xml.XmlNode nodeMediumImage = doc.SelectSingleNode("/ItemLookupResponse/Items/Item/MediumImage");
if (nodeMediumImage != null)
{
System.Diagnostics.Debug.Print("あったーよ!");
}
else
{
System.Diagnostics.Debug.Print("なかったズラ");
}
しかし結果は「なかったズラ」一辺倒。うむむ、試しに適当に作ったXMLファイルだとうまく動いたりするので、何かが足りないらしい。
動かない原因を調べてみたところ、ItemLookupResponseのxmlnsが付いていると検索できないっぽいです。XMLについては素人の私ですが、とりあえずネームスペース関係らしいことぐらいはわかります。かと言って、なぜこのネームスペース指定があると検索できないのかまではさっぱりわからず。勉強不足ですね orz
それで今日一日調べていたのですけど(ヒマですね)どうやらこんな感じでやればイケるみたいです。要はXmlNameManagerクラスを作って、そこにAddNamespaceメソッドで別名を定義、選択時はその別名をつけて検索せよと。
参考:@IT:連載:.NETで簡単XML 第5回 DOMとXPath
System.Xml.XmlNamespaceManager nsManager = new System.Xml.XmlNamespaceManager(doc.NameTable);
nsManager.AddNamespace("aws", "http://webservices.amazon.com/AWSECommerceService/2005-10-05");
nodeMediumImage = doc.SelectSingleNode(
"/aws:ItemLookupResponse/aws:Items/aws:Item/aws:MediumImage", nsManager);
if (nodeMediumImage != null)
{
System.Xml.XmlNode nodeValue;
System.Xml.XmlNode nodeAttrib;
nodeValue = nodeMediumImage.SelectSingleNode("aws:URL/text()", nsManager);
System.Diagnostics.Debug.Print("URL:{0}", node.Value);
nodeValue = nodeMediumImage.SelectSingleNode("aws:Width/text()", nsManager);
nodeAttrib = nodeMediumImage.SelectSingleNode("aws:Width/@Units", nsManager);
System.Diagnostics.Debug.Print("Width:{0}{1}", nodeValue.Value, nodeAttrib.Value);
nodeValue = nodeMediumImage.SelectSingleNode("aws:Height/text()", nsManager);
nodeAttrib = nodeMediumImage.SelectSingleNode("aws:Height/@Units", nsManager);
System.Diagnostics.Debug.Print("Height:{0}{1}", nodeValue.Value, nodeAttrib.Value);
}
else
{
System.Diagnostics.Debug.Print("なかったズラ");
}
と、これでとりあえずは取得できることが判明したわけで、また一歩野望に近づいた!(何の野望だ)。
続きは気が向いたら書くことにします。