从JSON字符串中获取动态键的值

时间:2018-01-23 07:18:59

标签: c# json json.net

我有这个json字符串,我希望获得每条记录的第4行(iValue, sValue)。 我的问题是每个记录的密钥都不同(基于值的数据类型)。

有没有办法在C#上做到这一点?

以下是一个例子:

{ "data": [
        {
          "pKey": "0",
          "Entity": "tableName",
          "Attribute": "CID",
          "iValue": "13"
        },
        {
          "pKey": "0",
          "Entity": "tableName",
          "Attribute": "username",
          "sValue": "test_user1"
        }] }

6 个答案:

答案 0 :(得分:1)

这是一个很大的实现,你必须为每个iValuefValue等实现这个,但是,它加快了实现和使用。首先,这是用法:

string rawJson = "{\"data\":[{\"pKey\":\"0\",\"Entity\":\"tableName\",\"Attribute\":\"CID\",\"iValue\":\"13\"},{\"pKey\":\"0\",\"Entity\":\"tableName\",\"Attribute\":\"username\",\"sValue\":\"test_user1\"}]}";

var values = JsonConvert.DeserializeObject<TakeData>(rawJson).Data.Select(v => v.PureData);

现在values包含列表。以下是访问每个的用法:

foreach (var val in values)
{
    if (val is IntData i)
    {
        int myInt = i.iValue;
        // use the rest of the properties
    }
    else if (val is StrData s)
    {
        string myStr = s.sValue;
        // use the rest of the properties
    }
}

以下是实施:

class TakeData
{
    public List<TakeItAll> Data { get; set; }
}

class TakeItAll
{

    public int pKey { get; set; }
    public string Entity { get; set; }
    public string Attribute { get; set; }

    private int _iValue;
    public int iValue
    {
        get => _iValue;
        set
        {
            _iValue = value;
            PureData = new IntData { pKey = pKey, Entity = Entity, Attribute = Attribute, iValue = iValue };
        }
    }

    private string _sValue;
    public string sValue
    {
        get => _sValue;
        set
        {
            _sValue = value;
            PureData = new StrData { pKey = pKey, Entity = Entity, Attribute = Attribute, sValue = sValue };
        }
    }

    public IPureData PureData { get; private set; }

}

interface IPureData
{
    int pKey { get; set; }
    string Entity { get; set; }
    string Attribute { get; set; }
}

class IntData : IPureData
{
    public int pKey { get; set; }
    public string Entity { get; set; }
    public string Attribute { get; set; }
    public int iValue { get; set; }
}

class StrData : IPureData
{
    public int pKey { get; set; }
    public string Entity { get; set; }
    public string Attribute { get; set; }
    public string sValue { get; set; }
}

当然你也可以使用一些替代品。例如在TakeItAll中使用枚举来跟踪数据类型(或类型变量)而不是那么多类。这样,但values对象的大小会更大。

class TakeItAll
{

    public int pKey { get; set; }
    public string Entity { get; set; }
    public string Attribute { get; set; }

    private int _iValue;
    public int iValue
    {
        get => _iValue;
        set
        {
            _iValue = value;
            ValType = typeof(string);
        }
    }

    private string _sValue;
    public string sValue
    {
        get => _sValue;
        set
        {
            _sValue = value;
            ValType = typeof(int);
        }
    }

    public Type ValType { get; private set; }

}

答案 1 :(得分:0)

我会将其反序列化为支持两种类型属性的对象,然后通过代码尝试解析整数或字符串(如果整数失败)。

如果carousel.autoscroll = -1.0 [carousel scrollToItemAtIndex:0 animated:YES]; 值为您提供了查找哪一个的线索,您也可以使用它来防止每次都尝试解析整数。

我不会依赖该物业作为第四个&#34;属性每次,因为我假设这将是外部数据,您可能无法控制这些属性是否每次(现在和将来)以完全相同的顺序出现。

答案 2 :(得分:0)

  1. 如果您不知道数据类型,那么您可以使用一个对象来处理它。
  2. 将JSON字符串反序列化为具体类是个好主意,以避免字符串操作错误。

    public class Datum
    {
        public object pKey { get; set; }
        public string Entity { get; set; }
        public string Attribute { get; set; }
        public string iValue { get; set; }
        public string sValue { get; set; }
    }
    
    public class DataCollection
    {
        public List<Datum> data { get; set; }
    }
    
    public void Test()
    {
        var str = "{\"data\":[{\"pKey\":\"0\",\"Entity\":\"tableName\",\"Attribute\":\"CID\",\"iValue\":\"13\"},{\"pKey\":\"0\",\"Entity\":\"tableName\",\"Attribute\":\"username\",\"sValue\":\"test_user1\"}]}";
        var list = JsonConvert.DeserializeObject<DataCollection>(str);
        var keys = list.data.Select(x => x.pKey).ToList();
    }
    

答案 3 :(得分:0)

另一种选择是反序列化为dynamic并检查:

var json = "{\"data\":[{\"pKey\":\"0\",\"Entity\":\"tableName\",\"Attribute\":\"CID\",\"iValue\":\"13\"},{\"pKey\":\"0\",\"Entity\":\"tableName\",\"Attribute\":\"username\",\"sValue\":\"test_user1\"}]}";

var result = JsonConvert.DeserializeAnonymousType<dynamic>(json, null);

if (result.data != null)
{
    for (var i = 0; i < result.data.Count; i++)
    {
        if (result.data[i]["iValue"] != null)
            // Parse iValue
        if (result.data[i]["sValue"] != null)
            // Parse sValue

    }

}

答案 4 :(得分:0)

您可以在ExpandoObject中加载Json

var expConverter = new ExpandoObjectConverter();
dynamic objList = JsonConvert.DeserializeObject<List<ExpandoObject>>(json, expConverter);

JSON array to ExpandoObject via JSON.NET

然后,当您将其作为List<ExpandoObject>加载后,您可以将其作为字典进行迭代。

    foreach(var obj in objList) 
    {
//convert the object to a Dictionary and select the 4th element.
      var yourresult = (obj as IDictionary<string, object>).ElementAt(3);
    }

答案 5 :(得分:0)

我的两分钱:

将数组的每个对象作为KeyValuePair

var json = "your json here";

var root = JsonConvert.DeserializeObject<Root>(json);

foreach (var element in root.Data)
{
    //===================================================> Here using object because your value type change. You can change it to string if your value is always wrapped in a string (like "13")
    var keyValuePair = element.ToObject<Dictionary<string, object>>();

    //here, for each object of the 'data' array, you can check if the desidered property exists
    if (keyValuePair.ContainsKey("iValue"))
    {
        var propertyValue = keyValuePair["iValue"];
    }
    else if (keyValuePair.ContainsKey("sValue"))
    {
        var propertyValue = keyValuePair["sValue"];
    }

    // Or you can check the property name in the desidered position
    if (keyValuePair.Keys.ElementAt(3) == "iValue")
    {
        var propertyValue = keyValuePair["iValue"];
    }
    else if (keyValuePair.Keys.ElementAt(3) == "sValue")
    {
        var propertyValue = keyValuePair["sValue"];
    }
}

Root

的位置
class Root
{
    [JsonProperty("data")]
    public List<JObject> Data { get; set; }
}

使用此解决方案,您始终可以知道指定了哪个属性(iValuesValue)。相反,如果您使用具有两个属性名称的模型类,则在值为null时您将不知道指定了哪个属性(除非您使用其他属性/类和自定义{{1 }})。

修改

正如Azure Cosmos DB Node.js SDK for SQL API提醒我的那样,JsonConverter类实现了JObject。所以,在IDictionary<string, JToken>内你可以使用:

foreach

当然,您可以优化此代码并检查空值。