プログラムの事とか

お約束ですが「掲載内容は私個人の見解です」

.NET で JSON を読んだ時に認知していないデータを保持したい

.NET 7 で System.Text.Json 使ったときの話です

最近のシステム間のデータのやり取りでは結構な割合でJSONを使うことがあります。ちょっと前までXMLだった気がしますがどんどんJSONになっていますね。(表記する時JSON なのか Json なのか json なのかよくわからない)

想定

{
"a":1,
"b":2
}

を受け取って、"a" をインクリメントして返したい場合、みたいな感じ

var json = @"{""a"":1,""b"":2}";

var t = JsonSerializer.Deserialize<Test>(json);
t.A++;

Console.WriteLine(JsonSerializer.Serialize(t)); // {"a":2,"b":2}

public class Test
{
    [JsonPropertyName("a")]
    public int A { get; set; }
    [JsonPropertyName("b")]
    public int B { get; set; }
}

これでいいですね?

想定外

JSONXML は拡張性があるのが売りです。ほかのシステムで上記 JSON を拡張してしまいました

{
"a":1,
"b":2,
"c":3,
"d":{
  "e":4
}}

これを先ほどのアプリに読み込ませると、当然ですがDeserialize時に c 以降が消えてしまいます

var json = @"{""a"":1,""b"":2,""c"":3,""d"":{""e"":4}}";

var t = JsonSerializer.Deserialize<Test>(json);
t.A++;

Console.WriteLine(JsonSerializer.Serialize(t)); // {"a":2,"b":2}

解決策

クラスの定義(↑ではTest)にJsonExtensionDataAttributeを付けた Dictionary を追加してあげます

var json = @"{""a"":1,""b"":2,""c"":3,""d"":{""e"":4}}";

var t = JsonSerializer.Deserialize<Test>(json);
t.A++;

Console.WriteLine(JsonSerializer.Serialize(t)); // {"a":2,"b":2,"c":3,"d":{"e":4}}

public class Test
{
    [JsonPropertyName("a")]
    public int A { get; set; }
    [JsonPropertyName("b")]
    public int B { get; set; }

    [JsonExtensionData]
    public Dictionary<string, object> AdditionalData { get; set; }
}

できました

XMLの場合

System.Xml.Serialization を使う場合は同じような感じで

[XmlAnyElement]
[XmlText]
public XmlNode[] ChildNodes { get; set; }

で行けるとおもいます

まとめ

JSONXML も 解決策は stackoverflow で見つけたんですが、日本語でもどういうキーワードで調べればいいのかがよくわからない問題だったので英語ではさらに苦労しました、という話でした(?)

続、文字列のソート

前回 文字列のソート - プログラムの事とか のおまけです

前回は絵文字で並べ替えていたので環境によっては正しく表示されなかったり、そもそも絵文字なんて並べ替えねーよ、と思われた方もいると思うので今回はシンプルに3桁の数字(数値ではない)で試してみます

コードは前回のものを使っています

リストに文字列入れてそのまま出力した結果とOrderBy()でソートした結果

ソート後が不思議な並び順になっていますが、ちゃんとソートしています

答え

リストに入れたのはこんな文字列たち

昔流行った(?)RLOですね1

Unicodeコワイ


  1. 右から左になるやつでファイルの拡張子変えて遊んだやつ

文字列のソート

文字列で昇順ソートしている部分の並べ替えが間違っている、と指摘されてどういうことなのかよく聞いたら漢字部分が"(訓)読み"通りになっていないということらしく「そこは文字コードでソート」と説明したんですが、最近の若い子は並べ替えの時に文字コード順にしないんですかね

と、わけのわからない事を書いてみましたが、プログラミングの勉強でソートは出てくるはずでそこで文字列を相手にやったりもすると思うんですよね

そんなときに

var list = new[] { "青森", "山形", "秋田" };
foreach (var s in list.OrderBy(s => s))
{
    Console.WriteLine(s);
}

この結果が

山形
秋田
青森

こうなってわけがわからなくなったりしないんでしょうか。ちなみに↑はどういう順番で並べ替えるのが正解なんでしょ

文字コード順は見ただけではわからない

ということで当て字なんかまで考慮して日本人になじみのある並べ替えなんてやっていられないので、並べ替えは基本的にシステム(フレームワーク)依存にします。多分文字コード順になるでしょう。そういう仕様にした場合、文字コード順に並べ替えられているか、をチェックする人がいるわけですがこのチェックがなかなか厄介っぽいです

このまえ C# の人のブログ 任意色絵文字? | ++C++; // 未確認飛行 C ブログ を見たのでこのあたりで以下のような cshtml を書いてみます (スクショですんません)

9~13行目で文字列リストを作って、20行目のループでそのまま出力。27行目のループで並べ替えて出力しています。出力はその文字列とデフォルトエンコーディングエンコード(?)したbyte配列です

上記 C# の人のブログにも書いてありますが Windows10では正しく表示されないので、Windows11のEdgeで見た結果がこちら

この結果はそれなりの経験者でも頭をひねるのではないでしょうか

ソート後の黒猫の位置がおかしいですね。 でもその横のデータを見るとおかしくないですね

ということで文字列部分でソートする時は気を付けましょう、というお話だったような気がします

おしまい