【Unity】CSVファイルをXML形式にコンバートするEditor拡張
Editor拡張を使った処理として、CSVファイルをXML形式にコンバートするサンプルを考えます。
上の記事ではUnityでマスタデータを持つ時のファイル形式について比較を行ったのですが、そこで紹介したのがCSV、XML、JSON、YAMLでした。
通常、マスタデータとなるExcelなどのファイルから出力するときに変換することが多いと思いますが、せっかくなのでそれぞれUnityの中で変換する方法もあってもいいよね! と思い立ったのでこの記事を書くことに。
ええ、ただEditor拡張のスクリプトを書きたいだけです。
環境
macOS 10.14 Mojave
Unity2018.2.20f1
ファイル形式について
今回はCSVファイルからXMLファイルへの変換を行います。
CSVファイル
CSVはComma-Separated Values、その名の通りカンマで区切られた値が並ぶテキストファイルです。
Excelなどの表計算ソフトからだとCSVファイルでエクスポートする機能があるかと思うので、それを使ってCSVファイルを用意します。
XMLファイル
XMLはExtensible Markup Language、拡張可能なマークアップ言語です。タグを使ってデータ構造を表現しており、データと意味との対応が分かりやすい形式です。
UnityでXMLを使うメリットはそんなにないのですが、例えば敵キャラのデータをエクスポートしてWebで公開したい、なんてときにはXMLで表現されていると便利……かもしれません。
変換元のデータ
以下の表データをExcelなどからCSV形式でエクスポートし、Unityのプロジェクトにインポートします。このファイルをUnityプロジェクト内でXML形式に変換します。
今回のサンプルでは、敵キャラのデータをCSVからXMLに変換する例を考えます。
enemyName | maxHp | atk | def | exp | gold |
スライム | 4 | 2 | 2 | 1 | 2 |
ゴブリン | 8 | 4 | 2 | 2 | 3 |
ジャイアントマウス | 12 | 5 | 3 | 3 | 5 |
作業の流れ
今回のサンプルで行う作業は以下の通り。
- コンバート対象のCSVファイルを参照し、変換ボタンを表示させるScriptableObjectを作成
- 上記ファイルのInspector表示と変換の動作を定義するEditor拡張スクリプトを作成
- ボタンを押してCSVファイルの内容がXMLファイルとして書き出されたことを確認
作成したいのはScriptableObjectが1つ、そのScriptableObjectに適用するEditor拡張スクリプトが1つ、合計2つのスクリプトです。
ScriptableObjectの概要や作り方については以下の記事で扱っているので、こちらも併せてご参照ください。
ファイル変換用のScriptableObjectを作成
今回のEditor拡張では独自のウィンドウを作成せず、作成したScriptableObjectのInspector表示をカスタマイズします。
まずはスクリプトファイルの作成から。Projectウィンドウで任意のフォルダで右クリックして[Create] -> [C# Script]を選択します。
こんな感じでスクリプトファイルが作成されます。名前は「CsvToXmlConverter」にしました。
フォルダ作成については省略しちゃいましたが、Projectウィンドウ内でスクリプトを整理したかったので、「Assets」フォルダの下に「Convert」フォルダを作成し、さらにその中に「CSVtoXML」フォルダを作成しています。
ScriptableObjectのアセットファイルと同じフォルダ内に変換後のファイルを書き出したいので、任意のフォルダに分けておくと整理しやすいです。
CsvToXmlConverterの中身は以下のように編集します。
ScriptableObjectを継承するのがポイントです。
CreateAssetMenuのAttributeではScriptableObjectのアセットファイルを作成するためのパスを設定しています。
このスクリプトを保存し、コンパイルが終わると、右クリックのメニューからScriptableObjectのアセットファイルを作成できるようになります。例えば上のスクリプトの例であれば、[Create] -> [MyScriptable] -> [Create CSV to XML Converter]と選択することでアセットファイルが作成されます。
メニューバーの[Assets]からも同様に作成することができます。
どちらからでも、以下のようなアセットファイルが作成されます。名前は分かりやすく「CsvToXmlConverter」にしました。ここは好きな名前を付けて大丈夫です。
このアセットファイルを選択するとInspectorウィンドウでは以下のように表示されます。
スクリプトの中で定義したCSVファイルを参照させるフィールドが表示されています。
そうそう、CSVファイル自体もUnityにインポートしておきましょうか。ExcelなどからエクスポートしたCSVファイルを同じフォルダなどにインポートします。
早速「CsvToXmlConverter」を選択して、フィールドで参照させておきましょう。フィールドの右にある丸ボタンから選択しようとするとスクリプトファイルまで表示されて探しにくいので、Projectウィンドウからドラッグ&ドロップで参照させると楽ちんです。
これで準備ができたので、このInspectorウィンドウにボタンを追加し、変換処理を実装します。
CSVからXMLへの変換処理をEditor拡張で実装
Editor拡張用のスクリプトは「Editor」フォルダに入れます。プロジェクト内の好きな場所に配置できるため、今回のスクリプトを配置している「CSVtoXML」に新しく「Editor」フォルダを作成します。
新しく作成したフォルダの名前は「Editor」にします。
次に「Editor」フォルダに移動し、Editor拡張用のスクリプトを作成します。名前は「CsvToXmlConverterEditor」としました。
このスクリプトの中で、「CsvToXmlConverter」をInspectorウィンドウで表示する際にボタンを表示させる処理と、変換処理を追加します。
長くなってしまいましたが、順番に説明させてください。
4行目の「UnityEditor」はUnityのエディタの動作を定義するクラスが含まれる名前空間、5行目の「System.IO」はファイルを読み書きするクラスが含まれている名前空間、6行目の「System.Xml.Linq」はC#でXMLを扱うときに使うクラスが含まれる名前空間です。
8行目のCustomEditorのAttributeは、どのScriptableObjectに対してカスタマイズを施すか、という指定です。今回カスタマイズしたいのは「CsvToXmlConverter」クラスのアセットですから、この型を指定します。
11行目から始まるOnInspectorGUI()では、表示をカスタマイズしたいScriptableObjectに含まれるフィールドをDrawDefaultInspector()で描画した後、ボタンを表示させています。ボタンが押された時の処理として、20行目から始まるConvertCsvToXmlのメソッドを呼んでいます。
なお、このメソッドの引数として渡しているcsvToXmlConverterは、Inspectorで表示しているScriptableObjectの情報が含まれています。この中にCSVファイルの参照や、出力後のXMLファイルの名前の情報があるんです。
続いてCSVファイルの内容をXMLファイルとして変換する処理です。
22行目ではCSVファイルの参照がセットされているかどうかを、28行目では出力するXMLファイル名が入力されているかどうかを確認しています。
34行目から37行目までは変換後のファイルの保存先を設定しています。今回はScriptableObjectのアセットファイルがあるフォルダに保存するようにしています。ファイル名については最後に“.xml”と拡張子を付けるようにしました。
40行目ではCSVファイルの内容をstringに格納しています。この情報は「CsvToXmlConverter」のInspectorウィンドウで参照させたCSVファイルを見ています。41行目では改行コードを区切り文字として各行に分割しています。
44行目はヘッダー行を列ごとに分割しています。ここで作成した配列がXMLのタグとして使われます。
47行目からはいよいよXMLファイルの作成です。
今回使うのはC#のXDocument。詳細な仕様はMSDNでご確認を。
47行目でルート要素の名前を決めて、48行目でXMLのドキュメントをメモリ上に作成しています。個人的に宣言部分を入れたかったのでXDeclarationを入れています。
new XElement を使うとタグで始まりタグで終わるXMLの要素が生成されます。最初にルート要素を作っておいて、そこにAddを使って追加していきます。
ループの中ではデータ行をカンマで分割し、ヘッダー行と同じ列のデータをひとつのXElementとして作成します。XMLの構造は、Root(全体でひとつ) -> Data(データ行ごと) -> 各データ要素 としているので、入れ子になっていることにご注意を。
生成が終わったらSaveメソッドを呼んでデータを保存します。引数でStreamWriterを渡しており、34行目から37行目で設定した情報を元にファイルが作成されます。
ファイル作成後は、Projectウィンドウでの表示を最新のものにするため、AssetDatabase.Refresh()を呼んでいます。
なお、正しくないCSVファイルが読み込まれている場合はtry-catchの中でこけるので、その場合はファイルを出力しないでメソッドを抜けるようにしています。ちょっと雑な気もするけどサンプルなので許してください。
実際にやってみよう
上のスクリプトを保存してコンパイルを終わらせると、「CsvToXmlConverter」のアセットを選択したときにInspectorウィンドウでの表示が変わります。
「XMLに変換」ボタンをクリックすると、以下のように変換後のファイルが同じフォルダに作成されます。
元のファイルと出力されたファイルを比べてみます。うまくマッピングできていますね。今回はRootやDataといったようにルート要素と親要素の名前をスクリプトに直書きしちゃいましたが、この辺はお好みで変えてください。「CsvToXmlConverter」のフィールドとして設定項目を入れてもいいかも。
これでCSVをXMLに変換するEditor拡張ができました!
今回のスクリプトの弱点
もうお気付きの方も多いかと思いますが、今回のスクリプトには弱点があります。
それは、セルの中にカンマがある場合のエスケープ処理と、セル内の要素を”ダブルクォーテーション”で囲ったときのエスケープ処理がないこと。
お行儀の良いデータを変換する際にはこれでもいいのですが、より汎用的に使えるようにするならエスケープ処理を入れておいたほうがいいかも。
と、いいCSVパーサーがないかなーとググったら、ライセンス不要で使えるパーサーを作ってくれた方がいました。神。
戻り値がList<List<string>>なので、ファイル全体を一気にパースしてくれます。50、53、57行目あたりの分割をこちらに任せれば良さそうです。
まとめ
CSVファイルをXMLファイルに変換するEditor拡張のサンプルを紹介しました。
ちょっとした時に使えるEditor拡張を貯めておくと便利かもしれません。
Unityをゲーム作りじゃなくてデータ変換ツールとして使うのもアリかも。
あ、スクリプトにツッコミがあったらぜひコメントでお願いします。
ゲーム開発の攻略チャートを作りました!
-
前の記事
【Unity】CSVファイルにデータを書き込むEditor拡張サンプル 2019.02.07
-
次の記事
【Unity】XMLファイルをCSV形式にコンバートするEditor拡張 2019.02.09
コメントを書く