4

SEDOL と ADP 値のリストを取得しようとしています。以下は私のjsonテキストです:

{
    "DataFeed" : {
        "@FeedName" : "AdminData",
        "Issuer" : [{
                "id" : "1528",
                "name" : "ZYZ.A a Test Company",
                "clientCode" : "ZYZ.A",
                "securities" : {
                    "Security" : {
                        "id" : "1537",
                        "sedol" : "SEDOL111",
                        "coverage" : {
                            "Coverage" : [{
                                    "analyst" : {
                                        "@id" : "164",
                                        "@clientCode" : "SJ",
                                        "@firstName" : "Steve",
                                        "@lastName" : "Jobs",
                                        "@rank" : "1"
                                    }
                                }, {
                                    "analyst" : {
                                        "@id" : "261",
                                        "@clientCode" : "BG",
                                        "@firstName" : "Bill",
                                        "@lastName" : "Gates",
                                        "@rank" : "2"
                                    }
                                }
                            ]
                        },
                        "customFields" : {
                            "customField" : [{
                                    "@name" : "ADP Security Code",
                                    "@type" : "Textbox",
                                    "values" : {
                                        "value" : "ADPSC1111"
                                    }
                                }, {
                                    "@name" : "Top 10 - Select one or many",
                                    "@type" : "Dropdown, multiple choice",
                                    "values" : {
                                        "value" : ["Large Cap", "Cdn Small Cap", "Income"]
                                    }
                                }
                            ]
                        }
                    }
                }
            }, {
                "id" : "1519",
                "name" : "ZVV Test",
                "clientCode" : "ZVV=US",
                "securities" : {
                    "Security" : [{
                            "id" : "1522",
                            "sedol" : "SEDOL112",
                            "coverage" : {
                                "Coverage" : {
                                    "analyst" : {
                                        "@id" : "79",
                                        "@clientCode" : "MJ",
                                        "@firstName" : "Michael",
                                        "@lastName" : "Jordan",
                                        "@rank" : "1"
                                    }
                                }
                            },
                            "customFields" : {
                                "customField" : [{
                                        "@name" : "ADP Security Code",
                                        "@type" : "Textbox",
                                        "values" : {
                                            "value" : "ADPS1133"
                                        }
                                    }, {
                                        "@name" : "Top 10 - Select one or many",
                                        "@type" : "Dropdown, multiple choice",
                                        "values" : {
                                            "value" : ["Large Cap", "Cdn Small Cap", "Income"]
                                        }
                                    }
                                ]
                            }
                        }, {
                            "id" : "1542",
                            "sedol" : "SEDOL112",
                            "customFields" : {
                                "customField" : [{
                                        "@name" : "ADP Security Code",
                                        "@type" : "Textbox",
                                        "values" : {
                                            "value" : "ADPS1133"
                                        }
                                    }, {
                                        "@name" : "Top 10 - Select one or many",
                                        "@type" : "Dropdown, multiple choice",
                                        "values" : {
                                            "value" : ["Large Cap", "Cdn Small Cap", "Income"]
                                        }
                                    }
                                ]
                            }
                        }
                    ]
                }
            }
        ]
    }
}

これが私がこれまでに持っているコードです:

var compInfo = feed["DataFeed"]["Issuer"]
.Select(p => new {  
    Id = p["id"],
    CompName = p["name"],
    SEDOL = p["securities"]["Security"].OfType<JArray>() ? 
        p["securities"]["Security"][0]["sedol"] : 
        p["securities"]["Security"]["sedol"]
    ADP = p["securities"]["Security"].OfType<JArray>() ? 
        p["securities"]["Security"][0]["customFields"]["customField"][0]["values"]["value"] : 
        p["securities"]["Security"]["customFields"]["customField"][0]["values"]["value"]
});

私が得るエラーは次のとおりです。

無効なキー値「sedol」で JArray 値にアクセスしました。Int32 配列インデックスが必要です

私はこれを理解することに本当に近づいていると思います。コードを修正するにはどうすればよいですか? SEDOLとを取得する代替手段がある場合は、ADP valueお知らせください。

[UPDATE1]動的 ExpandoObject の使用を開始しました。これまでに使用したコードは次のとおりです。

dynamic obj = JsonConvert.DeserializeObject<ExpandoObject>(json, new ExpandoObjectConverter());
foreach (dynamic element in obj)
{
    Console.WriteLine(element.DataFeed.Issuer[0].id);
    Console.WriteLine(element.DataFeed.Issuer[0].securities.Security.sedol);
    Console.ReadLine();
}

しかし、私は今、エラーが発生しています'ExpandoObject' does not contain a definition for 'DataFeed' and no extension method 'DataFeed' accepting a first argument of type 'ExpandoObject' could be found注:この json テキストの形式が正しくないことは理解しています。1 つのインスタンスには配列があり、もう 1 つはオブジェクトです。両方のインスタンスを処理できるように、コードを機敏にする必要があります。

[UPDATE2]これまで私のコードを手伝ってくれた @dbc に感謝します。現在の環境に厳密に一致するように、上記の json テキストを更新しました。SEDOL と ADP コードを取得できるようになりました。ただし、最初のアナリストを取得しようとすると、コードはオブジェクトに対してのみ機能し、配列の一部であるアナリストに対して null を生成します。これが私の現在のコードです:

var compInfo = from issuer in feed.SelectTokens("DataFeed.Issuer").SelectMany(i => i.ObjectsOrSelf())
           let security = issuer.SelectTokens("securities.Security").SelectMany(s => s.ObjectsOrSelf()).FirstOrDefault()
           where security != null
           select new
           {
               Id = (string)issuer["id"], // Change to (string)issuer["id"] if id is not necessarily numeric.
               CompName = (string)issuer["name"],
               SEDOL = (string)security["sedol"],
               ADP = security["customFields"]
                .DescendantsAndSelf()
                .OfType<JObject>()
                .Where(o => (string)o["@name"] == "ADP Security Code")
                .Select(o => (string)o.SelectToken("values.value"))
                .FirstOrDefault(),
              Analyst = security["coverage"]
                .DescendantsAndSelf()
                .OfType<JObject>()
                .Select(jo => (string)jo.SelectToken("Coverage.analyst.@lastName"))
                .FirstOrDefault(),
           };

常に最初のアナリストを選択するには、何を変更する必要がありますか?

4

3 に答える 3

7

すべての SEDOL と ADP の値に、それぞれに関連付けられた発行者 ID と CompName が必要な場合は、次のようにします。

var compInfo = from issuer in feed.SelectTokens("DataFeed.Issuer").SelectMany(i => i.ObjectsOrSelf())
               from security in issuer.SelectTokens("securities.Security").SelectMany(s => s.ObjectsOrSelf())
               select new
               {
                   Id = (long)issuer["id"], // Change to (string)issuer["id"] if id is not necessarily numeric.
                   CompName = (string)issuer["name"],
                   SEDOL = (string)security["sedol"],
                   ADP = security["customFields"]
                    .DescendantsAndSelf()
                    .OfType<JObject>()
                    .Where(o => (string)o["@name"] == "ADP Security Code")
                    .Select(o => (string)o.SelectToken("values.value"))
                    .FirstOrDefault(),
               };

拡張メソッドの使用:

public static class JsonExtensions
{
    public static IEnumerable<JToken> DescendantsAndSelf(this JToken node)
    {
        if (node == null)
            return Enumerable.Empty<JToken>();
        var container = node as JContainer;
        if (container != null)
            return container.DescendantsAndSelf();
        else
            return new[] { node };
    }

    public static IEnumerable<JObject> ObjectsOrSelf(this JToken root)
    {
        if (root is JObject)
            yield return (JObject)root;
        else if (root is JContainer)
            foreach (var item in ((JContainer)root).Children())
                foreach (var child in item.ObjectsOrSelf())
                    yield return child;
        else
            yield break;
    }
}

それで

Console.WriteLine(JsonConvert.SerializeObject(compInfo, Formatting.Indented));

プロデュース:

[
  {
    "Id": 1528,
    "CompName": "ZYZ.A a Test Company",
    "SEDOL": "SEDOL111",
    "ADP": "ADPSC1111"
  },
  {
    "Id": 1519,
    "CompName": "ZVV Test",
    "SEDOL": "SEDOL112",
    "ADP": "ADPS1133"
  },
  {
    "Id": 1519,
    "CompName": "ZVV Test",
    "SEDOL": "SEDOL112",
    "ADP": "ADPS1133"
  }
]

ただし、これまでに作成したクエリでは、発行者ごとに最初のSEDOL と ADPのみを返そうとしているようです。それが本当に必要な場合は、次のようにします。

var compInfo = from issuer in feed.SelectTokens("DataFeed.Issuer").SelectMany(i => i.ObjectsOrSelf())
               let security = issuer.SelectTokens("securities.Security").SelectMany(s => s.ObjectsOrSelf()).FirstOrDefault()
               where security != null
               select new
               {
                   Id = (long)issuer["id"], // Change to (string)issuer["id"] if id is not necessarily numeric.
                   CompName = (string)issuer["name"],
                   SEDOL = (string)security["sedol"],
                   ADP = security["customFields"]
                    .DescendantsAndSelf()
                    .OfType<JObject>()
                    .Where(o => (string)o["@name"] == "ADP Security Code")
                    .Select(o => (string)o.SelectToken("values.value"))
                    .FirstOrDefault(),
               };

結果は次のとおりです。

[
  {
    "Id": 1528,
    "CompName": "ZYZ.A a Test Company",
    "SEDOL": "SEDOL111",
    "ADP": "ADPSC1111"
  },
  {
    "Id": 1519,
    "CompName": "ZVV Test",
    "SEDOL": "SEDOL112",
    "ADP": "ADPS1133"
  }
]

余談ですが、あなたの JSON はかなりポリモーフィック (プロパティはオブジェクトの配列である場合もあれば、単なるオブジェクトである場合もあります) であるため、クラス階層への逆シリアル化ExpandoObjectは簡単ではないと思います。

アップデート

更新された JSON を指定するSelectTokens()と、JSONPath 再帰検索演算子..を使用して、最初のアナリストの姓を見つけることができます。再帰検索演算子は、アナリストが配列に含まれているかどうかという事実を処理します。

var compInfo = from issuer in feed.SelectTokens("DataFeed.Issuer").SelectMany(i => i.ObjectsOrSelf())
               let security = issuer.SelectTokens("securities.Security").SelectMany(s => s.ObjectsOrSelf()).FirstOrDefault()
               where security != null
               select new
               {
                   Id = (string)issuer["id"], // Change to (string)issuer["id"] if id is not necessarily numeric.
                   CompName = (string)issuer["name"],
                   SEDOL = (string)security["sedol"],
                   ADP = (string)security["customFields"]
                    .DescendantsAndSelf()
                    .OfType<JObject>()
                    .Where(o => (string)o["@name"] == "ADP Security Code")
                    .Select(o => o.SelectToken("values.value"))
                    .FirstOrDefault(),
                   Analyst = (string)security.SelectTokens("coverage.Coverage..analyst.@lastName").FirstOrDefault(),
               };
于 2016-04-15T17:30:28.580 に答える
0

newtonsoft.json の使用

dynamic obj = JsonConvert.DeserializeObject<ExpandoObject>(json);

目の前にアイデアがありませんが、値は次のとおりです。

obj.DataFeed.Issuer[0].securities.Security.sedol
于 2016-04-13T17:40:25.673 に答える