いつ公開されるの？JTIViewer

:::note warn
恐れ多くも昨年に引き続きこんぽさんの「[防災アプリ Advent Calendar 2022](https://adventar.org/calendars/7488)」に参加させていただいております。
他の筆者様の記事も必ず読んでください。
:::

多分12月14日に投稿されるんじゃなかろうかと思いますんで、暇だったら読んでいってくれると土下寝して喜びます。

文体とか気にせずダラダラ書くのでうざかったら画面叩きながら読んでください。
他の方々の内容が詳しすぎて頭の遅い私とは雲泥の差なので...

~~Markdown方式とかひっさしぶりに書くから書き方とか忘れてるので見づらくても許しておくんなまし...~~

# 「こんにちは」

どもども。生命線でございます。
最近寒くなってきて外に出るのも億劫になってきておりますが、皆様いかがお過ごしですか。
今回は色々あって公開できてない**JTIViewer**くんについて話していこうかなと思いまする。

# 開発ログ

## 思い立ち

時は2021年8月(多分)。
私生命線思いました。

「地震情報表示するやつは多くあるけど、津波情報表示するやつ開発されてなくね？」

これは来たと思いましたね。

デザインで参考にしたのはNHKの津波情報のやつですね。あれだけ見やすくて情報が適度にあるのはとてもいいものだと思いました。

ソース元はすぐに見つかりました。
「[気象庁防災情報XMLフォーマット](https://xml.kishou.go.jp/)」です。
来ましたこれでPULL叩いて情報更新した時に表示するだけの簡単なお仕事。

ですがここで問題にぶち当たります。

## 問題

生命線さん、これまで**JSON**しか扱ってきたことがありません。
JSONでEEWの情報やったり、P2Pの情報いじいじしたりぐらいしかやってません。

「XMLってなにそれおいしいの？」

ここで3時間ぐらい悪戦苦闘しました。

## XML問題の解決

解決法は簡単です。

[System.Xml.Serialization.XmlSerializer](https://learn.microsoft.com/ja-jp/dotnet/api/system.xml.serialization.xmlserializer?view=net-6.0)でぽぽぽーんとJSONの時と同じようにクラスに埋め込むことができました。

下はXMLのStringをClassに入れ込む関数です。
ちなみにXmlConvertクラスはJTIViewerで使ってるやつをそのままコピペしてます。どうぞご自由にお使いください。
``JTIViewerException``例外は適当に例外クラス作ってください(私がいつも使ってる[ページ](https://hackers-high.com/c-sharp/develop-self-exception/))。
```cs
//using System.Xml
//using System.Xml.Serialization
//多分usingはこんな感じだった気がする。

    public static class XmlConvert
    {
        public static T ConvertXMLFile<T>(string filePath)
        {
            if (filePath == null) throw new JTIViewerException("filePathはnull以外である必要があります", new NullReferenceException());
            string context = null;
            using (StreamReader reader = new StreamReader(filePath))
            {
                context = reader.ReadToEnd();
            }

            return ConvertXML<T>(context);
        }

        public static T ConvertXML<T>(string context)
        {
            if (context == null) throw new JTIViewerException("contextはnull以外である必要があります", new NullReferenceException());

            return ConvertXML<T>(context, Encoding.UTF8);
        }

        public static T ConvertXML<T>(string context, Encoding encoding)
        {
            if (context == null) throw new JTIViewerException("contextはnull以外である必要があります", new NullReferenceException());
            try
            {
                XmlSerializer __serializer = new XmlSerializer(typeof(T));
                return (T)__serializer.Deserialize(new MemoryStream(encoding.GetBytes(context)));
            }
            catch (XmlException xmlEx)
            {
                Console.WriteLine($"\n[ConvertXML] XmlException {xmlEx.Message}");
                MessageBox.Show($"解析中にエラーが発生しました. \n{xmlEx.Message}", "XMLファイル処理エラー", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return default;
            }
            catch (Exception Ex)
            {
                Console.WriteLine($"\n[ConvertXML] Exception {Ex.Message}");
                MessageBox.Show($"解析中にエラーが発生しました. \n{Ex.Message}", "XMLファイル処理エラー", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return default;
            }
        }

        public static T ConvertXML<T>(XmlReader xmlReader)
        {
            if (xmlReader == null) throw new JTIViewerException("xmlReaderはnull以外である必要があります", new NullReferenceException());
            try
            {
                Console.WriteLine($"Read: xmlReader");
                Console.WriteLine("[ConvertXML] Stream取得");

                Console.Write("[ConvertXML] シリアライズ開始...");
                XmlSerializer __serializer = new XmlSerializer(typeof(T));
                Console.WriteLine("完了");
                Console.Write("[ConvertXML] デシリアライズ開始...");
                Console.WriteLine("完了");
                return (T)__serializer.Deserialize(xmlReader);
            }
            catch (XmlException xmlEx)
            {
                Console.WriteLine($"\n[ConvertXML] XmlException {xmlEx.Message}");
                MessageBox.Show($"解析中にエラーが発生しました. \n{xmlEx.Message}", "XMLファイル処理エラー", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return default;
            }
            catch (Exception Ex)
            {
                Console.WriteLine($"\n[ConvertXML] Exception {Ex.Message}");
                MessageBox.Show($"解析中にエラーが発生しました. \n{Ex.Message}", "XMLファイル処理エラー", MessageBoxButtons.OK, MessageBoxIcon.Error);
                return default;
            }
        }
    }
```

### 使い方

```cs
var hoge = XmlConvert.ConvertXml<XmlClass>(xmlString);
//hogeは入れ込んだ後に出てくる変数。これを参照できる。
//XmlClassはJSONの時みたいなひな形。先にXML電文をコピーして、VSで「編集」→「形式を選択して貼り付け」→「XMLをクラスとして貼り付ける」を押すだけ。あら簡単。これだけでひな形が作れちゃう。
//xmlStringはただの本文。この文字列から読み込んでくれる。

var hooge = XmlConvert.ConvertXmlFile<XmlClass>(xmlFilePath)
//xmlFilePathはXMLファイルがあるパス。読み込みから反映まで一つにやってくれる優れもの。

```

他にもエンコード変更できたりするので試してみてくだせぇ。

## 後は簡単

XMLが解析出来たら後は簡単。
いい感じに整形して色付けて終わり。
そうしてできたのが、**JmaTsunamiInfoViewer**です。
ほら画像どうぞ。
![JmaTsunamiInfoViewer_SeB7r6d7Ma.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689137/a1b960b7-99f4-2e32-9ec1-0f19881a4cf7.png)
名前が違うじゃないかって？

## やらかし

<blockquote class="twitter-tweet"><p lang="ja" dir="ltr">津波アプリのソースコード消してしまいました。<br>GitHubのバックアップβ公開前のやつでした。<br>この一か月消えましたありがとうございました。<br>萎えました。</p>&mdash; 🍁🍠📖生命線📖🍠🍁@寒くなってきました (@userlifeline) <a href="https://twitter.com/userlifeline/status/1482716831530233862?ref_src=twsrc%5Etfw">January 16, 2022</a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>
やらかしましたわね。
Gitに上げてたのに、変なボタン押してバックアップが全部消えちゃいました...
未だになにを押してバックアップが消えちゃたのかわからないので再発防止できません...

## そして復活

その日のうちに消しちゃっても少し残ってたソースコードから新しいアプリを作成して「**J**ma**T**sunami**I**nfo**Viewer**」で「JTIViewer」という名前にして再開発&機能追加を行いました。

今のところの歴史はそんな感じです。

※画像は訓練報です
![13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/689137/27618189-7792-4b0d-0693-dd4d0bf9521b.png)

# 公開状況はどうなんですか

今のところは私のDiscord開発サーバー「[Lifeline's App - Discord](https://discord.gg/EEvB7YquPx)」で半クローズドβ版みたいな感じで公開しています。Discordアカウントあったら一応利用できます。
一般公開はいまだに未定ですね。納得いく更新機能と安定化したら公開する予定ではありますがどうでしょうか。
既に開発から一年。いつになったら一般公開できるのか...

『生命線先生の今後の作品をお楽しみに！』

――内容ないね...w

# リンク

- [説明動画 - YouTube](https://youtu.be/4rMSlSoZlWg)