将JSON字符串解析为List<string>

11
string json = "{\"People\":[{\"FirstName\":\"Hans\",\"LastName\":\"Olo\"}
                            {\"FirstName\":\"Jimmy\",\"LastName\":\"Crackedcorn\"}]}";

var obj = JObject.Parse(json);

List<string> first;
List<string> last;

foreach (var child in obj["People"].Children())
{
    var name = child.First()["countryName"].ToString();
    var two = child.First()["countryCode"].ToString();
    var three = child.First()["isoAlpha3"].ToString();

    countries.Add(name);
    twoCharCodes.Add(two);
    threeCharCodes.Add(three);

    Console.Write("Name:\t\t{0}\n2CharCode:\t{1}\n3CharCode:\t{2}\n\n", name, two, three);
}

我希望找到一种方法,将每个FirstName值添加到第一个列表中,并将LastName值添加到最后一个列表中。如何最好地实现这一点?
以上代码在以下位置出现错误:
var name = child.First()["countryName"].ToString();

出现如下错误:

 Cannot access child value on Newtonsoft.Json.Linq.JProperty

有什么建议吗?

6
我是否遗漏了什么?你从哪里得到了countryName和其他信息?我只看到People下有FirstNameLastName。请帮忙确认一下。 - Jonesopolis
对象之间缺少逗号。 - NASSER
汉斯·奥洛 - 有人在看星际之门吗? - Jesse C. Slicer
5个回答

19

看起来这是一种不太好的做法(创建两个相关联的列表),但我假设你有你的原因。

我会将JSON字符串解析为强类型对象,然后使用几个LINQ查询来获取这两个列表。

void Main()
{
    string json = "{\"People\":[{\"FirstName\":\"Hans\",\"LastName\":\"Olo\"},{\"FirstName\":\"Jimmy\",\"LastName\":\"Crackedcorn\"}]}";

    var result = JsonConvert.DeserializeObject<RootObject>(json);

    var firstNames = result.People.Select (p => p.FirstName).ToList();
    var lastNames = result.People.Select (p => p.LastName).ToList();
}

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

public class RootObject
{
    public List<Person> People { get; set; }
}

太棒了,这个运行得很好!非常感谢。我正在创建两个列表以最终将数值写入数据库。我想用一个简单的for循环就可以轻松实现这一点。你有其他建议吗? - ChangeJar

10

由于您正在使用JSON.NET,个人建议使用序列化以便为对象提供Intellisense支持。您需要一个表示JSON结构的类。您可以手动构建此类,也可以使用像json2csharp这样的工具为您生成:

例如:

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

public class RootObject
{
    public List<Person> People { get; set; }
}

接下来,您可以简单地调用JsonConvert的方法将JSON反序列化为对象:

RootObject instance = JsonConvert.Deserialize<RootObject>(json);

那么你就拥有了智能提示功能(Intellisense):

var firstName = instance.People[0].FirstName;
var lastName = instance.People[0].LastName;

你的意思基本上和我在你之前两分钟发布的答案一样吗? :-) - Craig W.
2
当然。我还在打字,就看到你发帖了。我确实给了你用来生成类的网站以及相应的信用;) - Kenneth K.
@KennethK.:使用此代码 RootObject instance = JsonConvert.DeserializeObject<RootObject>(json); 我得到了 Null。我的 json 字符串是 {\r\n \"People\":[\r\n {\r\n "{\r\n \"People\": [\r\n {\r\n \"FirstName\": \"Hans\",\r\n \"LastName\": \"Olo\"\r\n },\r\n {\r\n \"FirstName\": \"Jimmy\",\r\n \"LastName\": \"Crackedcorn\"\r\n },\r\n {\r\n \"FirstName\": \"Tim\",\r\n \"LastName\": \"John\"\r\n }\r\n ]\r\n} \r\n\r\n" - venkat
@venkat,你的JSON与此问题代码所代表的结构不匹配。这可能应该是一个新问题。 - Kenneth K.

1

我在我的项目中使用这个JSON辅助类。一年前我在网上找到了它,但是丢失了源URL。所以我直接从我的项目中复制粘贴它:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Runtime.Serialization.Json;
using System.IO;
using System.Text;
/// <summary>
/// JSON Serialization and Deserialization Assistant Class
/// </summary>
public class JsonHelper
{
    /// <summary>
    /// JSON Serialization
    /// </summary>
    public static string JsonSerializer<T> (T t)
    {
        DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(T));
        MemoryStream ms = new MemoryStream();
        ser.WriteObject(ms, t);
        string jsonString = Encoding.UTF8.GetString(ms.ToArray());
        ms.Close();
        return jsonString;
    }
    /// <summary>
    /// JSON Deserialization
    /// </summary>
    public static T JsonDeserialize<T> (string jsonString)
    {
        DataContractJsonSerializer ser = new DataContractJsonSerializer(typeof(T));
        MemoryStream ms = new MemoryStream(Encoding.UTF8.GetBytes(jsonString));
        T obj = (T)ser.ReadObject(ms);
        return obj;
    }
}

你可以像这样使用它:按照Craig W.的建议创建类。然后像这样反序列化。
RootObject root = JSONHelper.JsonDeserialize<RootObject>(json);

我的理解是,DataContractJsonSerializer 比 JSON.NET 的序列化器慢得多,这也是 ASP.NET 团队将默认的 JSON 序列化器切换到 JSON.NET 的原因。速度可能不是问题,但未来可能需要考虑。 - Kenneth K.
1
@KennethK。是的,这取决于项目场景。就我个人而言,我从未在这段代码中遇到过性能问题。这只是OP的另一个选择。其余的取决于他的项目需求。 - Aishwarya Shiva
优秀的解决方案!但是对于新用户来说,应该提到要序列化的类必须用属性[DataContract]进行注释,并且所有要序列化的属性都要用属性[DataMember]进行注释,而您不想序列化的属性可能需要使用[IgnoreDataMember]属性。 - Noor ul Ain
@Kenneth K. NewtonSoft的dll大约有700 kb。在我的情况下,系统内存是一个问题。此外,Newtonsoft.json(或JSon.Net)在目标系统上抛出异常,而这段代码嵌入到我的项目中作为常规类。但是您的评论非常重要,可以让用户意识到性能与内存之间的妥协。 - Noor ul Ain

1

作为对已接受答案的补充,我想将此作为评论发布,但可能会有些不清楚。因此,仅作为附注:

如果您不需要对象本身,并且希望项目中没有进一步未使用的类,则可以使用以下方式解析:

var list = JObject.Parse(json)["People"].Select(el => new { FirstName = (string)el["FirstName"], LastName = (string)el["LastName"] }).ToList();

var firstNames = list.Select(p => p.FirstName).ToList();
var lastNames = list.Select(p => p.LastName).ToList();

即使使用强类型的人类,您仍然可以通过创建一个列表并使用 JObject.Parse(json)["People"].ToObject<List<Person>>() 跳过根对象。 当然,如果您需要重复使用这些对象,最好从一开始就创建它们。只是想指出另一种选择 ;)

0

试试这个:

using System;
using Newtonsoft.Json;
using System.Collections.Generic;
public class Program
{
    public static void Main()
    {
        List<Man> Men = new List<Man>();

        Man m1 = new Man();
        m1.Number = "+1-9169168158";
        m1.Message = "Hello Bob from 1";
        m1.UniqueCode = "0123";
        m1.State = 0;

        Man m2 = new Man();
        m2.Number = "+1-9296146182";
        m2.Message = "Hello Bob from 2";
        m2.UniqueCode = "0125";
        m2.State = 0;

        Men.AddRange(new Man[] { m1, m2 });

        string result = JsonConvert.SerializeObject(Men);
        Console.WriteLine(result);  

        List<Man> NewMen = JsonConvert.DeserializeObject<List<Man>>(result);
        foreach(Man m in NewMen) Console.WriteLine(m.Message);
    }
}
public class Man
{
    public string Number{get;set;}
    public string Message {get;set;}
    public string UniqueCode {get;set;}
    public int State {get;set;}
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接