ADVENT CALENDAR 2019
ほんの10行でJsonとかXmlとか楽々読み込み with F#
By wraikny
はじめに
JsonやXmlやHtmlやCSVを読み込みたいことってありますよね。 でも文字列でアクセスするのはバグの要因になるし、かといってすべてClassなどにバインディングするコードを書くのは大変です。
urlやファイルパスを指定しただけで型が自動生成されて、すぐさまコード補完が効き始めたら、嬉しくありませんか?
今日はF#公式ライブラリFSharp.Dataの紹介をします。
環境
.NET Core SDK 3.0以上が必要です。
未インストールの方はこちらから
https://dotnet.microsoft.com/download
$ dotnet --version
3.0.100
また、VSCodeやVimを使っている方は、Ionideという拡張機能をインストールすることで補完等が効くようになります。 自分はVSCode + Ionideを使っていてオススメです。
テンプレート
を用意したので、こちらにあるのでCloneなりUse this templateしてください。
https://github.com/wraikny/FSharp.Data-Template
ローカルで開いたら、初回のみrestore(復元)を実行し、
dotnet tool restore
dotnet paket restore
以降は以下のコマンドで実行できます。
dotnet fsi --exec src/Main.fsx
書いてみる
src/Main.fsx を開くと、
printfn "Hello, world"
とあるはずです。
ではGithub
のapiから、FSharp.Dataのリポジトリのissue一覧を取得して表示するコードを書いてみましょう。
ファイルの中身は一度消去してください。
なお、F#のコードは上から下に一方向にしか書いて行けないので、ここに記載する順番にコードを書くものとします。
まずFSharp.Data
を使用するために以下のように記述して、間接的にdllを参照します。
#load "./FSharp.Data.fsx"
そして、FSharp.DataのJsonProvider
を使って型生成を行いましょう。
APIのurlを指定してGitHub
型としてエイリアスを作ります。
type GitHub = FSharp.Data.JsonProvider<"https://api.github.com/repos/fsharp/FSharp.Data/issues">
Ionideを入れていれば、自動的に型生成されて補完が効き始めるはずです。 (数秒のラグはあるかもしれません)
では、読み込んでいきましょう。
GitHub.GetSamples()
|> Seq.filter(fun x -> x.)
コード補完が働いているのがわかると思います!
(表示されなかったら一度.
を削除してもう一度打ってみるといいかもしれない)
続きを書いていきます。
State
がopen
のものだけを取り出し、そこから5個だけ取り出すコードです。
GitHub.GetSamples()
|> Seq.filter (fun x -> x.State = "open")
|> Seq.truncate 5
F#ではイコールが=
です。==
ではないです。
|>
はパイプ演算子と言って、関数を順次適用していくものです。
見た目はshellのパイプやC#のメソッドチェーンに近いですね。
ここではLinq
に相当する操作をしています。
続いて、得られた値を整形していきましょう。
|> Seq.map(fun x -> sprintf "#%d: %s" x.Number x.Title)
|> String.concat "\n"
|> printfn "%s"
map
はmapping、つまり写像です。
sprintf
を使って入力を文字列に変換しています。
String.concat
は文字列を結合する関数です。
最後にprintfn "%s"
にパイプすることで、文字列を出力します。
では、実行してみましょう! おおよそ以下のように出力されれば大丈夫です。
$ dotnet fsi --exec src/Main.fsx
#1295: Error with embedded resource in XmlProvider
#1294: Any way to get siblings of HtmlNode?
#1293: Http Utilities - Encoding problem
#1292: Can't get inner text of a script
#1291: Expose InnerResponse, Http properties
タイプミスなどは優しくエラーを出してくれるので、その場合は言われた場所をよく確認しましょう。
ここまでで、全体像は以下のようになっているはずです。
Main.fsx
#load "./FSharp.Data.fsx"
type GitHub = FSharp.Data.JsonProvider<"https://api.github.com/repos/fsharp/FSharp.Data/issues">
GitHub.GetSamples()
|> Seq.filter (fun x -> x.State = "open")
|> Seq.truncate 5
|> Seq.map(fun x -> sprintf "#%d: %s" x.Number x.Title)
|> String.concat "\n"
|> printfn "%s"
空行除けば8行しかありませんね! お手軽すぎる!!
また、こことは別のurlを読み込みたいこともあります。
処理を関数にして、Load
メソッドを使用して動的に取得してみましょう。
#load "./FSharp.Data.fsx"
type GitHub = FSharp.Data.JsonProvider<"https://api.github.com/repos/fsharp/FSharp.Data/issues">
let printIssues n (x : GitHub.Root []) =
x |> Seq.filter (fun x -> x.State = "open")
|> Seq.truncate n
|> Seq.map(fun x -> sprintf "#%d: %s" x.Number x.Title)
|> String.concat "\n"
|> printfn "%s"
GitHub.GetSamples() |> printIssues 3
printfn ""
GitHub.Load("https://api.github.com/repos/AmusementCreators/WebSite/issues")
|> printIssues 7
printfn ""
これでもたったの13行です!
実行すると、このように得られます!
$ dotnet fsi --exec src/Sample.fsx
#1295: Error with embedded resource in XmlProvider
#1294: Any way to get siblings of HtmlNode?
#1293: Http Utilities - Encoding problem
#77: ヘッダー画像のサイズが共有時に良くない(サイズと見栄え)
#76: Articles, Postsの一覧にアドカレの記事が表示されない。
#70: Hugo アップデート
#69: meta name="keywords" タグがない
#66: AmCr アドベントカレンダー 2019
#57: タイトル(と本文)をゴシック体にする
#45: 著者ページの実装
ここまで書いたコードは Smaple.fsx として載せてあります。
まとめ
今回はAPIからURL経由でJsonを取得させましたが、urlを入れた箇所にそのままファイルパスを指定することで読み込むことも可能ですし、
type Hoge = JsonProvider<"""
{
hoge: "neko",
fuga: "inu"
}
""">
のように直接サンプルを書くこともできるなど、とてもシンプルで使い勝手が良いです。
FSharp.Data
には、今回紹介したJsonProvider
以外にもXml、Html、CSVのType Providerが実装されています。
FSharp.Data以外でも YamlConfigProvider や SQLProvider や ExcelProvider など、様々なType Providerライブラリがあります。
スクリプトでお手軽にAPIやファイルを読み込めるF#とFSharp.Dataをぜひ使ってみてください!
今回のリポジトリをもう一度貼っておきます。
⭐などいただけると嬉しいです。
https://github.com/wraikny/FSharp.Data-Template
SHARE THIS POST
Tweet