砂漠の旅人(たびと)|新天地:たびとの旅路

電脳砂漠を旅する、ある旅人の日記。フロッピーを頼りに歩いた日から、クラウドの地平を見つめる今日まで。見つけたオアシスも、迷い込んだ砂の迷宮も、全てこの羊皮紙に。

JSONの迷宮を解き明かせ ~Redfishの入れ子構造をマージする、再帰の魔法~

どうやら、一筋縄ではいかない砂の迷宮に迷い込んだらしい。この顛末を書き残しておくか。

仕事でRedfishという広大な遺跡を探査していると、@odata.idという名の無数の道標に出会う。しかし、その道を一つ一つ手作業で辿るのは、あまりに果てしない旅だ。Postmanやcurlという名の松明を手にしても、道の数が二桁を超えたあたりで、私の心は折れそうになっていた。

「この迷宮の、完全な地図を描き出す魔法の道具はないものか?」 そう、全ての道を自動で辿り、その景色を一枚の巨大な羊皮紙に描き出す、そんな夢のような道具を。 今回は、実物の遺跡がなくとも試せるよう、Redfishのモックアップサイトという名の「設計図の断片(JSONファイル)」を使い、その夢をC#で実現する、壮大な錬金術の記録である。

この羊皮紙のあらまし

この羊皮紙が導く者

  • Redfishのような、JSON入れ子構造という迷宮に挑む者
  • 再帰という名の美しい魔法で、複雑な問題をエレガントに解決したい探求者
  • JSONという古代文字を、自在に読み解き、編集する術を知りたい冒険者

第一の儀式:遺跡の構造を理解する(Redfishとは)

Redfishとは、REST APIを使い、JSONという言葉でサーバの魂と対話する、現代の魔法体系だ。その最大の特徴は、@odata.idという道標によって、情報が入れ子状に繋がっていることにある。

全ての道の起点となる、遺跡の入り口

一つの道標を辿れば、また新たな道標が現れる。この無限に続くかのような構造こそが、我々冒険者を悩ませる、迷宮の正体だ。

一つの道を辿ると、また新たな道が現れる

第二の儀式:魔法のレンズを手に入れる(Newtonsoft.Json

この難解な迷宮を解き明かすには、Newtonsoft.Jsonという、強力な「魔法のレンズ」が必要だ。特に、JSONトークン単位で読み解くJsonTextReaderと、それを再び組み上げるJsonTextWriterは、我々の旅に欠かせない。

秘儀の核心:再帰によるマージ

この錬金術の核心は、@odata.idという道標を見つけるたびに、自分自身を呼び出す(再帰する)という、シンプルかつ強力な魔法にある。 その魔法を司るのが、RedfishJsonElementという、二つの設計図(クラス)だ。

設計図:魂を読み解くための器

/// <summary>
/// JSONの要素(魂の欠片)を記録する器
/// </summary>
class JsonElement
{
    public JsonToken TokenType { get; set; }
    public object? Value { get; set; }
}

/// <summary>
/// Redfishの迷宮を探査し、地図を描く者
/// </summary>
class Redfish
{
    public string Root { get; set; } = string.Empty; // 遺跡の断片が眠る場所
    public List<JsonElement> Elements { get; set; } = new List<JsonElement>(); // 集めた魂の欠片

    // 一度通った道を記録しておく羊皮紙
    HashSet<string> OdataItems { get; set; } = new HashSet<string>() { "/redfish/v1/" };
    // ...

    /// <summary>
    /// 全ての道を再帰的に読み込む
    /// </summary>
    public void Read(string path)
    {
        // 遺跡の断片(JSONファイル)を探す
        var jsonfile = @$"{Root}\{path}";
        if (!System.IO.File.Exists(jsonfile)) return;

        // 魔法のレンズで、断片を読み解く
        using var file = File.OpenText(jsonfile);
        var reader = new JsonTextReader(file);
        while (reader.Read())
        {
            // ...(魂の欠片をElementsリストに記録する処理)...

            // もし、そのページに「@odata.id」という名の「新たな道」が記されていたなら…
            if (((string)val1).Equals("@odata.id"))
            {
                // そして、その道がまだ我々の知らない道であったなら…
                if (!OdataItems.Contains((string)val2))
                {
                    // 新たな道を記録し、再びこのReadメソッド自身を呼び出す(再帰)
                    OdataItems.Add((string)val2);
                    Elements.Add(new JsonElement() { TokenType = JsonToken.PropertyName, Value = "/* @odata.child */" });
                    Read(((string)val2)[12..].Replace("/", "_") + ".json");
                }
            }
        }
    }
    // ...(Writeメソッドは、集めたElementsを一つの羊皮紙に書き出すだけなので省略)...
}

この再帰の魔法により、最初にmain.jsonという入口から入るだけで、そこから繋がる全ての道を自動的に探査し、巨大な一枚の地図(JSONファイル)として描き出すことができるのだ。

羊皮紙を巻く前に

今回は、Redfishという広大な遺跡の「地図の断片」を使い、その完全な地図を描き出す方法を紹介した。この魔法の核心は、@odata.idを見つけるたびに再帰的に情報を辿る、というシンプルな考え方にある。

この羊皮紙に記した呪文を改良し、ファイルを読む代わりにREST APIで直接遺跡を探査するようにすれば、この魔法はさらに強力なものとなるだろう。 (そして、その旅の記録は、また別の羊皮紙に記されることになる)

この記録が、同じように複雑なJSONの迷宮で迷う、未来の冒険者の助けとなることを願う。

おっと、どうやら相棒が腹を空かせたようだ。今日はこのへんで筆を置くとしよう。

羊皮紙の余白に書き足す

実際にサーバからRedfishで情報を取得するように修正した、Webアクセス版の冒険日誌はこちらだ。

遺跡の魂を直接読み解け ~RestSharpで、Redfishの深淵を覗く~ - 砂漠の旅人(たびと)

砂漠で見つけた魔法のランプ

  • DMTF Redfish | 遺跡に関する公式の古文書
  • Redfish Mockup | 遺跡の精巧な幻影
  • Json.NET | 古代文字を読み解く魔法のレンズ

ラクダの独り言

ご主人が「じぇいそんのめいきゅう」とか言って、何枚もの羊皮紙を睨みながら、ぶつぶつと呪文を唱えている。なんでも、クモの巣みたいに繋がった情報を、一枚の大きな地図にしているらしい。俺に言わせりゃ、そんな面倒なことする前に、普通に道を歩けばいいだろうに。まったく、人間ってのは、どうしてこう、物事をややこしくするのが好きなのかねえ。やれやれだぜ。