Help us understand the problem. What is going on with this article?

OutsystemsでCSVの読み込みと出力をしてみた

はじめに

会社のITメンバーで参加している2019年のアドベントカレンダーに、自身2つ目の記事を投稿します!
自己紹介も兼ねて、前回書いた記事はこちらになります。
https://qiita.com/tom-k7/items/d8ef19dccb42891a0698

今回もOutsystemsについて書きます。
今はちょうどOutsystemsでCSV変換ツール(Webアプリ)を開発しているので、
OutsystemsでCSVの読み込み・出力の実装方法、あとは開発中にぶち当たった壁について共有させていただきます。

やりたいこと

今開発しているツールでやりたいこととしては、
いろんな他社さんのサイトからダウンロードしたCSVファイルを
社内で使ってるシステムにインポートできるフォーマットのCSVファイルに変換したい。
なので、ダウンロードしたCSVファイルを読み込んで、
ごにょごにょ変換して新たなCSVファイルを出力するということをOutsystemsで実現します。

Forge

CSVファイルの読み込み・出力にはCSVUtilのForgeコンポーネントを使います。
https://www.outsystems.com/forge/component-overview/636/csvutil

こちらをダウンロードし、ServiceStudioにインストールしてDependencyに追加してください。

画面の開発

CSV処理をやる前に画面を作っちゃいます。

CSVファイルのアップロード

まずは読み込む対象のCSVファイルをアップロードする必要があります。
方法は2つあります。
①Uploadを使う
image.png
②RichWidgets\Popup_Uploadを使う
image.png

今回は①のほうが良いということになったので、Uploadを使います。
※ちなみにUploadウィジェットは、ListRecordsのようなリストの中では動かないのでご注意ください。

変換処理を行うサーバアクションを呼ぶためのボタンを配置

ConvertボタンのDestinationに変換処理を行うConvertサーバアクションを指定し、
そのサーバアクション内で変換処理を行います。
image.png

CSV読み込み処理の実装

さて、ここからは本題のCSVの処理です。
まずはCSVファイルの読み込みを実装します。

LoadConfigの設定

CSV読み込み時の設定をするためのCSVLoadConfig型のローカル変数を定義し、Assignで設定します。
image.png
主な設定内容は以下の通り。

  • Encode:CSVファイルの文字コード。utf-8やshift-jisなどを設定。
  • IsSkipHeader:CSVファイルにヘッダー行がある場合はTrue、ない場合はFalse。
  • IsIgnoreColumnChange:カラム数が合わない場合にエラーとする場合はFalse、エラーとしない場合はTrue。             試してみたら違いました。。このフィールド謎です"(-""-)"
  • FieldDelimiter:カラムの間の区切り文字。複数文字入れられるが、先頭の1文字しか適用されない。
  • IsDisableDoubleQuote:カラムがダブルクオーテーションで囲われてる場合はFalse、そうでない場合はTrue。

読み込み用RecordListを定義

CSVを読み込んだ結果を格納するEntity/StructureのRecordのリストを、ローカル変数で定義します。
今回は自作のSourceCSVというStructureのRecordListにしています。
image.png
※StructureのListでなく、StructureのRecordのListにしないとうまくいきません。

Extension処理の呼出し

ForgeのCSVUtilで定義されているLoadCSVRecordListサーバアクションを呼び出し、
引数には画面で作ったUploadのContentと、CSVLoadConfigのローカル変数、
Entity/StructureのRecordListをToObject()で変換した結果をそれぞれ設定します。
image.png
これで読み込みは完了です。

CSV出力処理の実装

続いて、CSV出力のほうも実装していきます。

ExportConfigの設定

CSV出力時の設定をするためのCSVExportConfig型のローカル変数を定義し、Assignで設定します。
image.png
主な設定内容は以下の通り。

  • IsShowHeader:CSVファイルにヘッダー行を入れる場合はTrue、入れない場合はFalse。
  • FieldDelimiter:カラムの間の区切り文字。複数文字入れられるが、先頭の1文字しか適用されない。
  • EncodeMode:カラムをダブルクオーテーションで囲うか否か。auto/quote/noquote/noquote_nocheckのいずれかを文字列で設定。
  • LineSeparator:改行コード。CRだとChr(13)、LFだとChr(10)、CRLFはChr(13) + Chr(10)と設定。

出力用RecordListを定義

出力するCSVのデータを格納するためのEntity/StructureのRecordのリストを、ローカル変数で定義します。
画像は自作のOutputCSVというStructureのRecordListにしています。
image.png

出力用RecordListに読み込んだデータを変換して設定

↑で定義した出力用RecordListに対して、Loadしたデータが入っているRecordListの全件を設定します。
その際に値を変換したり、結合したり、不要なものは捨てたりして出力用に設定すれば変換ができますね。
image.png
画像ではListAppendAllで単純に項目の結合だけしてますが、実際にはここでいろんな変換をします。
かなり複雑なことをやる場合はForEachでループするケースもあると思います。

Extension処理の呼出し

CSVUtilで定義されているExportRecordList2CSVサーバアクションを呼び出し、
引数にはEntity/StructureのRecordListをToObject()で変換した結果とCSVExportConfigのローカル変数をそれぞれ設定します。
image.png

変換後CSVファイルの出力(ダウンロード)

最後にExportRecordList2CSVで作成されたCSVデータをDownloadウィジェットに渡して終了です。
image.png

開発中に引っかかった罠

以上が実装方法になりますが、その他CSVUtilを使っててぶち当たった壁について共有したいと思います。

出力時にダブルクオーテーションで囲う方法がわかりづらい

「ExportConfigの設定」でダブルクオーテーションで囲う方法はすでに記載済みですが、
そこにたどり着くまでに結構かかりました。
だって、その項目の名前EncodeModeて。。
文字コードのことかと思うやん。わからんて。。
ていう愚痴でしたww

ちなみにCSVExportConfig.EncodeModeに"quote"を指定するとダブルクオーテーションで囲ってくれます!

Export処理でNullReferenceException

CSVUtilのExportRecordList2CSVサーバアクションを呼び出した際にこんなエラーが出ました。
Object reference not set to an instance of an object.
NullReferenceExceptionです。Javaでいうヌルポですね。
CSVの項目としては基本型しか使ってないので、Outsystemsで基本型でNullってあるんだっけ?って感じでした。

それでこのエラーはこれ以上詳細にはログに出ないので、いろいろ試してもうまくいかず途方に暮れた結果、
Extensionの中見るしかないな!ってなりました。
でExtensionダウンロードして、VisualStudioでsln開いてソース追っても原因わからず。
じゃあってことで、実際に渡してたデータをC#上で作って実行してみました!(^^)!(これが地味にめんどかった)

やってみた結果、渡したデータのカラムが1個足りてないせいでNullReferenceExceptionになっていたことが判明。
そのカラム何だろうと思ってたら、データ変換するときに特殊なことをしているカラムでした。

説明が意味不明だったらすいません
例えば読み込んだデータの値が"1"なら、変換後は"大学院"とするみたいなものをJSONファイルにKeyとValueのペアとして定義し、
JSONファイルをResourcesとしてモジュールにインポート。
image.png

そのJSONファイルをJSONDeserializeで読み込み、ForgeのHashTableを使ってKeyとValueのペアとしてメモリに格納しておき、
変換時はそのHashTableからgetした値を設定するという処理にしていました。

ForgeのHashable:https://www.outsystems.com/forge/component-overview/21/hashtable

それが、JSONで定義したKeyにはないデータ(↑のJSONだと"5"とか空文字とか)が読み込むCSVに入っていたため、getの結果がNullとなり、
それをExportRecordList2CSVに渡したためにNullReferenceExceptionとなったということでした。

Outsystemsで普通に実装してたらText型にNullは入らないのですが、
Extensionを介すとNullが入るんだなって知り、勉強になったなと思いました。

最後に

OutsystemsでのCSV読み込み・出力について説明しました。
これからCSVUtilを使う方、同じ壁にぶつかった方の一助になればと思っています。

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした