2019年12月30日月曜日

Kaleidox: Table

前回はKaleidoxの中軸となるRecordオブジェクトについて説明しました。

今回はRecordオブジェクトと同様にKaleidoxの中軸オブジェクトであるTableオブジェクトについて説明します。

Tableオブジェクトは文字通り表を記述するオブジェクトで、Recordオブジェクトの列にスキーマとヘッダ、フッタの情報を加えたものになっています。

準備

Tableをデータベース入出力で使用するための環境としてKaleidoxの初期化ファイルinit.kldに以下の設定をします。

この設定をしておくと、H2データベースのメモリデータベース上にpersonテーブルが作成され、2レコードが格納された状態になります。

* env

db.default.driver="org.h2.Driver"
db.default.url="jdbc:h2:mem:test;DB_CLOSE_DELAY=-1;DATABASE_TO_UPPER=false"

* voucher

** person

#+caption: 特性一覧
|特性  | 名前 | 型     | 多重度 | ラベル  |
|------+------+--------+--------+---------|
| 属性 | id   | int    |      1 | User ID |
| 属性 | name | string |      1 | 名前    |
| 属性 | city | string |      ? | 市      |

* data

** person

*** x

100,Taro,Yokohama
200,Hanako,Kawasaki

* main

store-create 'person
store-insert 'person x
DATA区画

準備として用意したinit.kldでは以下のデータ区画を定義しています。

* data

** person

*** x

100,Taro,Yokohama
200,Hanako,Kawasaki

変数xにCSVで記述された表データを持つTableオブジェクトが束縛されます。

入力

Tableオブジェクトの入力方法として以下の方法について見ていきます。

  • データベース読込み
  • CSVファイル
  • LTSVファイル
  • XMLファイル
  • JSONファイル
  • HTMLファイル
データベース読込み

Kaleidoxでは、データベースアクセスの仕組みとして以下の2つを用意しています。

Store
データストア機能
SQL
SQLで直接データベースアクセス
Store

データストア機能を使うと、スキーマ定義といったメタ情報を登録することで、データベースに対してレコードベースのインタフェースでアクセスすることができます。

データストアからstore-selectで検索すると、検索結果がテーブルを記述するTableオブジェクトに格納されて返されます。

以下ではstore-selectに検索条件を指定せずテーブル名のみを指定しているので全件検索になります。(ただし、読込件数はデフォルト値の件数で制限されます。)

kaleidox> store-select 'person
Table[3x2]

読み込んだTableの詳細情報を表示すると以下になります。

kaleidox> :show
┏━━━┯━━━━━━┯━━━━━━━━┓
┃id │name  │city    ┃
┣━━━┿━━━━━━┿━━━━━━━━┫
┃100│Taro  │Yokohama┃
┃200│Hanako│Kawasaki┃
┗━━━┷━━━━━━┷━━━━━━━━┛

Tableはオブジェクトなのでプロパティまたはメソッドを使って必要な情報を取り出すことができます。

以下headメソッドを使用して先頭の要素を取り出しています。

kaleidox> .head
id:100 name:Taro city:Yokohama
kaleidox> :show
Record[2] name:Taro city:Yokohama
SQL

データストア機能を使わず直接SQLを使用してデータベース内のデータをTableとRecordとして取得することもできます。

sql関数でSQL文を指定するとSQLが発行されます。SELECT文の場合は結果がTableとして返ってきます。

kaleidox> sql "select * from person"
Table[3x1]
kaleidox> :show
Table[3x1]
┏━━━┯━━━━┯━━━━━━━━┓
┃ID │NAME│CITY    ┃
┣━━━┿━━━━┿━━━━━━━━┫
┃100│Taro│Yokohama┃
┗━━━┷━━━━┷━━━━━━━━┛
kaleidox> .head
ID:100 NAME:Taro CITY:Yokohama
CSVファイル

CSVファイルからテーブルを読み込むことができます。

以下のCSVファイルpersons.csvを用意します。

id,name,city
100,Taro,Yokohama
200,Hanako,Kawasaki

CSVファイルの読込みにはtable-load関数を用います。table-load関数の引数にCSVファイルのURLを指定します。ローカルファイルでもHTTP経由でのリモートファイルでも読込み可能です。

kaleidox> table-load file:persons.csv
Tabble[3x2]

showコマンドで内容を表示すると以下のようにTableオブジェクトとして読み込まれています。

kaleidox> :show
Table[3x2]
┏━━━┯━━━━━━┯━━━━━━━━┓
┃id │name  │city    ┃
┣━━━┿━━━━━━┿━━━━━━━━┫
┃100│Taro  │Yokohama┃
┃200│Hanako│Kawasaki┃
┗━━━┷━━━━━━┷━━━━━━━━┛
LTSVファイル

LTSVファイルからテーブルを読み込むことができます。

以下のLTSVファイルpersons.ltsvを用意します。

id:100 name:Taro city:Yokohama
id:200 name:Hanako city:Kawasaki

LTSVファイルの読込みにはtable-load関数を用います。table-load関数の引数にLTSVファイルのURLを指定します。ローカルファイルでもHTTP経由でのリモートファイルでも読込み可能です。

kaleidox> table-load file:persons.ltsv
Table[3x2]
kaleidox> :show
Table[3x2]
┏━━━┯━━━━━━┯━━━━━━━━┓
┃id │name  │city    ┃
┣━━━┿━━━━━━┿━━━━━━━━┫
┃100│Taro  │Yokohama┃
┃200│Hanako│Kawasaki┃
┗━━━┷━━━━━━┷━━━━━━━━┛
XMLファイル

XML文書から以下のいずれかの構造を読み取り、その情報に基づいてTableオブジェクトを生成することができます。

  • 表データ
  • レコードデータ
表データ

XML文書が以下のようにリスト構造になっている場合は表データとして解釈することができます。

<accounts>
  <account>
    <id>100</id>
    <name>Taro</name>
    <city>Yokohama</city>
  </account>
  <account>
    <id>200</id>
    <name>Hanako</name>
    <city>Kawasaki</city>
  </account>
</accounts>

table-make関数はXML文書の構造を解釈してTableオブジェクトとして読み込みます。

このXML文書をpersons.xmlとして用意してtable-make関数を呼び出すとTableオブジェクトとして読み込むことができます。

kaleidox> table-make file:persons.xml
Table[3x2]
kaleidox> :show
Table[3x2]
┏━━━┯━━━━━━┯━━━━━━━━┓
┃id │name  │city    ┃
┣━━━┿━━━━━━┿━━━━━━━━┫
┃100│Taro  │Yokohama┃
┃200│Hanako│Kawasaki┃
┗━━━┷━━━━━━┷━━━━━━━━┛
レコードデータ

XML文書が以下のようにレコード構造になっている場合はレコードデータとして解釈することができます。

<account>
  <id>100</id>
  <name>Taro</name>
  <city>Yokohama</city>
</account>

このXML文書をperson.xmlとして用意してtable-make関数を呼び出すとTableオブジェクトとして読み込むことができます。

レコード構造の場合は1レコードを持つTableオブジェクトとなります。

kaleidox> table-make file:person.xml
Table[3x1]
kaleidox> :show
Table[3x1]
┏━━━┯━━━━┯━━━━━━━━┓
┃id │name│city    ┃
┣━━━┿━━━━┿━━━━━━━━┫
┃100│Taro│Yokohama┃
┗━━━┷━━━━┷━━━━━━━━┛
JSONファイル

JSON文書から以下のいずれかの構造を読み取り、その情報に基づいてTableオブジェクトを生成することができます。

  • 表データ
  • レコードデータ
表データ

JSON文書が以下のように配列になっている場合は表データとして解釈することができます。

[{
  "id": "100",
  "name": "Taro",
  "city": "Yokohama"
},{
  "id": "200",
  "name": "Hanako",
  "city": "Kawasaki"
}]

このJSON文書をpersons.jsonとして用意してtable-make関数を呼び出すとTableオブジェクトとして読み込むことができます。

kaleidox> table-make file:persons.json
Table[3x2]
kaleidox> :show
Table[3x2]
┏━━━┯━━━━━━┯━━━━━━━━┓
┃id │name  │city    ┃
┣━━━┿━━━━━━┿━━━━━━━━┫
┃100│Taro  │Yokohama┃
┃200│Hanako│Kawasaki┃
┗━━━┷━━━━━━┷━━━━━━━━┛
レコードデータ

JSON文書が以下のようにレコード構造になっている場合はレコードデータとして解釈することができます。

{
  "id": "100",
  "name": "Taro",
  "city": "Yokohama"
}

このJSON文書をperson.jsonとして用意してtable-make関数を呼び出すとTableオブジェクトとして読み込むことができます。

レコード構造の場合は1レコードを持つTableオブジェクトとなります。

kaleidox> table-make file:person.json
Table[3x1]
kaleidox> :show
Table[3x1]
┏━━━┯━━━━┯━━━━━━━━┓
┃id │name│city    ┃
┣━━━┿━━━━┿━━━━━━━━┫
┃100│Taro│Yokohama┃
┗━━━┷━━━━┷━━━━━━━━┛
HTMLファイル

HTML文書からTableオブジェクトを生成することができます。この場合は、HTML文章内の表構造を抽出し、条件に適合するものをTableオブジェクトとして取り出します。

以下のHTMLファイルpersons.htmlにはtableタグによって表が1つ定義されています。

<html>
    <head>
<title>表サンプル</title>
    </head>
    <body>
<p>表のサンプルです</p>
<table>
   <thead>
<tr><th>id</th><th>name</th><th>city</th></tr>
   </thead>
   <tbody>
<tr><td>100</td><td>Taro</td><td>Yokohama</td></tr>
<tr><td>200</td><td>Hanako</td><td>Kawasaki</td></tr>
   </tbody>
</table>
    </body>
</html>

このHTMLファイルに対してtable-make関数を適用するとHTML文書内の表データをTableオブジェクトとして抽出することができました。

kaleidox> table-make file:persons.html
Table[3x2]
kaleidox> :show
Table[3x2]
┏━━━┯━━━━━━┯━━━━━━━━┓
┃id │name  │city    ┃
┣━━━┿━━━━━━┿━━━━━━━━┫
┃100│Taro  │Yokohama┃
┃200│Hanako│Kawasaki┃
┗━━━┷━━━━━━┷━━━━━━━━┛

出力

データストア機能を使ってTableのデータをデータベースに格納することができます。

以下ではstore-insert関数を使って、personテーブルにTableの情報を追加しています。

kaleidox> store-insert x
(101)
kaleidox> store-get 'person 101
ID:101 NAME:Hanako CITY:Kawasaki
kaleidox> store-select 'person
Table[3x2]
kaleidox> :show
Table[3x2]
┏━━━┯━━━━━━┯━━━━━━━━┓
┃id │name  │city    ┃
┣━━━┿━━━━━━┿━━━━━━━━┫
┃100│Taro  │Yokohama┃
┃101│Hanako│Kawasaki┃
┗━━━┷━━━━━━┷━━━━━━━━┛

参照

Tableの内容はRecordのシーケンスとして参照することができます。

準備

前述のinit.kldの設定によって、変数xにTableオブジェクトが束縛されています。

kaleidox> x
Table[3x2]
kaleidox> :show
Table[3x2]
┏━━━┯━━━━━━┯━━━━━━━━┓
┃id │name  │city    ┃
┣━━━┿━━━━━━┿━━━━━━━━┫
┃100│Taro  │Yokohama┃
┃200│Hanako│Kawasaki┃
┗━━━┷━━━━━━┷━━━━━━━━┛

このTableオブジェクトを参照の対象にします。

プロパティ取得

Tableオブジェクトのプロパティは以下のようにプロパティ名を指定して取得することができます。

以下ではTableオブジェクトのカラム数をプロパティwidthで、レコード数をプロパティheightで取得しています。

kaleidox> x.width
3
kaleidox> x.height
2
レコード操作

Tableオブジェクトの先頭レコードはプロパティheadで取得することができます。

kaleidox> x.head
id:100 name:Taro city:Yokohama
kaleidox> :show
Record[3] id:100 name:Taro city:Yokohama

また、先頭レコードを除いた残りのレコードを保持したTableオブジェクトはプロパティtailで取得することができます。

kaleidox> x.tail
Table[3x1]
kaleidox> :show
Table[3x1]
┏━━━┯━━━━━━┯━━━━━━━━┓
┃id │name  │city    ┃
┣━━━┿━━━━━━┿━━━━━━━━┫
┃200│Hanako│Kawasaki┃
┗━━━┷━━━━━━┷━━━━━━━━┛

Tableオブジェクトが空の場合はプロパティheadはnilを返します。

kaleidox> setq y x.tail
Table[3x1]
kaleidox> y.tail
Table[3x0]
kaleidox> :show
Table[3x0]
┏━━┯━━━━┯━━━━┓
┃id│name│city┃
┣━━┿━━━━┿━━━━┫
┗━━┷━━━━┷━━━━┛
kaleidox> .head
nil
スキーマ

Tableオブジェクトのスキーマ情報はプロパティschemaで取得することができます。

kaleidox> x.schema
Schema[3] id,int,1 name,string,1 city,string,?
kaleidox> :show
Schema[3]
┏━━━━┯━━━━━━━━┯━━━━━━━━━━━━┓
┃name│datatype│multiplicity┃
┣━━━━┿━━━━━━━━┿━━━━━━━━━━━━┫
┃id  │int     │1           ┃
┃name│string  │1           ┃
┃city│string  │?           ┃
┗━━━━┷━━━━━━━━┷━━━━━━━━━━━━┛

まとめ

今回はKaleidoxの中軸オブジェクトの一つであるTableについて説明しました。

データベースやCSVファイルといった外部リソースの情報をTableオブジェクトとして読込み、Recordオブジェクト単位で処理していくのがKaleidoxの基本処理モデルです。TableとRecordをハブにして各種の連携を進めていきます。

諸元

  • Kaleidox : 0.1.8