DataWeaveをコマンドラインから実行する

[DataWeave](https://docs.mulesoft.com/jp/mule-runtime/4.1/dataweave) は、[Mulesoft](https://www.mulesoft.com/jp/) が提供するデータ変換のための言語で、JSON、Excel、CSV、XML 等様々なファイル形式をサポートしています。DataWeave の主要な機能は以下の通りです。

* データ形式の変換 (e.g., JSON から XML など)
* データを操作するための多くの組み込み関数
* データ構造内の項目にアクセスするためのセレクタ
* 型強制
* 独自のデータ型、変数、関数の定義

[その他の豊富な例を確認するには公式ガイドを参照](https://docs.mulesoft.com/jp/mule-runtime/4.1/dataweave-cookbook)してください。通常 DataWeave は Mulesoft のアプリケーション内で使用しますが、[オープンソースの CLI ツール](https://github.com/mulesoft-labs/data-weave-native)を用いることで、DataWeave を独立して使用することができます。この記事では DataWeave CLI の設定方法と基本的な使用方法を紹介します。

## インストール
```
brew tap mulesoft-lab/data-weave
brew install dw
```

Windows では native-image がどうにもうまく作成できませんでした。アップデートを待ちたいと思います。

## DataWeave スクリプトの構成と CLI の使い方
DataWeave スクリプトは以下のような構造を取ります。

```
ヘッダ
---
本文
```

文字列を結合する簡単な例は以下の通りです。

```hello.dwl
output application/json
---
{ "myString" : ('hello' ++ 'World') }
```

* ヘッダの `output` はスクリプトから出力される MIMEタイプ を指定するためのディレクティブです。ヘッダには他にも、変数定義や関数定義、モジュールをインポートする等の処理を記載できます。
* 本文には、出力するための式を記載します。`++` は DataWeave で文字列を結合したりオブジェクトに key, value を追加するための演算子です。

CLI コマンドは、スクリプトを外部ファイルとして読み込むか、インラインで実行することができます。上記の Dataweave スクリプトを dw コマンドで実行する例は以下の通りです。

```
$ dw -f hello.dwl
{
  "myString": "helloWorld"
}%
```

インラインの DataWeave スクリプトを実行する場合は、ヘッダ、区切り文字(`---`)、本文を半角スペースで繋いだ文字列を渡します。

```
$ dw "output application/json --- { "myString" : ('hello' ++ 'World') }"
{
  "myString": "helloWorld"
}%
```

`dw` を実行するとリファレンスが確認できますが、コマンドの使用方法は以下の通りです。

```sh
dw [-p <weavePath>]? [-i <name> <path>]* [-v]? [-o <outputPath>]? [[-f <filePath>] | [-m <nameIdentifier>] | <scriptContent>]
```

|引数&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;|内容|
|------|------|
|--path または -p|独自で定義した関数を別ファイルとして読み込む際のファイルパス|
|--input or -i|インプットファイルのエイリアスとファイルパス。複数指定可。この引数の代わりにパイプで標準出力を渡すこともできます。|
|--verbose または -v|詳細表示オプションを有効にする|
|--output または -o|出力をファイル保存する際のファイルパス。この引数の代わりに標準出力にリダイレクトすることもできます。|
|-f| 実行するDataWeaveファイルのスクリプト |


## 例
### 変換
XML から JSON にそのまま変換する例は以下の通りです。

```input.xml
<?xml version='1.0' encoding='UTF-8'?>
<order>
  <product>
    <price>5</price>
    <model>MuleSoft Connect 2016</model>
  </product>
  <item_amount>3</item_amount>
  <payment>
    <payment-type>credit-card</payment-type>
    <currency>USD</currency>
    <installments>1</installments>
  </payment>
  <buyer>
    <email>mike@hotmail.com</email>
    <name>Michael</name>
    <address>Koala Boulevard 314</address>
    <city>San Diego</city>
    <state>CA</state>
    <postCode>1345</postCode>
    <nationality>USA</nationality>
  </buyer>
  <shop>main branch</shop>
  <salesperson>Mathew Chow</salesperson>
</order>
```

```sh
dw -i payload input.xml -o output.json "output application/json --- payload"
```

```output.json
{
  "order": {
    "product": {
      "price": "5",
      "model": "MuleSoft Connect 2016"
    },
    "item_amount": "3",
    "payment": {
      "payment-type": "credit-card",
      "currency": "USD",
      "installments": "1"
    },
    "buyer": {
      "email": "mike@hotmail.com",
      "name": "Michael",
      "address": "Koala Boulevard 314",
      "city": "San Diego",
      "state": "CA",
      "postCode": "1345",
      "nationality": "USA"
    },
    "shop": "main branch",
    "salesperson": "Mathew Chow"
  }
}
```

### リストの処理
Google Books APIを使用して、400ページ未満の[東野圭吾さんの本](https://www.googleapis.com/books/v1/volumes?q=%E6%9D%B1%E9%87%8E%E5%9C%AD%E5%90%BE)をリストしてみましょう。(ページ数が取得できるものだけ)

```book.dwl
output application/json
---
payload.items filter ((item) -> (item.volumeInfo.pageCount !=null and item.volumeInfo.pageCount < 400))
              map ((item) -> { title : item.volumeInfo.title, 
                              pageCount : item.volumeInfo.pageCount })
```
[map](https://docs.mulesoft.com/jp/mule-runtime/4.1/dataweave-cookbook-map) 関数や [filter](https://docs.mulesoft.com/jp/mule-runtime/4.2/dw-core-functions-filter) 関数を用いてリストを自由に加工できます。

```
curl "https://www.googleapis.com/books/v1/volumes?q=東野圭吾" | dw -f book.dwl -o book.json
```

```book.json
[
  {
    "title": "東野圭吾ミステリースペシャル 分離帯",
    "pageCount": 56
  },
  {
    "title": "ちゃれんじ?",
    "pageCount": 253
  },
  {
    "title": "ナミヤ雑貨店の奇蹟",
    "pageCount": 398
  },
  {
    "title": "東野圭吾ミステリー「白銀ジャック」",
    "pageCount": 336
  },
  {
    "title": "東野圭吾ミステリー「ウインクで乾杯」",
    "pageCount": 322
  }
]
```
cURL など他のコマンドとの組み合わせられるのは CLI の利点を活かせる良い例ですね。パイプで受け取ったインプットのエイリアスは `payload` になります。

### CSV のデータを集計
以下の CSV ファイルから5人のスコアの平均点を計算してみましょう。

```score.csv
player,gameA,gameB
Alice,84.0,79.5
Bob,20.0,56.5
Jimmy,80.0,31.0
Kent,90.5,15.5
Ross,68.0,33.0
```

```score.dwl
output application/json
---
{
    gameA : avg(payload map ((item) -> item.gameA as Number)),
    gameB : avg(payload map ((item) -> item.gameB as Number))
}
```

```
$ dw -i payload hello.csv -f score.dwl
{
  "gameA": 68.5,
  "gameB": 43.1
}%
```

### 組み込みライブラリの読み込み
コアライブラリ以外を使用する場合は import が必要です。以下はメールアドレスから MD5 ハッシュを作成して Gravatar の画像 URL を取得する例です。この他豊富なモジュールが用意されているため詳細は[リファレンス](https://docs.mulesoft.com/jp/mule-runtime/4.1/dw-functions)を確認してください。

```gravatar.dwl
import dw::Crypto
var emailChecksum = Crypto::MD5("email@example.com" as Binary)
var imageURL = "https://www.gravatar.com/avatar/$(emailChecksum)"
output application/json
---
imageURL
```

```
$ dw -f gravatar.dwl
"https://www.gravatar.com/avatar/4068fcaf4bd4822746cc4537a422eced"%
```

## おわりに
DataWeave はインテグレーションに必要となる複雑なデータ処理に対応する言語で、この軽量な CLI は、簡単に API をテストする等、様々な用途に使用できます。サポートされているデータタイプが幅広く、JSON 用、XML 用、CSV 用…等と複数のツールを扱わなくても良いのも魅力です。ぜひ試してみてください。

## 参考リンク
* [DataWeave 言語ガイド](https://docs.mulesoft.com/jp/mule-runtime/4.1/dataweave-language-guide)
* [DataWeave の例](https://docs.mulesoft.com/jp/mule-runtime/4.1/dataweave-cookbook)