FileMaker 作るメディア管理DBの派生、メディアファイルから情報を取得して専用メタテーブルに展開して利用します。ファイルメーカー内製の関数GetContainerAttributeを利用します。
前提として、メインのテーブルがすでにあってメディア管理が成り立っている状態です。IDがあり、オブジェクトフィールドがあります。そのオブジェクトフィールドに登録したメディアのメタデータを取得して利用するという話でございます。
メタデータの取得と利用
以前、FileMakerでメディア管理 – メタデータの取得で、取得をレベルに分けました。
LEVEL 1 何もしない
LEVEL 2 GetAsText
LEVEL 3 GetContainerAttribute
LEVEL 4 AppleScript
LEVEL 5 Exiftool
LEVEL 3 まではファイルメーカーの機能だけで実現できます。今回その LEVEL 3 GetContainerAttribute でメタデータを取得します。取得した後それを専用テーブルに展開するところまで踏み込みます。
このポストは FileMakerメディア管理の作り方 R8 の補足記事でもあります。
取得LEVEL 3
取得方法は簡単です。オブジェクトフィールドからメタデータをゲットする関数を使って計算させます。
GetContainerAttribute( オブジェクト; "all" )
上手くいけば下記ようにデータが網羅されます。
[General] Filename: IMGP4954.jpg Storage Type: File Reference MD5: 57AE7960CB988DEE7D3F4256F00C844C File Size: 8144885 Internal Size: 140 External Size: 8144885 External Files: 1 [Image] Width: 6000 Height: 4000 DPI Width: 72 DPI Height: 72 Transparency: 0 (False) [Photo] Orientation: 1 (Normal) Created: 2021/05/10 8:05:54 Modified: 2021/09/08 2:44:03 Latitude: Longitude: Make: RICOH IMAGING COMPANY, LTD. Model: PENTAX K-70
取得したデータの束を入れておくフィールドを追加しておきましょう。フィールドを使わず変数で済ませてもいいんですが、ここは分かりやすくフィールドにしておきます。「GLB_field」というフィールドに格納しましょう。
利用
「GLB_field」はグローバルフィールドですが、普通のフィールドにしてデータを放り込んでもいいんです。検索すればヒットするし、レイアウト上に配置すれば内容を目視で確認もできます。それ以前に、そもそも「all」で全部ゲットしなくても必要な項目だけをさくっと取得するのも現実的です。
で、それは今回言いっこなしということで、データを加工してメタテーブルに仕上げましょう。今後、もっと多くのメタデータをドバッと取得するときの予行演習と考えてもよろしいです。で、ここではこうします。
- 別途専用テーブルにレコードとして展開します。
- 利用の際はポータルで表示します。まとめて表示したり、フィルタしたりします。
- 特に重要と思える項目については、フィールドとして昇格させてもいいでしょう。
では行きます。
専用テーブルに展開する
取得したデータを専用テーブルに展開すると、完成形はこのようになります。これを作るのが最初の目的になります。
GetContainerAttributeで取得したテキストデータは、改行で区切られたリストと言えます。それは概ね「 項目名: 値 」その他の形になっています。これを専用metaテーブルにレコード化します。
metaDataテーブルのフィールド
メタデータを扱う専用テーブルをこしらえます。metaDataと名付けました。必要なフィールドは次の通り。
ID
メインデータと繋げるための ID フィールドは必須です。
key と value
基本かつ重要なフィールドは key(項目)と value(値)です。コンピュータの世界というのは概ね項目と値でできています。世はすべてkeyとvalueなのです。これが宇宙を司るアイデンティティの砦です(何言ってんだこいつ)
tool
今回はGetContainerAttributeの話だけをしているので関係ないですが、先々は別の取得方法を使います。そこで、tool フィールドを作成し、取得元というか取得方法を記していきたいと思います。今回なら “GetContainerAttribute” なので “GCA” です。
group
取得した GetContainerAttribute のデータは、グループ分けがされています。 [General] や [image] がそれです。グループも生かしましょう。group フィールドを作りました。
他にもフィールドがあります。最初に GetContainerAttribute の結果を格納するフィールド、ポータル使用時にフィルタや検索で使うフィールドなどです。これらは全てグローバルフィールドです。
GetContainerAttribute をレコードに分配
GetContainerAttributeで取得した内容をmetaDataテーブルに分配してレコード化するスクリプトを作ります。
オブジェクトフィールドから GetContainerAttribute “all” でゲットしたテキストは言わば改行区切のテキストです。1行ずつ処理してフィールドに転記していくという流れです。
処理部分では、改行テキストの規則制を見つけて上手に整形することが要になります。
GetContainerAttribute データの規則
GetContainerAttributeで取得したテキストを眺めればその規則性にすぐに気づきます。
- 改行されたリストになっている
- 空白行が存在する
- 先頭に [ ] で囲まれた文字列の行は、それ以下の行のグループを示している
- 項目と値の行は、セパレータ「: 」(コロンとスペース)を挟んで左側が項目、右側が値になっている
簡単な規則が発見できましたので、分配してレコード化するのも容易いです。
スクリプトの流れ
1 事前にいろいろ変数を仕込んで準備
必要素材をすべて変数に入れておきます。
- 現在のメインテーブルでアクティブなレコードのIDを変数 $ID に保存
- GetContainerAttribute の処理だから、変数 $type に「GCA」と保存
- ゲットした本文を一応変数 $vals に保存
変数を設定 [ $ID ; 値: メインテーブルのID ] 変数を設定 [ $tool ; 値: "GCA" ] 変数を設定 [ $vals ; 値: metaData::GLB_field ]
2 metaテーブルを新規ウインドウで開いて作業
変数の準備を整えたら、目的のmetaテーブルを新規ウインドウで開きます。レイアウト切り替えでもどっちでもいいんですが、ここでは新規ウインドウで。最後に閉じます。
3 $vals をループで1行ずつ処理していく
ループで $vals を1行ずつ処理していきます。いつも使うLoopテンプレです。変数 $vc(行数)と $c = 0(カウンタ) を作ってループ開始、$c に 1 を足して exit loop if を設定して本チャン処理します。
1. 変数を設定 [ $vc ; 値: ValueCount ( $vals )] 2. 変数を設定 [ $c ; 値: 0 ] 3. Loop 4. 変数を設定 [ $c ; 値: $c + 1 ] 5. Exit Loop if [ $c > $vc ] 6. 変数を設定 [$gv = GetValue ( $vals ; $c )] 7. 〜ここに肝心の処理〜 8. end Loop
ここで、慣れた人なら「カウンタが $i じゃなくて $c って何だよ馬鹿かこいつ」と思われたかもしれません。達人の間ではカウンタは $i と書くのが通例のようですね。はい。独学の悲しさ、counter の c で $c と書いてしまう癖が付いてしまい取れません。
「〜ここに肝心の処理〜」の本チャン処理についてはもう少し後で。
4 すべて終わったらウインドウを閉じて終わり
以上で終わりですが、この一連の処理を「いつどのように行うか」によって、最初に根本的な分岐を作っておく必要があります。
二度目以降の同じ処理のために
この措置、一度目ならいいんですが、二度目以降同じ処理を繰り返すと、テーブルに同じレコードがどんどん追加されていってマズいです。すでにデータがある場合の処理を最初に付けておくのが良いと思います。
レコードのループ × vals行のループを繰り返して「等しいとスキップ、差異があると上書き、存在しないなら新規」の工程を踏むのが正統です。でも面倒です。将来的には必要かもしれませんが今は面倒なのでこうします。
既存を全部削除して常に新規で作ります。これならかんたん。
最初に metaDataテーブルのレイアウトを開くとき、ID と tool で検索、既存があれば全部削除して、対象レコードを0にしてからLoop作業を開始します。
何しろ、重複レコードを生まないような工夫は必須でございます。
ということで、テンプレ的な流れは以上です。ここからは、さっき省略した肝心の本チャン処理について説明します。
行の処理
では「〜肝心の処理〜」の中身いきます。中身とは、行のレコード化です。
GetValue
まずは GetValue して行を抜き出すところから。すでにカウンタ$cがありますから、$c行目をいただけば良いです。変数 $gv に入れておきましょう。変数の名前についての苦情は受け付けません。
変数を設定 [ $gv ; 値: GetValue ( $vals ; $c ) ]
行を抜き出しましたので処理します。行の中身は、上のほうで判明した通り次のいずれかが想定されます。
A. 空白行 → 何もしない。
B. ” [ ” で始まっていればグループ名である → 次のグループ名が登場するまでの共通のグループ名の値として変数に保存しておく。
C. “: ” が含まれれば「項目と値」である → 新規レコードを作成して必要フィールドを埋める。ID、グループ名、項目、値、あと tool に「GCA」と。
B [ group ] の行
もし[ ] で囲まれたグループを示す行なら
グループ名を変数 $group に保存します。” [ ” と ” ] ” はいらないから置換して消してしまいます。グループ名だけを頂いときます。それだけです。
変数を設定 [ $group ; 値: substitute ( $gv ; [ "[" ; "" ] ; [ "]" ; "" ] ) ]
C 項目: 値 の行
項目: 値 の行はメイン行なのでレコードを作成して分配します。
1 $gv のセパレータ( “: ” )を改行に置換して1行目が項目名(Key)、2行目が値(value)です。変数 $key と $value に入れておきましょうか。
2 新規レコードを作成
3 フィールドを埋める
ID に $ID
tool に “GCA”
groupに $group
key に $key
value に $value
以上おわり。ここまで済むと End Loopに到達し、Loopの最初に戻ります。そうするとカウンタ$c に1が足され、$vals の$c行目を対象に同じ処理を繰り返します。
最後の行まで処理が終わってloopの最初でカウンタ$cが$vcを超えた時点でループ終了。お疲れ様でした。
これでmetaテーブルにだーっとレコードが作成されました。
ポータルで表示
metaテーブルにデータがレコードとして収まりました。メインテーブルとは1対多の関係です。メインテーブルのレイアウト上にポータル表示で表示してみましょう。
このような網羅の形でもいいし、特定のkeyだけをフィルタすることも有効です。
フィルタ・検索
網羅タイプのポータルではフィルタや検索の機能が欲しくなります。GetContainerAttribute の今は大した情報量じゃないので目視で十分ですが、いずれメタデータが増えると必要になりましょう。
少々仕込みに手間が必要ですが、ポップアップでKeyを選択して狙ったkeyだけ表示を絞り込むなんてインターフェイスもよく使います。
普通の検索と異なり、ポータルでは「フィルタ」の計算式に書く内容がすべてです。フレキシブルに検索したい場合、フィルタに書く計算式が難しくていつも頭を抱えます。
ただ、これまで頭を抱えていましたが最近フィルタ計算式の知られざる真実を知り、心が晴れました。つまり、量子はもつれています。違った。フィルタ条件に当てはまらない場合にデフォルト挙動に設定したいわけですが、このとき「1」と書けば良いだけだと知りました。これは衝撃。
例えばグローバルフィールド「g_group」とgroupが等しければフィルタ、空ならデフォルト状態を目指すとき
if ( not IsEmpty ( metaData::g_group ) ; metaData::group = metaData::g_group ; 1 )
と、こう書けば良いだけでした。複数フィールドを使う場合はこの if を and で繋げます。まじでこの「1」を知らない十余年、デフォルト条件をわざわざ設定して複合的に処理する煩わしさに苦しんできました。
フィルタしたいフィールドがどれで、それを指定するフィールドがいくつあるかは作ってるデータベースによって異なりますから、ここではこれ以上しつこく触れませんが、このポストは FileMakerメディア管理の作り方 R8 メタデータテーブル の補足記事でありますから、MediaDB.fmp12 に特化したフィルタについては、そちらに詳細を記しております。
フィールドに昇格
1対多のリレーションでは面倒なことが一つあります。メインテーブルから値を利用することが気軽にできないことです。常に面倒なスクリプトが必要で、使い勝手が悪いんです。
頻繁に利用する重要データであるなら、metaテーブルの1レコードではなく、メインテーブルにフィールドとして作っておくのが良いと思われます。
ということで、メタデータの内いくつかをフィールドとして昇格させます。
その方法は、これは「レコード化」のスクリプトの行の処理の中に紛れ込ませるのがベストでしょう。
ID や key や value を入力していく際に「もし$keyが○○ならフィールド○○に$valueを記入」という一文を付け加えます。
ここでまた根源的なそもそも論を言いますと、もし特定keyをいくつか欲しいだけなら、その項目を個別に取得すればいいんであって、メタデータの網羅もいらないしmetaテーブルも不要です。つまりこのポストの全否定ですが、ここでは「それが必要なんだ」という気持ちを尊重しておきました。