目次
クラウド連携の仕組み

クライアント(ブラウザ)から見えるのは、1つのドメイン(サーバサイド)だけである。サーバサイドは、PHP などのプログラムを介して、Yahoo! や Amazon といったクラウド・サービスが提供する WebAPI を利用する。したがって、クライアントからどんな WebAPI を利用しているのかはわからない。ここまでのデータ交換は、すべて http(s)通信で処理される。
さらに、WebAPI の裏側にはデータベースなどのシステムがあるが、クライアントから WebAPI が見えないのと同様、サーバサイドからそれらのシステムを見ることはできない。
サンプルXMLとプログラムのダウンロード
yahoosearch.xml | サンプルXMLファイル。 |
readxml4.php | サンプル・プログラム本体(PHP 4)。 |
readxml5.php | サンプル・プログラム本体(PHP 5/7/8)。 |
readxml5.php | サンプル・プログラム本体(PHP 4/5/7/8)。 |
XML のツボ


1.HTML のようなタグ構造をしているテキスト
XML は、<hoge>...</hoge> というタグ構造をなしているテキストデータである。
ただ、HTML と異なり、タグの名前は自由に設定できる(厳密には定義が必要)。
2.UTF-8 が標準
XML ファイルの冒頭行は
<?xml version="1.0" encoding="utf-8"?>
と書かれていることが多い。つまり、標準コードは UTF-8 である。
ShiftJIS や EUC-JP で書くこともできるが、PHP が用意している XML 処理関数の中には UTF-8 でないと正常に処理できないものがあるため、ここではすべて UTF-8 として扱うことにする。
3.PHP では XML を扱う方法が複数ある
PHP バージョン 4 と 5 では、同じ DOM(Document Object Model)でも互換性がほとんどない。そこで、
を利用することにする。SimpleXML は PHP バージョン 5 で導入された関数群で、DOM や XML パーサ(SAX)に比べて短いコードで XML 処理を行うことができるのが特長だ。
- PHP4 ⇒ DOM
- PHP5 ⇒ SimpleXML
XML ファイルの構造
このサービスを利用し、ある日の "中央線E233系" の検索結果の XML ファイルを用意した。
冒頭の <?xml ...> はヘッダである。
それ以降は <ResultSet> で囲まれるブロックが1つある。
<ResultSet> の下には、<Result> で囲まれるブロックが複数ある。
<Result> の下には、<Title>, <Summary>, <Url>, <ClickUrl>, <ModificationDate>, <MimeType> で囲まれるブロックが各々1つずつある。

次のページで紹介するサンプルプログラムでは、複数登場する <Title> タグの内容を、配列変数に格納することを目指す。
解説:DOM XML (PHP 4)
  90: /**
  91: * 指定XMLファイルを読み込んでDOMを返す.
  92: * @param string $xml XMLファイル名
  93: * @return object DOMオブジェクト/NULL 失敗
  94: */
  95: function read_xml4($xml) {
  96: if (! isphp5over()) return NULL;
  97: if (($fp = fopen($xml, "r")) == FALSE) return NULL;
  98:
  99: //いったん変数に読み込む
 100: $str = fgets($fp);
 101: $str = preg_replace("/UTF-8/", "utf-8", $str); //コーディング文字の置換
 102:
 103: while (! feof($fp)) {
 104: $str = $str . fgets($fp);
 105: }
 106: fclose($fp);
 107:
 108: //DOMを返す
 109: $dom = domxml_open_mem($str);
 110: if ($dom == NULL) {
 111: echo "\n>Error while parsing the document - " . $xml . "\n";
 112: exit(1);
 113: }
 114:
 115: return $dom;
 116: }
PHP4 には、XML ファイルを読み込んで DOM を返す関数 domxml_open_file があるのだが、日本語ファイルを正常に処理できないことがあったので(バージョンや OS によるものかもしれない)、ユーザー関数として用意することにした。

まず、XML ファイルをテキストファイルとみなし、いったん変数 $str にすべて読み込む。この際、冒頭行のエンコーディング指定が大文字の 'UTF-8' だと、DOM 関数群が正常に作用しないので(これも PHP のバージョンや OS に依存する問題かもしれない)、小文字の 'utf-8' に置換しておく。
XML ファイルをすべて変数 $str に読み込んだら、関数 domxml_open_mem を使って、DOM を得る。XML の構造が間違っていたり、UTF-8 で書かれていないとエラーになる。
解説:XML処理 (PHP 4)
 118: /**
 119: * 指定したXMLファイルを読み込んで,タグ名を要素名にした連想配列に読み込む.
 120: * XMLファイルはYahoo! ウェブ検索WebサービスAPIが出力するもの.
 121: * @param array $items 情報を格納する配列
 122: * @param string $xml XMLファイル名
 123: * @return int 情報の数/FALSE
 124: */
 125: function getTitles4(&$items, $xml) {
 126: $name = 'Title';
 127:
 128: if (($dom = read_xml4($xml)) == NULL) return FALSE;
 129: $resultset = $dom->get_elements_by_tagname('ResultSet');
 130: $results = $resultset[0]->get_elements_by_tagname('Result');
 131: //検索結果取りだし
 132: $cnt = 1;
 133: foreach ($results as $element) {
 134: $node = $element->get_elements_by_tagname($name);
 135: if ($node != NULL) {
 136: $items[$cnt] = $node[0]->get_content();
 137: }
 138: $cnt++;
 139: }
 140:
 141: return ($cnt - 1);
 142: }

まず、ユーザー関数 read_xml を呼び出して DOM を取得する。
次に、全体を一括りにしているタグ <ResultSet> をオブジェクトとして、メソッド getElementsByTagName を適用する。ここでは <ResultSet> は1つしかないので、$resultset[0] が全体を括る <ResultSet> オブジェクトを示す。

<ResultSet> には複数の <Result> がぶら下がっているが、$resultset[0] に対してメソッド getElementsByTagName を適用することで、これらのオブジェクトを取得できる。
<Result> は複数あるので、各々のオブジェクトは、$results[0], $results[1], $results[3]‥‥に格納されていく。

<Title> は <ResultSet> にぶら下がっているので、$results[N] に対してメソッド getElementsByTagName を適用することで、<Title> オブジェクトを取得できる。
<Title> の内容は、オブジェクトに対してメソッド get_content を適用すれば取得できる。
解説:HTML BODY作成 (PHP 4)
 144: /**
 145: * 指定したXMLを読み込んでHTML BODYを作成する.
 146: * @param string $fname XMLファイル名
 147: * @return string HTML BODY
 148: */
 149: function makeCommonBody($fname) {
 150: $myself = MYSELF;
 151: $refere = REFERENCE;
 152: $p_title = TITLE;
 153: $version = '<span style="font-size:small;">' . date('Y/m/d版', filemtime(__FILE__)) . '</span>';
 154: $width = WIDTH;
 155: $debug = '';
 156:
 157: //デバッグ情報
 158: if (! FLAG_RELEASE) {
 159: $phpver = phpversion();
 160: $isSimpleXML = function_exists('simplexml_load_string') ? 'enabled' : 'disabled';
 161: $debug =<<< EOT
 162: <p>
 163: <span style="font-weight:bold;">★デバックモードで動作中...</span><br />
 164: PHPver : {$phpver}<br />
 165: SimpleXML : {$isSimpleXML}
 166: </p>
 167:
 168: EOT;
 169: }
 170:
 171: //XMLの解釈と表示
 172: $items = array();
 173: if (file_exists($fname)) {
 174: $n = getTitles4($items, $fname);
 175: if ($n == FALSE) {
 176: $res = 'error - 正しいXMLファイル名を入力してください.';
 177: } else {
 178: $i = 1;
 179: $res = '';
 180: foreach ($items as $title) {
 181: $res .= "{$i} : {$title}<br />\n";
 182: $i++;
 183: }
 184: }
 185: } else {
 186: $res = 'ファイル名を入力してください.';
 187: }
 188:
 189: $body =<<< EOT
 190: <body>
 191: <h2>{$p_title} {$version}</h2>
 192: <form name="myform" method="post" action="{$myself}" enctype="multipart/form-data">
 193: XMLファイル:<input name="file" type="file" size="80" />
 194: <input type="submit" name="execute" value="抽出" />
 195: </form>
 196:
 197: <div style="border-style:solid; border-width:1px; margin:20px 0px 0px 0px; padding:5px; width:{$width}px; font-size:small; overflow-wrap:break-word; word-break:break-all;">
 198: <h3>使い方</h3>
 199: <ol>
 200: <li>[<span style="font-weight:bold;">XMLファイル</span>]に抽出したいファイルを入力し、[<span style="font-weight:bold;">抽出</span>] ボタンを押してください。</li>
 201: <li>抽出結果が表示されます。</li>
 202: </ol>
 203: ※参考サイト:<a href="{$refere}">{$refere}</a>
 204: {$debug}
 205: </div>
 206: <hr />
 207: {$res}
 208: </body>
 209:
 210: EOT;
 211: return $body;
 212: }
サンプル・プログラム(PHP5/7/8)
解説:SimpleXML (PHP 5/7/8)
  90: /**
  91: * Yahoo! ウェブ検索WebサービスAPIが出力するXMLから
  92: * タイトルを配列に格納する
  93: * @param array $items 情報を格納する配列
  94: * @param string $xml XMLファイル名
  95: * @return int 情報の数/FALSE
  96: */
  97: function getTitles5(&$items, $xml) {
  98: $name = 'Title';
  99:
 100: if (($ResultSet = @simplexml_load_file($xml)) == FALSE) return FALSE;
 101: //検索結果取りだし
 102: $cnt = 1;
 103: foreach ($ResultSet->Result as $element) {
 104: if (isset($element->$name)) {
 105: $items[$cnt] = $element->$name;
 106: }
 107: $cnt++;
 108: }
 109:
 110: return ($cnt - 1);
 111: }

SimpleXML はPHP5で導入された関数群で、DOMやXMLパーサ(SAX)に比べて短いコードでXML処理を行うことができるのが特長だ。
たとえば、今回のXMLファイルの <Title> の内容を参照したければ、
$ResultSet->Result->Title
と記述するだけでよい。

ユーザー関数 read_xml は不要である。
関数 simplexml_load_file を利用し、一気にXMLファイルを読み込む。

次に、ResultSet->Result まで一気に下り、複数ある <Title> の内容を配列変数 $items に逐次格納していく。

これ以外の部分はPHP4用と共通である。
サンプル・プログラム(PHP4/5/7/8)
解説:バージョン検査
  79: /**
  80: * PHP5以上かどうか検査する.
  81: * @return bool TRUE:PHP5以上/FALSE:PHP5未満
  82: */
  83: function isphp5over() {
  84: $version = explode('.', phpversion());
  85:
  86: return $version[0] >= 5 ? TRUE : FALSE;
  87: }
解説:read_xml(PHP4/5/7/8)
  89: /**
  90: * 指定XMLファイルを読み込んでDOMを返す.
  91: * @param string $xml XMLファイル名
  92: * @return object DOMオブジェクト/NULL 失敗
  93: */
  94: function read_xml($xml) {
  95: if (isphp5over()) return NULL;
  96: if (($fp = fopen($xml, "r")) == FALSE) return NULL;
  97:
  98: //いったん変数に読み込む
  99: $str = fgets($fp);
 100: $str = preg_replace("/UTF-8/", "utf-8", $str); //コーディング文字の置換
 101:
 102: while (! feof($fp)) {
 103: $str = $str . fgets($fp);
 104: }
 105: fclose($fp);
 106:
 107: //DOMを返す
 108: $dom = domxml_open_mem($str);
 109: if ($dom == NULL) {
 110: echo "\n>Error while parsing the document - " . $xml . "\n";
 111: exit(1);
 112: }
 113:
 114: return $dom;
 115: }
解説:getTitles(PHP4/5/7/8)
 117: /**
 118: * 指定したXMLファイルを読み込んで,タグ名を要素名にした連想配列に読み込む.
 119: * XMLファイルはYahoo! ウェブ検索WebサービスAPIが出力するもの.
 120: * @param array $items 情報を格納する配列
 121: * @param string $xml XMLファイル名
 122: * @return int 情報の数/FALSE
 123: */
 124: function getTitles(&$items, $xml) {
 125: $name = 'Title';
 126:
 127: //PHP4用; DOM XML利用
 128: if (isphp5over() == FALSE) {
 129: if (($dom = read_xml($xml)) == NULL) return FALSE;
 130: $resultset = $dom->get_elements_by_tagname('ResultSet');
 131: $results = $resultset[0]->get_elements_by_tagname('Result');
 132: //検索結果取りだし
 133: $cnt = 1;
 134: foreach ($results as $element) {
 135: $node = $element->get_elements_by_tagname($name);
 136: if ($node != NULL) {
 137: $items[$cnt] = $node[0]->get_content();
 138: }
 139: $cnt++;
 140: }
 141:
 142: //PHP5/7/8用; SimpleXML利用
 143: } else {
 144: if (($ResultSet = @simplexml_load_file($xml)) == FALSE) return FALSE;
 145: //検索結果取りだし
 146: $cnt = 1;
 147: foreach ($ResultSet->Result as $element) {
 148: if (isset($element->$name)) {
 149: $items[$cnt] = $element->$name;
 150: }
 151: $cnt++;
 152: }
 153: }
 154:
 155: return ($cnt - 1);
 156: }
参考サイト
- PHPでクラウド連携:参考書籍:ぱふぅ家のホームページ
- PHP: 基本的な SimpleXML の使用法:PHPマニュアル
- 第1回 Web サービス APIを使ってみる:PHPプロ!
- 初心者Web開発者の Web API 製作メモ&ノウハウ集:NAVER まとめ
- クラウド連携での高速処理:パソコンのある生活
- クラウド連携の基礎知識。連携が必要な理由と具体的な方法を解説:JBアドバンスト・テクノロジー
こうした仕組みを WebAPI、これを利用することを クラウド連携と呼んでいる(2010年代前半までは マッシュアップ(MushUp) と呼んでいた)。
WebAPI は無料で利用できるものが多い。また、WebAPI を公開する企業としても、無償でクラウド連携して顧客を呼び込んでくれるパワーユーザーの存在はありがたい。今後、WebAPI の公開が、ますます盛んになるだろう。
というわけで、このコーナーは「ぱふぅ家のホームページ」100万回アクセス記念として、PHP で Web API を利用し、クラウド連携していく方法を説明していくことにする。