MODxでJSON形式のデータを扱う
「MODxで複数ドメイン・複数サイトを管理する方法と問題点」の最後で書いたチャンクを連想配列のように扱う方法を改善して、汎用性の高いJSONを使うようにしてみました。
大量のデータには専用のデータベーステーブルやファイルを用意するのが便利ですが、ちょっとしたデータの場合には、MODxマネージャやテキストエディタからでも編集できるJSONのようなデータ形式の方が便利です。JavaScriptでもそのまますぐに使い回せます。
今回は、JSON形式のデータをチャンクとして用意しました。
- チャンク: json.product
{ "apple" : { "name": "りんご", "price": "150" }, "gorilla": { "name": "ゴリラの鼻くそ", "price": "525" }, "rakko" : { "name": "らっこの鼻くそ", "price": "525" }, "emotion": { "name": "この感動は", "price": "priceless" } }
これをそのままJSONとして出力する場合は、新しいドキュメントを作成し、「ページ設定」の「コンテンツタイプ」を「application/json」にして、次のようにチャンクタグを書きます。
{{json.product}}
あとは、このドキュメントにアクセスするだけでJSONが得られるので、JavaScriptなどから使うことができます(外部からの利用を禁止する場合は、利用を制限するためのスニペットを通します)。
JSONをXHTMLに展開するには、テンプレートとなるチャンクと簡単なスニペットを作ってやります(作ってみたスニペットは最後にあります)。
- チャンク: tpl.product.item
<tr> <th scope="row">[+product+]</th> <td>[+product.name+]</td> <td>[+product.price+]</td> </tr>
- ドキュメント
<table> <caption>商品詳細</caption> <thead> <tr> <th scope="col">キー</th> <th scope="col">名称</th> <th scope="col">価格</th> </tr> </thead> <tbody> <!-- 全てのデータを出力する場合 --> [[JSON? &json=`json.product` &tpl=`tpl.product.item` &prefix=`product`]] <!-- 単一のデータを出力する場合 --> <!-- [[JSON? &json=`json.product` &key=`emotion` &tpl=`tpl.product.item` &prefix=`product`]] --> </tbody> </table>
手軽にまとめて編集できる点や、もっとよい方法が見つかった場合でもデータの移行が簡単にできる点がいいです(たぶん)。
ついでに、次のようなこともできると便利そうなので、今、試しています(結構、面倒くさそうな感じですが…)。最上位のキーのみですができるようにしてみました(@json.seller 808.name
とかはできません)。
- チャンク: json.product
{ "apple": { "name": "りんご", "price": "150", "seller": "@json.seller 808" } }
- チャンク: json.seller
{ "808": { "name": "八百屋" } }
- チャンク: tpl.product.item
<tr> <th scope="row">[+product+]</th> <td>[+product.name+][+phx:if=`[+product.seller.name+]`:ne=``:then=`([+product.seller.name+])`+]</td> <td>[+product.price+]</td> </tr>
素直にデータベースを使った方がいいかもしれませんが、いちいちブラウザで編集するのは面倒です。JSONだとすぐに編集できるというメリットが大きいし、データをExcelなどで管理している場合にも、コピー&ペーストするだけなので軽いし、早いです 😐
データ同士を関連付ける必要がないのであれば、json.productの中で{{json.seller}}
と書いて、チャンクを入れ子にするようにしておけば、JSONデータを結合することができます。
スニペット: JSON
$json_sJson = isset($json) ? trim($json) : '';
$json_sKey = isset($key) ? trim($key) : '*';
$json_sTpl = isset($tpl) ? trim($tpl) : '';
$json_sPrefix = isset($prefix) ? trim($prefix) : $json_sKey;
unset($json, $key, $tpl, $prefix);
// 連想配列を再帰的に走査
if (!function_exists('json_makeHash')) {
function json_makeHash($aData = '', $sKey = '', $sPrefix = 'data') {
global $modx;
$_hash = array();
$_hash[$sPrefix] = $sKey; // キー名をセット
foreach ($aData as $_key => $_value) {
$_prefix = $sPrefix . '.' . $_key;
if (is_array($_value)) { // 多次元配列
$_hash = array_merge($_hash, json_makeHash($_value, $_key, _prefix));
} elseif (strpos($_value, '@') === 0
&& false !== $_separator = strpos($_value, ' ')) { // バインディング
$_bind_json = substr($_value, 1, $_separator - 1);
$_bind_key = trim(substr($_value, $_separator + 1));
$_bind_data = json_decode($modx->getChunk($_bind_json), true);
if (isset($_bind_data[$_bind_key])) {
$_hash = array_merge($_hash, json_makeHash($_bind_data[$_bind_key], $_bind_key, $_prefix));
} else {
$_hash[$_prefix] = '';
}
} else {
$_hash[$_prefix] = $_value;
}
}
return $_hash;
}
}
// 連想配列からデータを検索
if (!function_exists('json_find')) {
function json_find($aData = array(), $sKey = '', $sTpl = '', $sPrefix = '') {
global $modx;
$_output = $modx->getChunk($sTpl);
if ($sKey == '*') { // 全てのデータ
$_output = '';
foreach ($aData as $_key => $_value) {
$_hash = json_makeHash($_value, $_key, $sPrefix);
// [+prefix+] -> $_value or $_key
// [+prefix.key+] -> $_value['<key>'] or <key>
// [+prefix.key.key2+] -> $_value['<key>']['<key2>'] or <key2>
// ...
$_output .= $modx->parseChunk($sTpl, $_hash, '[+', '+]');
}
} elseif (isset($aData[$sKey])) { // 単一のデータ
$_hash = json_makeHash($aData[$sKey], $sKey, $sPrefix);
// [+prefix+] -> $aData[$sKey] or $sKey
// [+prefix.key+] -> $aData[$sKey]['<key>'] or <key>
// [+prefix.key.key2+] -> $aData[$sKey]['<key>'][<key2>'] or <key2>
// ...
$_output = $modx->parseChunk($sTpl, $_hash, '[+', '+]');
}
return $_output;
}
}
// チャンクのJSONをデコード(PHP5)
// PHP4の場合はJSONモジュール/ライブラリを使う。
$json_aData = json_decode($modx->getChunk($json_sJson), true);
return json_find($json_aData, $json_sKey, $json_sTpl, $json_sPrefix);
JSONといいつつ、実際にはほぼ連想配列を処理するスニペットですが、JSONファイルを読み込んだり、JavaScriptからJSONを取得したり、反対にJSONを出力する機能を付けても面白いかもしれません。使い道は少なそうですが… :p
トラックバック (0)
この記事へのトラックバックはまだありません。
コメント (0)
この記事へのコメントはまだありません。