質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

ただいまの
回答率

90.04%

C#でJSONデータの型を変換する

解決済

回答 3

投稿 編集

  • 評価
  • クリップ 2
  • VIEW 456

Sanm

score 2

前提・実現したいこと

まず、a.jsonファイルを読み込み、データ内の"dataname"を見る。
b.JSONファイルの"dataname"を参照し、a.jsonファイルの"dataname"と一致したら"type"を見る。
そのtypeによって、a.jsonファイル内の"value"のデータの型を変換し、output.jsonファイルで出力する。
を実装したいです。

該当のソースコード

//a.json
{
    "data": [
        {
            "id": "100_1",
            "name": "tarou",
            "dataname": "AAA",
            "value": 155
        },
        {
            "id": "100_2",
            "name": "hanako",
            "dataname": "BBB",
            "value": 50
        },
        {
            "id": "100_3",
            "name": "manami",
            "dataname": "AAA",
            "value": 120
        }
    ]
}
//b.json
{
    "definition": [
        {
            "dataname": "AAA",
            "type": "string"
        },
        {
            "dataname": "BBB",
            "type": "float"
        },
        {
            "dataname": "CCC",
            "type": "int"
        }
    ]
}

結果は
id:100_1 の value:"155"
id:100_1 の value:50.0
id:100_1 の value:"120" となるはずなので、

//output.json
{
    "data": [
        {
            "id": "100_1",
            "name": "tarou",
            "dataname": "AAA",
            "value": "155"
        },
        {
            "id": "100_2",
            "name": "hanako",
            "dataname": "BBB",
            "value": 50.0
        },
        {
            "id": "100_3",
            "name": "manami",
            "dataname": "AAA",
            "value": "120"
        }
    ]
}

試したこと

色々なサイトを巡り、以下までコーディングができましたが、これ以上手が進まなくなってしまいました…
お目汚しで申し訳ありません。(VisualStudio2019でjson.NET,C#を用いてコーディングしています)

using Newtonsoft.Json;
using System;
using System.IO;
using System.Text;

namespace ConsoleApp_1
{
    class Program
    {
        static void Main(string[] args)
        {
            string filepath = @"C:\Users\User\Desktop\a.json";
            string jsonstring = File.ReadAllText(filepath, Encoding.UTF8);
            Console.WriteLine("読込完了");

            var obj = JsonConvert.DeserializeObject(jsonstring);
            var deserialized = JsonConvert.DeserializeObject<object>(jsonstring);
            Console.WriteLine(deserialized);
            File.WriteAllText(@"C:\Users\User\Desktop\output.json", deserialized.ToString());
            Console.WriteLine("出力完了");
        }
    }
}

皆様のお力添えをよろしくお願いいたします。

失礼しました。編集しました。
そうです。違う型で出力したいです。
ただ、そのやり方が見当つかず苦戦しています。
output.jsonの不備はどこか分かりませんでした。

  • 気になる質問をクリップする

    クリップした質問は、後からいつでもマイページで確認できます。

    またクリップした質問に回答があった際、通知やメールを受け取ることができます。

    クリップを取り消します

  • 良い質問の評価を上げる

    以下のような質問は評価を上げましょう

    • 質問内容が明確
    • 自分も答えを知りたい
    • 質問者以外のユーザにも役立つ

    評価が高い質問は、TOPページの「注目」タブのフィードに表示されやすくなります。

    質問の評価を上げたことを取り消します

  • 評価を下げられる数の上限に達しました

    評価を下げることができません

    • 1日5回まで評価を下げられます
    • 1日に1ユーザに対して2回まで評価を下げられます

    質問の評価を下げる

    teratailでは下記のような質問を「具体的に困っていることがない質問」、「サイトポリシーに違反する質問」と定義し、推奨していません。

    • プログラミングに関係のない質問
    • やってほしいことだけを記載した丸投げの質問
    • 問題・課題が含まれていない質問
    • 意図的に内容が抹消された質問
    • 広告と受け取られるような投稿

    評価が下がると、TOPページの「アクティブ」「注目」タブのフィードに表示されにくくなります。

    質問の評価を下げたことを取り消します

    この機能は開放されていません

    評価を下げる条件を満たしてません

    評価を下げる理由を選択してください

    詳細な説明はこちら

    上記に当てはまらず、質問内容が明確になっていない質問には「情報の追加・修正依頼」機能からコメントをしてください。

    質問の評価を下げる機能の利用条件

    この機能を利用するためには、以下の事項を行う必要があります。

質問への追記・修正、ベストアンサー選択の依頼

  • YAmaGNZ

    2019/08/08 07:51 編集

    output.jsonはjson2csharpでコード化出来ましたよ。
    というか、ajsonのvalueをobjectとしただけではないでしょうか?

    キャンセル

  • Zuishin

    2019/08/08 08:07

    「この関数を使うよ」というほどのものではなく、ループ内で swich や if を使うだけでできますね。
    「これ以上手が進まなくなりました」のコード内には Json のデコード以外何も書かれていないので、ほんとうにこれしかできないのであれば、何も作れないと思います。
    完成を目指すなら場当たり的に勘でコピペするのではなく、まず文法を確認してください。ループも分岐も使えずプログラミングしようというのは無謀すぎます。

    キャンセル

  • SurferOnWww

    2019/08/08 08:35

    > output.jsonはjson2csharpでコード化出来ましたよ。

    やってみました。value は object 型になりますね。「output.json は JSON として不正」とまでは言えなかったようです。

    失礼しました>質問者さん

    でも、それからシリアライズした JSON 文字列をデシリアライズした時に、デシリアライズする処理系で value の型が判定できるのか悩ましそうです。やっぱり全面的に見直した方がよさそうな気はします。

    キャンセル

回答 3

checkベストアンサー

+1

コード書いてみました。
"string" → typeof(string)
"float" → typeof(float)
"int" → typeof(int)
の変換には Dictionary を使いましたが、ここがもう少しスマートにできるとカッコいいかなと思います。

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Text;
using Newtonsoft.Json;

namespace ConsoleApp8
{
    class Program
    {
        static void Main(string[] args) {
            var typeDic = new Dictionary<string, Type>();
            typeDic.Add("string", typeof(string));
            typeDic.Add("float", typeof(float));
            typeDic.Add("int", typeof(int));

            var rootA = GetJson<RootData>("a.json");
            var rootB = GetJson<RootDefinition>("b.json");
            foreach (var itemA in rootA.data) {
                var itemB = rootB.definition.Find(data => data.dataname == itemA.dataname);
                if (itemB != null && itemA.value != null) {
                    var cnv = TypeDescriptor.GetConverter(itemA.value.GetType());
                    if (cnv != null) {
                        itemA.value = cnv.ConvertTo(itemA.value, typeDic[itemB.type]);
                    }
                }
            }
            var outputString = JsonConvert.SerializeObject(rootA, Formatting.Indented);
            File.WriteAllText("output.json", outputString, Encoding.UTF8);
            Console.WriteLine(outputString);
            Console.ReadKey();
        }

        static T GetJson<T>(string filepath) {
            string jsonstring = File.ReadAllText(filepath, Encoding.UTF8);
            return JsonConvert.DeserializeObject<T>(jsonstring);
        }

    }

    public class Data
    {
        public string id { get; set; }
        public string name { get; set; }
        public string dataname { get; set; }
        public object value { get; set; }
    }

    public class Definition
    {
        public string dataname { get; set; }
        public string type { get; set; }
    }

    public class RootData
    {
        public List<Data> data;
    }

    public class RootDefinition
    {
        public List<Definition> definition { get; set; }
    }
}

投稿

編集

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/08/08 15:18 編集

    ありがとうございます。
    また、挙動の確認が取れました。
    stringからstringへ変換する場合、エラーとなってしまいました。こちらに関して解決に至らない場合は後日別で質問しようと思います。

    キャンセル

  • 2019/08/10 08:08 編集

    変ですね。
    元の型が string なら TypeDescriptor.GetConverter は StringConverter を返すはずで、ConvertTo(value, typeof(string)) を実行してもエラーにはならないはずです。
    ちょっとやってみましたがエラーにはなりませんでした。
    新しい質問が上がっていないようなので解決したのであれば良いですが・・・

    キャンセル

  • 2019/08/10 23:45

    KOZ6.0様
    気にかけていただきありがとうござます。
    結果から申しますと、当方のオペレーションミスでした。
    stringからstringへ正常に変換されることの確認ができました。
    大変失礼いたしました。

    キャンセル

+1

  1. a.jsonをデシリアライズする
  2. b.jsonをデシリアライズする
  3. a.jsonの項目数分以下の処理を続ける
    3-1. b.jsonの項目からdatanameが同じものを見つける
    3-2. 見つかった場合、typeによってa.jsonのvalueをキャストする
  4. 変換の終わったa.jsonをoutput.jsonとしてシリアライズして書き込む

このような流れになるかと思います。
1.や2.が出来ているかは、その内容を一覧で表示してみるとよろしいかと思います。
3.についてはC#の基本的な構文で実現できるはずです。

また、1.2.4.については検索すればいくらでも例が出てくると思います。
読み込むべき型を定義するのが分かりやすくなるのではないかと思います。
JSONの型定義であれば、json2csharpみたいな便利なサイトがいくつかあります。

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/08/08 14:12 編集

    1,2は完了、3は作業中です。
    コードを載せることができず申し訳ありません。

    表現が良くなかったです。a,b両ファイルRead後、JObject使用しますか?という意味でした。

    キャンセル

  • 2019/08/08 14:20

    JObjectを使用してもいいでしょうが、KOZ6.0さんのようにデータを格納するクラスを定義したほうが、コードも分かりやすくなるかと思います。

    キャンセル

  • 2019/08/08 14:27

    KOZ6.0様のコードを見て当方もそう思いました…

    YAmaGNZ様、色々とご教授いただきありがとうございます。

    キャンセル

+1

上の質問に対する私のコメントで、

デシリアライズする処理系で value の型が判定できるのか悩ましそうです。やっぱり全面的に見直した方がよさそうな気はします。

と書きました。

その対応ための代案ですが・・・

output.json を何かの処理系に渡しで、最終的にそこでデシリアライズして使うのだと思いますが、であれば、output.json は a.json と b.json をマージするような形、即ち以下のようにするという案は NG ですか?

{
    "data": [
        {
            "id": "100_1",
            "name": "tarou",
            "dataname": "AAA",
            "value": 155,
            "type": "string"
        },
        {
            "id": "100_2",
            "name": "hanako",
            "dataname": "BBB",
            "value": 50,
            "type": "float"
        },
        {
            "id": "100_3",
            "name": "manami",
            "dataname": "AAA",
            "value": 120,
            "type": "string"
        }
    ]
}

投稿

  • 回答の評価を上げる

    以下のような回答は評価を上げましょう

    • 正しい回答
    • わかりやすい回答
    • ためになる回答

    評価が高い回答ほどページの上位に表示されます。

  • 回答の評価を下げる

    下記のような回答は推奨されていません。

    • 間違っている回答
    • 質問の回答になっていない投稿
    • スパムや攻撃的な表現を用いた投稿

    評価を下げる際はその理由を明確に伝え、適切な回答に修正してもらいましょう。

  • 2019/08/08 10:56

    質問からは読めませんが、コメントに「javascript で別の方が書いたコードをC#化している」とありますから、既存の何かがあると考えられると思いますが・・・

    キャンセル

  • 2019/08/08 11:06

    想像で話をしても何ですので、質問者さんからの回答を待ちたいと思います。

    キャンセル

  • 2019/08/08 14:16

    皆さまらご検討していただきありがとうございます。
    こちらはC#での処理方法以外の部分は決められています。
    打診しましたが現行のフォーマットを崩すのはあまり推奨しないとの事でした。

    キャンセル

15分調べてもわからないことは、teratailで質問しよう!

  • ただいまの回答率 90.04%
  • 質問をまとめることで、思考を整理して素早く解決
  • テンプレート機能で、簡単に質問をまとめられる

同じタグがついた質問を見る