「データ操作」カテゴリーアーカイブ

クライアント・データベース操作(SQLite)

CurlではJava DB(Derby)やAIRのようなローカルデータベース機能をオープンソースであるCDK(Curl Data Kit)を利用して、利用することができます。CDKはSQLiteを利用しています。また、Curl7.0からは特権なしで稼働します。

sqlite01.jpg

 

 

 

 

 

 

SQLiteの詳細については以下のサイトを参照ください。
http://www.sqlite.org/

準備

ローカルデータベースを利用するために、CDKを下記サイトからダウンロードし、Zipファイルを展開します。2010年2月時点ではバージョン1.1が最新のようです。
http://sourceforge.net/projects/curl-cdk/

この中にSQLiteのライブラリも含まれておりますので、別途SQLiteをダウンロードする必要はありません。

基本的なSQLiteへのアクセス

まずは以下のようにmanifestを設定し、COM.CURL.CDK.SQLITEをimportします。(manifest.mcurlのパスは環境に合わせて変更してください。)

{curl 7.0 applet}
{applet manifest = “deploy/COM.CURL.CDK.1.1/manifest.mcurl”}
{import * from COM.CURL.CDK.SQLITE}

最初にSQLiteDatabaseクラスを用いてデータベースオブジェクトを生成します。 この際指定するURLはデータの格納されるファイルのパスとなります。もしurlがNULLの場合は、メモリデータベースとなります。メモリデータベースはApplet停止時にクリアされてしまいます。 

def db = {SQLiteDatabase {url “test1.db”}}

次に上記で生成されたデータベースオブジェクトのexecuteメソッドを用いて更新系のSQL文を実行します。(creata table/drop table等のSQL文も実行可能)以下のサンプルコードではテーブルを作成し、テストデータを挿入しています。

{db.execute “CREATE TABLE IF NOT EXISTS test (col1 INTEGER, col2 TEXT)”}
{db.execute “INSERT INTO test VALUES(1, ‘test1’)”}
{db.execute “INSERT INTO test VALUES(2, ‘test2’)”}

SQL文の記載されたファイルからそのSQL文を実行するために、以下のようなこともできます。

{db.execute {read-from {url “test.sql”}}}

次にデータベースからデータを取得する例を紹介します。以下のサンプルコードでは、sql-rowsメソッドで取得した行データをdumpマクロでコンソールに出力しています。1行だけの取得であれば、sql-rowというメソッドも用意されております。

def rows = {db.sql-rows “SELECT * FROM test”}
{for row in rows do
    {dump
        row[0], || col1 
        row[1]  || col2
    }
}

ステートメントを利用したSQL実行については、create-statementメソッドを利用し、SQLiteStatementオブジェクトを作成し、stepメソッドでSQL文を実行できます。また、CDKではJDBCのPreparedStatementのような、ステートメントを事前に準備しておき、ステートメント作成時にプレース・ホルダとして「?」をセットできます。これらのプレース・ホルダにバインドするにはbindメソッドを利用し、最後にstepでSQL文を実行します。sql-rowsql-rowsにも同様にプレース・ホルダをセットすることができ、残余引数としてバインドする値をセットできます。

|| プレース・ホルダ
def row = {db.sql-row “SELECT * FROM test WHERE col1 = ? and col2 = ?“, 2, “test2”}
{dump row[0], row[1]}

|| SQLiteStatment利用(更新SQL)
def stmt1 = {db.create-statement “INSERT INTO test VALUES(?, ?)”}
{stmt1.bind 3, “test3”}
{stmt1.step}

|| プレース・ホルダとして以下のような書き方も可能
def stmt2 =
    {db.create-statement “INSERT INTO test (col1, col2) VALUES (:c1, :c2“}
{stmt2.bind c1 = 4c2 = “test4”}
{stmt2.step}

|| with-statementマクロでコーディングの簡略化
{with-statement in db
    stmt3 = “INSERT INTO test (col1, col2) VALUES (?, ?)”
  do
    {stmt3.bind 5, “test5”}
    {stmt3.step}
}

レコードセットとの連携

テーブルとRecordSetと連携が容易に可能となっています。これにはコネクションオブジェクト(SQLiteConnection)を引数にしてSQLiteRecordSet.create-from-table-nameクラスプロシージャを実行します。以下はサンプルとなります。 

def con = {SQLiteConnection db}
def rs =
        {SQLiteRecordSet.create-from-table-name
            con, || SQLiteConnection
            “main”, || データベース名
            “test”, || テーブルもしくはSQL文
            request-modifiable? = true || 変更可否
        }
{RecordGrid record-source = rs}

データベースの暗号化

Curl7.0からはSQLiteデータベースの暗号化がサポートされています。暗号方式はAES256, AES128, RC4がサポートされております。(SQLiteEncryptionType参照)暗号化されたデータベースを利用する方法は、SQLiteDatabaseのコンストラクタ、もしくは、SQLiteDatabase.attach, SQLiteLibrary.rekeyで、引数に暗号方式(encryption-type)と鍵(key)を指定します。以下はSQLiteDatabaseコンストラクタに指定している例です。

def db =
    {SQLiteDatabase 
        {url “test.db”},
        encryption-type = SQLiteEncryptionType.aes256, || 暗号方式(ここではAES256)
        key = {ByteArray 1, 2, 3, 4, 5} || 鍵(ByteArrayで指定)
    }

サポートタイプ

サポートされるSQliteとCurlの型は以下のようになります。

SQLite Curl Type
TEXT String
INTEGER int or int64
REAL double
BLOB ByteArray
NULL null

サポートバージョン

RTE6.0以上

その他、CDKには多くの機能(例えば、SQLiteStatement.import-csvによるCSVインポート、コミット時などの各種イベントハンドリング、SQLDatabase.install-functionを利用したSQL関数の作成、権限設定など)があります。ダウンロードしたCDKディレクトリの中には、多くのコードサンプルやドキュメントが記載されていますので、詳細についてはそちらをご覧ください。

 

WSDKを使ったExcel(XMLスプレッドシート)の取り込み

ここでは、Excelのデータ形式の1つであるXMLスプレッドシートをWSDKを使用し読み込む際のtipsを紹介いたします。

WSDKを使用したXML解析で、パス表現を使って要素を抽出したいときは、下記のように要素を抽出します。

{XDMElement.search “タグ名”}

該当するXMLに名前空間がつけられていると、単純に名前のみではパスの認識ができません。(下記のXML参照)
XMLが名前空間を含んでいる場合はひと手間加える必要があります。

{XDMElement.search “名前空間:タグ名”}

ただし、単純に上記のように検索を行うと「XDMException: No declaration for prefix ‘名前空間’」

という例外が出てしまいます。

そこで、名前空間を検索前に認識させる必要が出てきます。(名前空間認識プロシージャを参照)

 

 

名前空間を持ったXML(Book2.xml)

 



<Workbook xmlns=”urn:schemas-microsoft-com:office:spreadsheet”
 xmlns:o=”urn:schemas-microsoft-com:office:office”
 xmlns:x=”urn:schemas-microsoft-com:office:excel”
 xmlns:ss=”urn:schemas-microsoft-com:office:spreadsheet”
 xmlns:html=”http://www.w3.org/TR/REC-html40“>
 <Styles>
  <Style ss:ID=”Default” ss:Name=”Normal”>
   <Alignment ss:Vertical=”Center”/>
   <Borders/>
   <Font ss:FontName=”MS Pゴシック” x:CharSet=”128″ x:Family=”Modern” ss:Size=”11″/>
   <Interior/>
   <NumberFormat/>
   <Protection/>
  </Style>
  <Style ss:ID=”s21″>
   <Borders>
    <Border ss:Position=”Bottom” ss:LineStyle=”Continuous” ss:Weight=”1″/>
    <Border ss:Position=”Left” ss:LineStyle=”Continuous” ss:Weight=”1″/>
   </Borders>
  </Style>
  <Style ss:ID=”s23″>
   <Borders>
    <Border ss:Position=”Bottom” ss:LineStyle=”Continuous” ss:Weight=”1″/>
    <Border ss:Position=”Left” ss:LineStyle=”Continuous” ss:Weight=”1″/>
   </Borders>
   <Interior ss:Color=”#FFCC00″ ss:Pattern=”Solid”/>
  </Style>
 </Styles>
</Workbook>

 

名前空間認識プロシージャ

 

{define-proc {dwim-prefix-declarations
                 subject:XDMElement,
                 context:XDMNamespaceContext = xml-namespace-context
             }:void
    {subject.walk-children
        || walk descendants and self
        include-self? = true,
        include-descendants? = true,
        {proc {n:XDMNode}:bool
            {type-switch n
             case e:XDMElement do
                || check declared prefixes
                {if-non-null ps = e.namespace-declarations then
                    {for p in {ps.get-prefixes} do
                        {if-non-null ns = {ps.get-uri p} then
                            {if {context.get-uri p} == null
                             then
                                || extend global declarations accordingly
                                {context.declare-prefix? p, ns}}}}}}
            || continue walking
            {return true}}}
}

 

 

{value
    let loc:Url = {url “TESTDATA/Book2.xml”}
    ||XMLdocumentModelエレメント
    let xml:XDMElement =
        {build-xml preserve-whitespace? = false, loc}.root
    
    ||名前空間認識
    {dwim-prefix-declarations xml}
    let worksheets:XDMNodeSet = {xml.search “ss:Styles”}
    {output worksheets.size}
}

 

RecordViewを用いたデータのソート・抽出

 RecordView は、基になるソース RecordSet に含まれているデータに効率よくアクセスするための基本的な手段です。

RecordViewを使用することで、フィルタリングで抽出したデータだけを照会することが出来ます。
例えば画面表示を行う前に、RecordViewデータに対して
アプリケーションロジックを適用してデータのソートを行ったり、
フィルタリングを実施することが出来ます。
RecordViewを用いて特定のデータを抽出したからといって、
元のRecordSetに登録されているデータが無くなるわけではありません。

RecordViewのサンプルコードは以下の通りです。

{curl 6.0 applet}
{curl-file-attributes character-encoding = “shift-jis”}

{let staff:RecordSet =
    {RecordSet
        {RecordFields
            {RecordField
                “id”, caption = “ユーザーID”, domain = int,
                index-type = RecordFieldIndexType.unique
            },
            {RecordField “First”, domain = String, caption = “名前”},
            {RecordField “Last”, domain = String , caption = “名字”},
            {RecordField “City”, domain = String , caption = “住所(都市)”},
            {RecordField “State”, domain = String, caption = “住所(州)”}
        },
        {RecordData id = 1, First = “Gene”, Last = “Smith”, City = “Boston”, State = “MA”},
        {RecordData id = 2, First = “Fred”, Last = “Smith”, City = “Cambridge”, State = “MA”},
        {RecordData id = 3, First = “Mike”, Last = “Smith”, City = “Keene”, State = “NH”},
        {RecordData id = 4, First = “Ben”, Last = “Smith”, City = “New Haven”, State = “CT”},
        {RecordData id = 5, First = “Ben”, Last = “Abrams”, City = “Boston”, State = “MA”},
        {RecordData id = 6, First = “Sam”, Last = “Jones”, City = “Storrs”, State = “CT”},
        {RecordData id = 7, First = “Nigel”, Last = “Stevens”, City = “Hartford”, State = “CT”},
        {RecordData id = 8, First = “Bert”, Last = “Stevens”, City = “Cambridge”, State = “MA”},
        {RecordData id = 9, First = “Pat”, Last = “Linden”, City = “Hartford”, State = “CT”},
        {RecordData id = 10, First = “Mat”, Last = “Abrams”, City = “Boston”, State = “MA”},
        {RecordData id = 11, First = “John”, Last = “Rogers”, City = “Cambridge”, State = “MA”},
        {RecordData id = 12, First = “Dan”, Last = “Abrams”, City = “Keene”, State = “NH”},
        {RecordData id = 13, First = “Chris”, Last = “Abrams”, City = “Cambridge”, State = “MA”},
        {RecordData id = 14, First = “Glenn”, Last = “Abrams”, City = “Keene”, State = “NH”},
        {RecordData id = 15, First = “Doug”, Last = “Jones”, City = “New Haven”, State = “CT”},
        {RecordData id = 16, First = “Susan”, Last = “Rogers”, City = “Concord”, State = “NH”},
        {RecordData id = 17, First = “Joan”, Last = “Smith”, City = “Concord”, State = “MA”},
        {RecordData id = 18, First = “Tom”, Last = “Frankel”, City = “Keene”, State = “NH”},
        {RecordData id = 19, First = “Sarah”, Last = “Frankel”, City = “Concord”, State = “NH”},
        {RecordData id = 20, First = “John”, Last = “Jones”, City = “Keene”, State = “NH”},
        {RecordData id = 21, First = “Pam”, Last = “Frankel”, City = “Storrs”, State = “CT”}
    }
}
{let rv:RecordView =
    {RecordView staff}
}
{let rg:RecordGrid =
    {RecordGrid
        record-source = rv, height = 5cm, width = 14cm
    }
}
{value
    {VBox
        rg,
        {HBox
            {CommandButton
                width = {make-elastic},
                label = “住所(州), 住所(都市), 名字, 名前の順に昇順ソート”,
                {on Action do
                    set rv.sort = “State, City, Last, First”
                }
            },
            {CommandButton
                width = {make-elastic},
                label = “FirstがBertのものをフィルタリング”,
                {on Action do
                    set rv.filter = {RecordData First = “Bert”}
                }
            }
        }
    }       
}

このサンプルを実行すると以下のような結果が得られます。

左のボタンをクリックしたとき

record-view_1.jpg

 

 

 

 

 

 

 

 

右のボタンをクリックしたとき

record-view_2.jpg

 

 

 

 

 

 

 

 

ただし、RecordViewを作成したからといって、
RecordSetに含まれる各レコードが個別にコピーされた訳ではありません。
RecordViewで抽出したレコードに格納されている値を直接書き換えてしまうと、
RecordSetに登録されている値も変更されてしまうので、注意が必要です。

また、レコードのステータスを更新するRecordViewの以下のメソッドは、
元のRecordSetの更新状態を基準に処理を実行します。
そのため、RecordSet側でデータが更新されていた場合は、
RecordViewの方でデータの更新を行っていなくとも
現在抽出している全てのレコードに変更が生じる場合があるため、利用時に注意が必要です。

  ○RecordView.commit
  ○RecordView.revert
  ○RecordView.load
  ○RecordView.load-state
  ○RecordView.pending-update?

XPathを利用したXMLハンドリング

 

XMLのハンドリングについて、Curlでは、いくつかの方法が用意されています。
ここでは、WSDKというCurlの開発をサポートするキットで提供されている、
XPath表現を使ったハンドリングの例をご紹介します。

このエントリで紹介するアプリでは、顔ラボ から提供されている、画像の顔位置検出APIのXMLデータを利用しています。
顔ラボのサービスに画像のURLを渡すと、顔情報が保持されたXMLが返却されます。

 

■顔ラボ 返却XML例

<results version=”1.0″ xmlns=”http://xmlns.kaolabo.com/detect”>
   <faces>
     <face height=”60″ score=”742″ width=”60″ x=”234″ y=”117″>
        <left-eye x=”275″ y=”136″ />
        <right-eye x=”253″ y=”136″ />
     </face>
     <face height=”48″ score=”705″ width=”48″ x=”303″ y=”138″>
        <left-eye x=”336″ y=”153″ />
        <right-eye x=”318″ y=”153″ />
     </face>
     <face height=”36″ score=”505″ width=”36″ x=”134″ y=”143″>
        <left-eye x=”159″ y=”153″ />
        <right-eye x=”145″ y=”153″ />
     </face>
  </faces>
</results>

 results タグの中に、顔として認識されたブロックの位置情報が face タグとして格納されています。
各 face タグ の中には、属性として各顔位置情報が、
タグとして目の位置情報がそれぞれ格納されています。

顔ラボの詳細な仕様については、 http://kaolabo.com を見てください。

 

■顔マスクアプリ解説

顔マスクアプリ ([developers.curlap.com] に対する特権が必要です。)

アプリケーションダウンロード

上記WEBサービスを利用した顔マスクアプリケーションでは、
start.curl内の、下記コード部にて、返却されたXMLをXPathで解析しています。

|| XML構造をモデル化
let model:XDMElement = {build-xml preserve-whitespace? = false, strb}.root

・・・

|| 画像内の顔位置を示すXMLを解析する
{for i:int = 0 to ({model.search “//*[name()=’face’]”}.size) do

    let fr:ImageMask =
        {ImageMask
            {url “laughing-man-mini.gif”},
            height = ({model.search “//*[name()=’face’][” & i &”]/@height”}.as-int) * 1px,
            width = ({model.search “//*[name()=’face’][” & i &”]/@width”}.as-int) * 1px
        }
       
    {c.add
        fr,
        x = ({model.search “//*[name()=’face’][” & i &”]/@x”}.as-int) * 1px,
        y = ({model.search “//*[name()=’face’][” & i &”]/@y”}.as-int) * 1px + fr.height
    }
}

■{build-xml preserve-whitespace? = false, strb}

build-xml プロシージャを利用することで、対象のXMLをモデル化することが出来ます。
XDMDocument.root から XDMElementクラス型のXMLツリー全体を取得しています。

■{model.search “//*[name()=’face’]

{XDMElement.search XPath表現} では、XPath表現に合ったノードが、XDMNodeSetとして返却されます。
ここでは、XML内のタグで face という名前のタグをを取得しています。

さらに XDMNodeSetのサイズを、for文のカウントとして利用しています。

これによってXML内の顔情報の数だけループすることになります。

■{model.search “//*[name()=’face’][” & i &”]/@height”}

ループのカウントを表す変数 i を使って、順番に顔情報のタグを扱っています。
属性情報を取得するXPath表現である @ を利用して、height という属性の値を取得しています。

また、XDMNodeSet.as-int で、返却されたデータを int型で扱うようにしています。

 

XPathは、このプログラムで利用している表現以外にも、いろいろな書き方があります。
下記リソースなどを利用して、簡易なXMLハンドリングを試してみてください。

■XPath W3C 勧告
http://www.infoteria.com/jp/contents/xml-data/REC-xpath-19991116-jpn.htm

■XPath の概要
http://msugai.fc2web.com/java/XML/XPath.html

Google EarthをCurlで操作

今回は、Google EarthをCurlからGoogle Earth COM APIを利用して、操作する方法を説明していこうと思います。これを用いることで、Google Earth上を自由に移動・観光したり、3D建物を配置したり、画面のスクリーンショットを取得することができます。ここではGoogle Earth4.3のインストールを前提としています。

まずは、Google Earthをインストール後、以下のコマンドにてCOMレジストリの登録を実施します。

“C:Program FilesGoogleGoogle Earthgoogleearth.exe” /RegServer

 

コーディング(Google Earth COM API)

CurlでGoogle Earth COM APIを利用するには、ActiveXObjectを利用します。ActiveXの扱い方についてはこちらのページを参考ください。

まずは、CURL.GRAPHICS.ACTIVEXパッケージをインポートし、ActiveXObjectオブジェクトを生成します。この際、ProgIdにGoogleEarth.ApplicationGEを指定します。

{import * from CURL.GRAPHICS.ACTIVEX}

{def ge = {ActiveXObject ProgId = “GoogleEarth.ApplicationGE“}}

これにより、IApplicationGEオブジェクトが生成されます。このオブジェクトからバージョン情報を取得する簡単なサンプルは以下の通りです。(IApplicationGEのゲッターであるVersionMajor、VersionMinor、VersionBuild、VersionAppTypeを利用)

{output ge.VersionMajor & “.” & ge.VersionMinor & “.” & ge.VersionBuild}
{output ge.VersionAppType}

 これだけでは面白くないので、カメラ位置を設定して、いろいろな場所へ移動できるようにしてみます。まずは、カメラ・オブジェクト(ICameraInfoGE)をIApplicationGEのGetCameraメソッドから取得します。このICameraInfoGEのいくつかのセッターを設定し、再度IApplicationGEオブジェクトにカメラをセットすることで場所の移動が可能となります。

|| カメラの取得
def ge-cam = {ge.GetCamera 0}

|| カメラのプロパティに値をセット
set ge-cam.FocusPointLatitude = 35.3800 || 緯度
set ge-cam.FocusPointLongitude = 139.0000 || 軽度
set ge-cam.FocusPointAltitudeMode = 2 || 1 or 2
set ge-cam.FocusPointAltitude = 1000.0 || 高度(meter)
set ge-cam.Range = 1000.0 || カメラとフォーカスポイントの距離(meter)
set ge-cam.Tilt = 80.0 || 傾き 
set ge-cam.Azimuth = 90 || 方位

|| カメラをIApplicationGEにセット
{ge.SetCamera ge-cam, 0.5}

また、目的地の場所から移動することができます。これにはGetFeatureByNameメソッドを利用し、IFeatureGEオブジェクトを取得し、存在すればSetFeatureViewで移動します。例えば以下のようにディズニーランドに飛んでみます!

def feature = {ge.GetFeatureByName “アメリカ フロリダ州、ディズニーランド”}
{if-non-null feature then
    {ge.SetFeatureView feature, 10.0} || 場所の移動
    {ge.ShowDescriptionBalloon feature} || バルーンの表示
}

実行しますと、ディズニーランドに飛びます。

g-earth01.jpg

Google Earth上の画面左の検索・場所・レイヤを操作することもできます。これにはSearchController(検索)やGetMyPlace(場所)等を用いて、操作できます。例えば検索の例は以下の通りです。

def search = ge.SearchController || ISearchControllerGEの取得
{search.Search “東京タワー”} || 検索
def feature-collection = {search.GetResults} || 検索結果の取得 
{dump {feature-collection.Item 1}.Name}

さらに「場所」にある”観光”名所をツアーすることもできます。これには、以下のようなコードにて実現できます。

def tour = ge.TourController || ツアーオブジェクト
{tour.PlayOrPause} ||画面左の「観光」をツアー

最後に3DオブジェクトをGoogle Earth上に配置する方法を記載します。Google Earth上に配置されるオブジェクトはKML(Keyhole Markup Language)というフォーマット形式で記述された情報を元に作成されます。これにはGoogle SketchUpを利用し、作成することができます。またGoogle 3D Galleryからダウンロードすることもできます。

ここではそれらから作成されたファイルをCurlで開きます。コードは以下のようになります。(たった一行) 

{ge.OpenKmlFile “C:\doc.kml”, true}

これを実行しますと以下のように3Dオブジェクト(車)が配置されます。

g-earth03.jpg

XMLフォーマットの利用(DOMパーサー)

XMLフォーマットを扱うために、Curlでは拡張コンポーネントのWSDKにDOM(Document Object Model)機能が用意されています。DOMは、XMLをツリー構造として扱い、これを「DOMツリー」といいます。XML全体を解析してDOMツリーとしてメモリ上に保存するのでデータの多いXMLを解析する場合は多くのメモリを消費します。

ここではDOMパーサーを利用したXML解析方法について、下記サンプルXMLを用いて説明します。 

<RecordSet>
  <Record name=”AAA”>
    <Value>”123″</Value>
    <Value>”456″</Value>
  </Record>
  <Record name=”BBB”>
    <Value>”xyz”</Value>
  </Record>
</RecordSet>

DOMパーサーを使用するためには、まずWSDKをインストール及びデリゲートする必要があります。下記サンプルは、XMLから取得した値をoutputプロシージャにて結果表示させています。

XMLの読取り

XMLフォーマットをデータモデルに変換する場合、build-xmlプロシージャを使用します。build-xmlプロシージャの戻り値はXDMDocumentオブジェクトになります。build-xmlプロシージャで解析可能なデータはUrl、StringInterface、TextInputStream、ByteInputStreamです。

let xml:XDMElement = {build-xml preserve-whitespace? = true, XMLデータ}

XMLの解析

XMLを解析するために、まずXDMElementのrootでルートの要素を取得します。また、各子要素のを取得するにはget-elementsメソッドを実行します。取得した要素から属性を取得するにはattributes、テキストを取得するにはget-textを利用します。以下にコメント入りでサンプルを掲載します。

||build-xmlプロシージャを用いて、XMLをのCurlのXML構造体オブジェクトに変換します。
||更に、build-xmlの戻り値であるXDMDocumentから、そのXMLのルートとなるエレメントを取得します。

let root:XDMElement = {build-xml preserve-whitespace? = false, XMLデータのURL}.root

||以下XMLの解析
||get-elementsメソッドで、エレメントを取得します。

let record-elements:{Array-of XDMElement} = {root.get-elements}
  {for record-element:XDMElement in record-elements do
   ||attributesアクセッサで、属性を取得します。
      {output “Record attribute = “ & record-element.attributes[“name”]}
      let value-elements:{Array-of XDMElement} = {record-element.get-elements}
      {for value-element in value-elements do
     ||get-textメソッドでテキストを取得します。
        {output ” Value text = “ & {value-element.get-text}}
      }
  }

実行結果 

Record attribute = AAA
 Value text = “123”
 Value text = “456”
Record attribute = BBB
 Value text = “xyz”

 参考サイト

XML Data

Transforming XML

Using XPath

 

WSDK(Web Service Development Kit)のインストール

WSDK(Web Service Development Kit)とは、Webサービスを利用したアプリケーションをCurlで開発する為に有用なAPIがまとめられた拡張コンポーネントです。

WSDKのAPI及び機能の一覧

 ・XDM(XML Document Model:XMLのドキュメントを、その構造を保った形でCurlオブジェクト化したもの)
 ・Webサービス接続用API(SOAP通信)
 ・WSDL(Curlモジュールへのコンバージョン)
 ・XHTML/CSS解析API
 ・RSS解析用API

WSDKを使用する手順は以下の通りです。

ダウンロード

 1.ここからWSDKをダウンロードする。
 2.ダウンロードしたファイルを解凍する。

ドキュメントのインストール

Note: 下記手順は古いので、最新の8.0 IDEでは、WSDKパッケージがCURL-UTIL-V7V8-V1.1を必要となった為、WSDKダウンロードして解凍後、WSDK(WSDK-V7V8-V2.1フォルダ)のドキュメントインストール後に、UTIL(CURL-UTIL-V7V8-V1.1フォルダ)も同様にインストールする必要があります。

 1.IDEを起動する。
 2.IDEのメニューから、「ヘルプ」→「ドキュメンテーションのインストール」を選択する。
wsdk-install04.jpeg

 

  3.以下の画面にて「インストール」ボタンを押下し、解凍したディレクトリ配下のdocs-install\WSDKにあるmanifest.mcurlを選択する。
wsdk-install05.jpeg

 

 4.パッケージ名が表示されたらインストール終了。
wsdk-install07.jpeg

 

 5.ヘルプドキュメントに表示される。
wsdk-install08.jpeg

 

WSDKプロジェクトの作成

 1.IDEを起動し、プロジェクトを開く。
 2.IDEのメニューから、「プロジェクト」→「デリゲート先の追加」を選択する。
wsdk-install01.jpeg

 

 3.以下の画面にて、解凍したディレクトリ配下のwsdk-source/lib/WSDKにあるmanifest.mcurlを選択する。
wsdk-install02.jpeg

 

 4.プロジェクトに追加されるとパッケージが表示される。
wsdk-install03.jpeg

 

これで、WSDKを利用可能となります。

 

日付と時刻の利用

Curlで日付と時刻を扱うには、DateTimeクラスを利用します。

DateTime

現在時刻を表示するには、以下のようにします。

let now:DateTime = {DateTime}
{output now}

指定した時刻のDateTimeオブジェクトを生成するには、以下のようにします。 

let past1:DateTime = {DateTime “01/01/2001”}
{output past1}

let past2:DateTime = {DateTime year = 2001, month = 1, day = 1}
{output past2}

文字列への変換

DateTimeオブジェクトを文字列に変換するには、DateTimeInfoクラスを利用します。これはDateTimeクラスのinfoゲッターにアクセスすることで取得できます。

let now:DateTime = {DateTime}
{dump
    now.info.iso-date, || yyyy-mm-dd
    now.info.iso-time, || hh:mm:ss
    now.info.year,       || 年(int)
    now.info.month,    || 月(int)
    now.info.day,        || 日(int)
    now.info.hour,       || 時(int)
    now.info.minute,    || 分(int)
    now.info.second     || 秒(int)
}

2038年問題について

以下のようにDateTimeを用いた場合は2038年までしか扱うことができません。(参考Wikipedia:2038年問題

let v:DateTime = {DateTime year = 2039}

上記コードを実行すると以下のような例外が発生します。

DateTimeException: DateTimeInfo ‘2039-01-01 00:00:00.000000’ を DateTimeData に変換することができません:指定された日時が範囲外です。

これを回避するためには、キーワード引数「zone」に以下のように指定して、インスタンスを生成します。

let v:DateTime = {DateTime year = 2039, zone = {DateTimeZone mode = DateTimeZoneMode.utc}}

もしくはDateTime.dateファクトリを用いることでも回避することができます。

 

コレクション・クラスの利用

Curlの持つコレクション・クラスについて、説明します。

配列(FastArray-of)

Curlで配列を扱うには、FastArray-ofを利用します。FastArray-ofの宣言時に引数として、配列の型を定義します。また、配列は最大サイズを宣言時点で指定する必要があります。

def a = {new {FastArray-of int}, max-size = 3}

または

def a = {{FastArray-of int} max-size = 3} || newは省略可

{a.append 1} || 追加
{a.append 2} || 追加
{a.append 3} || 追加

{dump a[0], a[1], a[2], a.size}

データを追加する際は、appendメソッドを利用し、値を参照する場合は、変数名[インデックス]でアクセスできます。インデックスは0から始まります。

リスト(Array-of)

Javaのようなリスト(List、ArrayList)を扱うには、Array-ofを利用します。これはFastArray-ofのように、最大サイズは指定する必要がありません。 

def a = {new {Array-of int}, 1, 2, 3} || 初期値も設定

または

def a = {{Array-of int} 1, 2, 3} || newは省略可

{dump a[0], a[1], a[2], a.size}

ハッシュテーブル(連想配列)(HashTable-of)

Javaのハッシュマップ(Map、HashMap)のような連想配列を扱うには、HashTable-ofを利用します。これはキーと値をもちますので、引数にキーの型と値の型を指定する必要があります。値を参照するには、変数名[“キー名”]でアクセスできます。値をセットするには、setメソッドを利用します。

def h = {new {HashTable-of String, int}, “key1”, 1, “key2”, 2, “key3”, 3}

または

def h = {{HashTable-of String, int} “key1”, 1, “key2”, 2, “key3”, 3} || newは省略可

{h.set “key4”, 4}

{dump h[“key1”], h[“key2”], h[“key3”], h[“key4”], h.size}

コンテナループ

上記のような配列やリスト・連想配列をFor文で繰り返して、値を取得するには以下のようにin句を利用します。(連想配列の場合は、key句でキーの値も取得できます。)

|| 配列・リスト
{for v in a do
    || vに値
    {dump v}
}

|| 連想配列
{for v key k in h do
    || kにキー値
    || vに値

    {dump k, v}
}

タプル

バージョン6.0からタプルがサポートされました。これはPython等にサポートされている編集不可のコレクションクラスです。これを利用するには、Tuple2-ofTuple3-ofTuple4-ofTuple5-ofクラスを使います。具体的な例を以下に記載します。

|| Tuple2-ofの例
def t2 = {{Tuple2-of int, String} 
             1, “hoge.”
         }
{output t2[0], t2[1]} || アクセス方法は配列と同様

|| Tuple5-ofの例
def t5 = {{Tuple5-of int, int, String, String, bool}
             1, 100, “hoge”, “foo”, true
         }
{for v in t5 do
    {output v} || コンテナループも利用可能
}

メモ

ちなみにFastArray-ofからArray-ofを生成するには、Array-ofのfrom-FastArrayコンストラクタを利用し、逆にArray-ofからFastArray-ofを生成するには、underlying-FastArrayアクセサを利用します。

文字列操作

Curlの文字列クラスは、StringInterfacceを継承したStringStringBufがあります。Stringは値を代入した後は変更が不可です。逆にStringBufは値を代入した後も変更することが可能です。具体的に利用方法を以下に紹介します。

String

let str1:String = “abc”
let str2:String = {String “efg”}
set str1 = str & “efg” || 値を代入しなおす。

{output str1.size} || サイズ

{if {str1.equal? str2} then
    {output “一緒”}
}

{if {str1.prefix? “ab”} then
    {output “最初の文字列が一致!”}
}

{if {str1.suffix? “fg”} then
    {output “最後の文字列が一致!”}
}

let str3:String = {str1.substr 1, 3}

Stringクラスのequal?メソッドは文字列が一致するか否かをチェックし、boolを返します。

prefix?やsuffix?は文字列の最初もしくは最後の一部が一致するかをチェックし、boolを返します。

また、よく利用するメソッドとして、substrがあります。これは、文字列から指定した部分を切り取ります。

その他Stringのメソッド等についての詳細は、こちらを参照ください。

StringBuf 

let buf1:StringBuf = {StringBuf}
let buf2:StringBuf = {StringBuf “abc”}

{buf1.append ‘e’}
{buf1.concat “efg”}
{buf1.replace “ab”, “zz”}
{buf1.reverse}
{buf1.clear}

Stringクラスで利用できたprefix?、suffix?、substrは、StringBufでも利用できます。それ以外に、append(1文字の追加)、concat(文字列の結合)、replace(文字列の変換)、reverse(文字列の順番を逆にする)、clear(文字列をクリア)などがあります。

その他StringBufのメソッド等についての詳細は、こちらを参照ください。

 

また、StringとStringBufは以下のようなこともできます。

CSVなどのように区切り文字で分割し、それを配列に格納するためのメソッドとして、splitがあります。これは以下のように利用します。 

let str:String = “www.curl.com
let array:StringArray = {str.split split-chars = “.”}
{for a in array do
    {output a}
}

 

 

 

正規表現の利用

正規表現とは文字列のパターンを表現する手法です。
Curl言語は Perl プログラミング言語の高レベルの正規表現構文を採用しており、多くの異なる種類のデータ抽出やレポート作成タスクに適しています。

正規表現を Curl 言語で使用するためには、import を使用して正規表現パッケージをインポートする必要があります。具体的には CURL.LANGUAGE.REGEXPパッケージをインポートすることで正規表現の比較 regexp-match? マクロが使用できるようになります。
 
 
{import * from CURL.LANGUAGE.REGEXP}
 
では、具体的な正規表現の方法を見てみましょう。ここでは、[開発者ガイド-逆引きリファレンス-イベント-バリデーションチェック]のサンプルコードで使用している正規表現を使って説明します。
 
{define-enum PhoneValidationPattern
    ||携帯電話を含む正規表現
    ja-phone-number = |”(0dd?-?d{4}-?d{4})|((0dd?)d{4}-d{4})|(0d{3}-dd-d{4})|(0dd-d{3}d?-d{4})|(0dd?(d{4})d{4})”|
}

構文 意味
((0dd?)d{4}-d{4})|(0d{3}-dd-d{4})

|(パイプ)で区切られた左右どちらかの正規表現を含む文字列とマッチします。

d 1つの数値とマッチします。
d{4} 4つ連続した数値とマッチします。
d? 数値がない、あるいは1つの数値とマッチします。
-? -を含まない、あるいは1回含む部分文字列とマッチします。
( (を認識させるために (エスケープシーケンス)をつけています。
 
 
以下は、リファレンスです。
 

一文字のマッチング-ワイルドカード使用による正規表現

構文  意味
.

改行文字以外の任意の文字とマッチします。

d 任意の数字とマッチします。
D 数字以外の任意の文字とマッチします。
s 任意の空白文字とマッチします。
S 空白以外の任意の文字とマッチします。
w 単語を構成する任意の文字とマッチします。
W 単語を構成する文字以外の任意の文字とマッチします。

繰り返しを含むマッチング

構文 意味
regexp* regexp (正規表現) を 0 回以上連続して含む部分文字列とマッチします。
regexp+ regexp を 1 回以上連続して含む部分文字列とマッチします。
regexp? regexp を含まない、あるいは 1 回含む部分文字列とマッチします。
regexp{m,n} regexp を m 回以上、n 回以下連続して含む部分文字列とマッチします。
regexp{m,} regexp を m 回以上連続して含む部分文字列とマッチします。
regexp{n} regexp を n 回連続して含む部分文字列とマッチします。

文字列内の任意の位置に対するマッチング

^ 行頭の直前の空白とマッチします。
$ 行末の直後、または文字列の末尾の改行の直前の空白とマッチします。
A 文字列の先頭の直前とマッチします。
Z 文字列の末尾の直後、または文字列の末尾の改行の直前とマッチします。
z 文字列の末尾の直後とマッチします。
b 単語の境界、つまり単語を構成する任意の文字とそれ以外の文字の間の空白とマッチします (文字列の先頭と末尾の範囲外にある存在しない文字は、単語を構成しない文字として扱われます)。
B b とマッチしない任意の空白とマッチします。
 
 
正規表現に関しては、IDEの[Curl開発者ガイド→基本概念-ライブラリ→正規表現]で実際に文字列を操作しながら確認することが最も理解が深まると思いますので、IDEを持っている方は、ぜひ試してみてください。

関連ヘルプドキュメント

Curl開発者ガイド→基本概念-ライブラリ→文字列→文字列での作業→文字列の検索→正規表現

Curl開発者ガイド→基本概念-ライブラリ→正規表現

ActiveXを使用したExcelデータの操作

一般的なWebアプリケーションからアクセスされるコンテンツはWebサーバーを通じたデータベース内のデータなどです。
しかしCurlはそれらの一般的なサーバーサイドにあるデータでなくローカルディスク上のデータにもアクセスすることができます。
通常のテキストデータやバイナリデータではなく(※)ローカルマシンにインストールされたアプリケーションに依存したファイルなどにアクセスする必定があり場合があります。例えば以下のようなコンテンツです。

  • Microsoft Excel ,Word ,PowerPoint ,VISIO
  • Flashムービー
  • CAD
  • Browserコンロール

上記のようなコンテンツにアクセスする場合は提供されているActiveXコントロールを使用してデータを読み込んだり、または再生したりすることができます。
今回はCurlアプリケーション上に表示されているRecordGrid(一覧形式のインタフェース)からExcelファイルに出力するサンプルを解説していきます。

activex.jpg

※ テキストファイルやバイナリファイルのアクセスについては以下を参照ください。

ActiveXObjectの作成

サンプルソースの7行目に以下のような記述があります。

 

  let obj_Excel:ActiveXObject =
        {ActiveXObject
            ProgId = “Excel.Application”
        }

Excelのような外部コンテンツとやり取りを行うにはまず、ActiveXObjectクラスを使用してExcelアプリケーションのActiveXObjectのインスタンスを生成します。
ちなみにMicrosoft Office 2003、Microsoft Office 2007で確認しましたがExcelのプログラムIDは”Excel.Application”です。

ActiveXObjectのメソッドやプロパティの使用

ActiveXオブジェクトのインスタンスが生成されたらあとはそのメソッドやプロパティを使用してコンテンツを制御することができます。
11行目から32行目までの処理はExcelのマクロの処理をCurlで記述しただけです。
ちなみ以下のセルのボーダーの設定をしている部分を
Curlで記述してる部分とExcelマクロで書いてる部分を比較してみましょう。

 

|| Curlの場合

    set {obj_Excel.Range “A2″,”C14”}.Borders.LineStyle = 1
    set {obj_Excel.Range “A2″,”C2”}.Borders.weight = 4
    set {obj_Excel.Range “A2″,”C2”}.Interior.ColorIndex=12

 

‘  Excel マクロの場合

    Range(“A2:C14”).Borders.LineStyle = 1
    Range(“A2:C2”).Borders.LineStyle = 4
    Range(“A2:C2”).Interior.ColorIndex = 12

 ほとんど同じ記述をしていることがわかります。
このようにActiveXObjectを使用して外部コンテンツをコントロールすることができます。

CurlからExcelファイルの生成とデータの出力

サンプルソースは以下の流れになっています。

1.ボタンを押し出力ファイルを選択する

80行目のCommandButtonの部分で実装しています。84行目のchoose-fileプロシージャを使用してファイル選択ダイアログを出力し、
choose-fileプロシージャの返却値(Url)を6行目で定義されたrecords-to-excelプロシージャに渡しています。

 

{CommandButton
    label=”Excel出力”,
    {on Action do
        let file-url:#Url
        {if-non-null file-url={choose-file
                                  style = FileDialogStyle.save-as,
                                  filters={{Array-of FileDialogFilter}
                                              {FileDialogFilter
                                                  “Microsoft Office Excel ブック”,
                                                  {new
                                                      {Array-of FileDialogTypeFilter},
                                                      {FileDialogTypeFilter “xls”}
                                                  }
                                              }
                                          }
                              } then
           
            {records-to-excel file-url.name,”海外ドラマ「HEROS」のキャスト”,rg.records}
        }
    }
}

2.Excelファイルが生成され保存される。

Excelファイルを生成し、データを出力する部分がrecords-to-excelプロシージャです。このプロシージャはパラメータとして以下を受け取っています。

  • ファイル名(String)
  • タイトル名(String)
  • レコードデータ(RecordView)

 

define-proc {records-to-excel str_FileName:String,title:String,records:RecordView}:void

メインの処理は3番目のレコードデータを35行目のロープ処理で1行づつ出力しているところです。それ以外は罫線や背景を設定しています。 

 

let i:int=3
{for r in records do
    set {obj_Excel.Cells i,1}.Value = {r.get “First”}
    set {obj_Excel.Cells i,2}.Value = {r.get “Last”}
    set {obj_Excel.Cells i,3}.Value = {r.get “Power”}
    set {obj_Excel.Cells 1,3}.ColumnWidth = 40
    set i = i + 1
 }

 

注意事項

  • AcitveXの削除
    ActiveXObjectは削除しない場合はガベージコレクションでされない限りメモリ上に残ってしまいますので処理の終了時にActiveXObjectを削除することをお勧めします。
  • クライアントマシンに依存するActiveXコントロール
    またActiveXコントロールはクライアントマシンの環境に依存するためActiveXコントロールの有無やバージョンなども十分に考慮し使用することをお勧めします。
  • セキュリティについて
    ActiveXコンロールはクライアント資源の一つです。クライアント資源にアクセスするにはセキュリティレベルを解除する「特権」を 付与しなければなりません。

詳しくはこちらをご覧ください。
Curlのセキュリティモデルについて」(Curl Blog)
チュートリアル-開発準備編-セキュリティの設定(特権設定)」 

 

サンプルコードのダウンロード

関連ヘルプドキュメント

Curl開発者ガイド→グラフィカルユーザーインターフェイス→ActiveXコントロール

XMLフォーマットの利用(SAXパーサー)

XMLフォーマットを扱う場合、Curlでは標準APIとしてSAX(Simple API for XML)機能が用意されています。SAXはXML文書を先頭から解析し、発生したイベントをアプリケーションでキャッチして処理するAPIです。DOMに比べ、解析速度が速く少量のメモリ消費量というメリットがありますが、ノードの追加、削除等、XML文書を更新する機能はありません。

ここではSAXパーサーを利用したXML解析方法について、下記サンプルXMLを用いて説明します。 

<RecordSet>
  <Record name=”AAA”>
    <Value>”123″</Value>
    <Value>”456″</Value>
  </Record>
  <Record name=”BBB”>
    <Value>”xyz”</Value>
  </Record>
</RecordSet>

 SAXパーサーを使用するためには、まずDefaultHandlerクラスを継承したイベントハンドラを作成します。このクラスのstart-document、end-document、start-element、end-element、charactersメソッドを実装します。下記サンプルは、それぞれのメソッドで取得したXMLの値等をoutputプロシージャにて結果を表示させています。

{define-class public MySAXApp {inherits DefaultHandler}
  {constructor public {default }
    {construct-super}
  }

  {method public {start-document}:void
    {output “#start-document”}
  }

  {method public {end-document}:void
    {output “#end-document”}
  }

  {method public {start-element
                     uri:String,
                     name:String,
                     qname:String,
                     atts:Attributes
                 }:void
    {output “#start-element”}
    {output ” タグ = ” & name}
    {output ” 属性名 = ” & {atts.get-local-name 0}}
    {output ” 属性 = ” & {atts.get-value 0}}
  }

  {method public {end-element
                     uri:String,
                     name:String,
                     qname:String
                 }:void
    {output “#end-element”}
    {output ” タグ = ” & name}
  }

  {method public {characters
                     ch:StringBuf,
                     start:int,
                     length:int
                 }:void
    {output “#characters”}
    {output ” 要素 = ” & ch}
  }
}

各XML構文解析イベントを受け取り呼び出されるメソッドの説明は下表の通りです。

start-document ドキュメント開始の通知を受け取ります。
end-document ドキュメント終了の通知を受け取ります。
start-element

要素の開始の通知を受け取ります。
XML ドキュメント内の各要素の開始時にこのメソッドを起動します。

end-element

要素の終了の通知を受け取ります。
XML ドキュメント内の各要素の最後にこのメソッドを起動します。

characters 文字データの通知を受け取ります。

XML構文解析イベントの流れは、まずstart-documentメソッドが実行されます。ノードを読み込むとstart-elementメソッドが実行され、タグ名や属性等を取得できます。次にstart-elementメソッドが終了すると、charactersメソッドが実行され、テキストを取得できます。最後に終了タグを読み込むため、end-elementメソッドの中身が実行されます。 

これらのハンドラの呼び出し方法は、以下のようにSAXパーサーを作成し、set-content-handlerを使用して上記で作成したイベントハンドラを登録します。

{let xr:XMLReader = {SAXParser}}
{let handler:MySAXApp = {MySAXAppt}}
{xr.set-content-handler handler}

上記にて作成したSAXパーサーのparseメソッドを使用してXMLデータを解析します。 

{xr.parse {InputSource system-id = XMLデータのURL}}

実行結果

#start-document
#start-element
 タグ = RecordSet
 属性名 = <null>
 属性 = <null>
#characters
 要素 =
 
#start-element
 タグ = Record
 属性名 = name
 属性 = AAA
#characters
 要素 =
   
#start-element
 タグ = Value
 属性名 = <null>
 属性 = <null>
#characters
 要素 = “123”
#end-element
 タグ = Value
#characters
 要素 =
   
#start-element
 タグ = Value
 属性名 = <null>
 属性 = <null>
#characters
 要素 = “456”
#end-element
 タグ = Value
#characters
 要素 =
 
#end-element
 タグ = Record
#characters
 要素 =
 
#start-element
 タグ = Record
 属性名 = name
 属性 = BBB
#characters
 要素 =
   
#start-element
 タグ = Value
 属性名 = <null>
 属性 = <null>
#characters
 要素 = “xyz”
#end-element
 タグ = Value
#characters
 要素 =
 
#end-element
 タグ = Record
#characters
 要素 =

#end-element
 タグ = RecordSet
#end-document

サポートバージョン

RTE5.0以上

参考ドキュメント

http://developers.curlap.com/curl/docs/rte/6.0/ja/docs/ja/dguide/using-sax-xml.html

 

JSONフォーマットの利用

JSON(JavaScript Object Notation)とは、Javascriptの言語仕様がベースになっている軽量のデータフォーマットです。JSONフォーマットはCurl6.0から扱えるようになりました。詳細については、以下のホームページをご参照ください。
  http://www.json.org/

JSONフォーマットのパースとフォーマット文字列の出力

まずは以下のJSONフォーマットで記載されたファイル(test.json)を用意します。 

{
  “id”:123,
  “name”:”岡田”,
  “address”:”東京都”,
  “hobbies”:[“snowboard”, “golf”]
}

 CurlはJSONデータタイプのクラスとして以下のものを用意しています。 

 クラス 説明 
 JsonValue  これはany型のシノニムです。
 JsonObject  これは{HashTable-of any}型のシノニムです。JSONフォーマットでは”{“及び”}”で囲まれたデータが連想配列となります。
 JsonArray  これは{Array-of any}型のシノニムです。JSONフォーマットでは”[“及び”]”で囲まれたデータが配列となります。

JSONフォーマットをパースし、JsonValueもしくはJsonObject・JsonArrayオブジェクトを生成するには、JsonValue-parseを使います。以下の例では、test.jsonのJSONフォーマットをパースし、JsonValueを作成しています。 

let obj:JsonObject =
    {JsonValue-parse {url “test.json”}} asa JsonObject
    {dump
        v[“id”],
        v[“name”],
        v[“address”],
        v[“hobbies”][0],
     v[“hobbies”][1]
    }

逆にJsonValueをJSONフォーマット(文字列)に変換するには、JsonValue-to-Stringプロシージャを利用します。

let str:String = {JsonValue-to-String v}{dump str}

サポートバージョン

RTE6.0以上

 

RecordSetを使用したデータハンドリング

Curlでは、構造化データを扱う際は、基本APIのRecordSetを使用します。RecordSetを使用することで、1つ以上のデータベースから取得したデータを、クライアント側でDBを操作するようにフィルタリングやソート等の処理を行うことが可能になります。

RecordSetは”deta centric”なアプリケーションには必須のAPIです。

RecordSet Data

RecordSetはRecordの集合を保持しています。各Recordは事前に定義されたキー(カラム)に対しての値を保持しています。カラム構造はフィールド定義(RecordfieldとRecordFieldsを使います)によって定義されます。

/wiki/samples/images/RecordSet.jpg

Curlでは、RecordSetを作成するのに、2種類の方法があります。
1.プログラミングにより生成する方法
2.CSV形式のファイルデータを読み込み生成する方法

また、CurlAPIにはデータベース、もしくはリモートのデータファイルと直接接続できるものもあります(RecordSetを使用したデータハンドリング:2 でご紹介いたします。)

プログラミングによりRecordSetを生成する方法

他のCurlオブジェクトと同じように、RecordSetもコンストラクタを呼び出し、引数を使うことでインスタンスを生成します。

・RecordFieldsはRecordFieldの集合体を定義するために使用されます。各RecordFieldの記述は各カラムの名前とデータ型を宣言しています。)
・RecordDataオブジェクトは1組のレコードの値を操作、管理するために使用されます。

 

{curl 5.0, 6.0 applet}

{value
   let items:RecordSet =
       {RecordSet
           {RecordFields
               || 各フィールドの名前や使用するデータ型(ドメイン)を定義
               {RecordField “Item”, domain = String},
               {RecordField “Description”, domain = String},
               {RecordField “Quantity”, domain = int}
           },
           || 各フィールドに値を代入したレコードを定義、RecordSetに代入しています。
           {RecordData Item = “PR1400”, Description = “Blue pens”, Quantity = 12},
           {RecordData Item = “LG4597”, Description = “Envelopes”, Quantity = 100},
           {RecordData Item = “NP3400”, Description = “Notepads”, Quantity = 6},
           {RecordData Item = “PN5601”, Description = “Pencils”, Quantity = 28}
       }
  ||RecordSetを表形式で表します
   let record-display:RecordGrid =
       {RecordGrid
           record-source = items
       }
   record-display
}

 

*基本のドメインは次のCurl型によって定義されています。: char, String, int, int64, float, double, bool, DateTime, Time, or any

 CSV形式のファイルデータを読み込み生成する方法

CSVは、データをカンマで区切って並べたデータ形式であり、大量のデータを一気にスプレッドシートやデータベース等からアプリケーションへ移行する際に有効な形式です。

CurlもこのCSV形式をサポートするAPIを持っています。CsvRecordSetはRecordSetのサブクラスであり、RecordSetの中に複数のRecordを自動で作成することが可能です。

それではまず、CSV形式のデータを作成してみましょう。 Microsoft ® Excel を使って、下記のようなデータを作成し、CSV形式で保存します。 inventory_items.csvという名前で任意のフォルダに保存して下さい。

 

/wiki/samples/images/csvdata.jpg

 次にCurlアプレットを作成してみましょう。コードは下記のようになります。
下記のコードをstart.curlとして、CSVファイルと同階層に保存してください。
今回は、CsvRecordSetを使用し、CSV形式のファイルをCurlにインポートします。

{curl 5.0, 6.0 applet}

{value
   let rs:CsvRecordSet =
       {CsvRecordSet  
           ||CSVファイルの場所を指定します。
           {url “inventory_items.csv”}
       }
   {RecordGrid record-source =  rs,
       width = 6in,
       height = 2in
   }
}

CsvRecordSetは以下のステップでCSVデータを読み込みます。

・CSVデータの各行からRecordを作成
・データの各フィールドをパース
・各フィールドをCurlデータ型へ変換