使用 C# 反序列化 JSON

Posted

技术标签:

【中文标题】使用 C# 反序列化 JSON【英文标题】:Deserializing JSON using C# 【发布时间】:2011-05-30 02:32:07 【问题描述】:

在尝试在 C# 中反序列化 JSON 时发现获取信息的一些困难。

我有来自 Google 自定义搜索的结果以 JSON 格式返回。我只想检查我的步骤并建立尝试反序列化它的顺序。是这样吗?

    我需要创建类来匹配 JSON 格式。有点像一个 创建架构文件。 使用javascriptSerializer() 类和 deserialize方法提取 相关位。

我想我会遇到的一个问题是我不需要返回所有数据,而只需要 html 链接。我怎样才能做到这一点?

更新

我已使用以下 JSON sn-p 和 C# 代码更新了我的问题。我想将字符串“链接”输出到控制台,但它似乎不起作用。我认为我错误地定义了我的课程?

来自 Google 自定义搜索的 JSON

handleResponse(
 "kind": "customsearch#search",
 "url": 
  "type": "application/json",
  "template": "https://www.googleapis.com/customsearch/v1?q\u003dsearchTerms&num\u003dcount?&start\u003dstartIndex?&hr\u003dlanguage?&safe\u003dsafe?&cx\u003dcx?&cref\u003dcref?&sort\u003dsort?&alt\u003djson"
 ,
 "queries": 
  "nextPage": [
   
    "title": "Google Custom Search - lectures",
    "totalResults": 9590000,
    "searchTerms": "lectures",
    "count": 1,
    "startIndex": 2,
    "inputEncoding": "utf8",
    "outputEncoding": "utf8",
    "cx": "017576662512468239146:omuauf_lfve"
   
  ],
  "request": [
   
    "title": "Google Custom Search - lectures",
    "totalResults": 9590000,
    "searchTerms": "lectures",
    "count": 1,
    "startIndex": 1,
    "inputEncoding": "utf8",
    "outputEncoding": "utf8",
    "cx": "017576662512468239146:omuauf_lfve"
   
  ]
 ,
 "context": 
  "title": "Curriculum",
  "facets": [
   [
    
     "label": "lectures",
     "anchor": "Lectures"
    
   ],
   [
    
     "label": "assignments",
     "anchor": "Assignments"
    
   ],
   [
    
     "label": "reference",
     "anchor": "Reference"
    
   ]
  ]
 ,
 "items": [
  
   "kind": "customsearch#result",
   "title": "EE364a: Lecture Videos",
   "htmlTitle": "EE364a: \u003cb\u003eLecture\u003c/b\u003e Videos",
   "link": "http://www.stanford.edu/class/ee364a/videos.html",
   "displayLink": "www.stanford.edu",
   "snippet": "Apr 7, 2010 ... Course materials. Lecture slides · Lecture videos (2008) · Review sessions.   Assignments. Homework · Reading. Exams. Final exam ...",
   "htmlSnippet": "Apr 7, 2010 \u003cb\u003e...\u003c/b\u003e Course materials. \u003cb\u003eLecture\u003c/b\u003e slides · \u003cb\u003eLecture\u003c/b\u003e videos (2008) · Review sessions. \u003cbr\u003e  Assignments. Homework · Reading. Exams. Final exam \u003cb\u003e...\u003c/b\u003e",
   "cacheid": "TxVqFzFZLOsJ"
  
 ]

);

C# 代码段

public class GoogleSearchResults

    public string link  get; set; 



public class Program

    static void Main(string[] args)
    
        //input search term
        Console.WriteLine("What is your search query?:");
        string searchTerm = Console.ReadLine();

        //concantenate the strings using + symbol to make it URL friendly for google
        string searchTermFormat = searchTerm.Replace(" ", "+");

        //create a new instance of Webclient and use DownloadString method from the Webclient class to extract download html
        WebClient client = new WebClient();
        string Json = client.DownloadString("https://www.googleapis.com/customsearch/v1?key=My Key&cx=My CX&q=" + searchTermFormat);

        //create a new instance of JavaScriptSerializer and deserialise the desired content
        JavaScriptSerializer js = new JavaScriptSerializer();
        GoogleSearchResults results = js.Deserialize<GoogleSearchResults>(Json);

        Console.WriteLine(results);
        //Console.WriteLine(htmlDoc);
        Console.ReadLine();
    

谢谢

【问题讨论】:

您可以尝试的一件事是将 JSON 反序列化为类型对象 - serializer.Deserialize(jsonContent, typeof(object))。根据 JSON,你会得到一个字典对象或类似的东西,然后你可以使用它。 【参考方案1】:

我使用您的#2 方法:使用JavaScriptSerializer 反序列化。

这就是我反序列化来自 Facebook 的响应的方法:

// get the id for the uploaded photo
var jss = new JavaScriptSerializer();
var resource = jss.Deserialize<Facebook.Data.Resource>(responseText);

....其中 Facebook.Data.Resource 的定义如下:

namespace Facebook.Data

    public class Resource
    
        public string id  get; set; 
    

我正在反序列化来自responseText看起来像这样:

"id":"10150111918987952",
 "from":"name":"Someone",
     "id":"782272221",
 "name":"uploaded from Cropper. (at 12\/15\/2010 7:06:41 AM)",
 "picture":"http:\/\/photos-f.ak.fbcdn.net\/hphotos-ak-snc4\/hs817.snc4\/69790_101501113333332_782377951_7551951_8193638_s.jpg",
 ...

但由于我在Resource 类中只定义了一个属性,所以我只对那个 进行反序列化。在类中定义要反序列化的字段。

当然,它可以使用继承。您可以像这样定义数据类:

namespace Facebook.Data

  public class Resource
  
    public string id  get; set; 
  

  public class Person : Resource
  
    public string name  get; set; 
  

...然后您可以反序列化 Person 对象。


编辑

好的,鉴于您在更新的问题中提供的示例 json,以下是我编写类来保存响应的方式:

public class GoogleSearchItem

    public string kind  get; set; 
    public string title  get; set; 
    public string link  get; set; 
    public string displayLink  get; set; 
    // and so on... add more properties here if you want
    // to deserialize them


public class SourceUrl

    public string type  get; set; 
    public string template  get; set; 


public class GoogleSearchResults

    public string kind  get; set; 
    public SourceUrl url  get; set; 
    public GoogleSearchItem[] items  get; set; 
    // and so on... add more properties here if you want to
    // deserialize them

这是要反序列化的 C# 代码:

    // create a new instance of JavaScriptSerializer
    JavaScriptSerializer s1 = new JavaScriptSerializer();

    // deserialise the received response 
    GoogleSearchResults results = s1.Deserialize<GoogleSearchResults>(json);

    Console.WriteLine(s1.Serialize(results));

一些cmets:

保存搜索结果的***类称为 GoogleSearchResults。 GoogleSearchResults 类中的第一个属性是kind,对应于 json 对象中的第一个命名属性。你有 link 这不起作用,因为 link 不是该 json 对象中***属性的名称。在您的 json 的层次结构中有一些名为“link”的属性较低,但 JavaScriptSerializer 不会将那些较低级别的东西拉到较高级别。 GoogleSearchResults 类中的下一个属性是 SourceUrl 类型。这是因为 json 中的 url 属性不是一个简单的字符串——它是一个 json 对象,有两个属性,每个属性都有一个字符串值。因此 SourceUrl 作为 C# 中的一个类获得两个字符串属性,每个属性都有适当的名称来反序列化这些命名属性之一。 GoogleSearchResults 类中的下一个属性称为“items”,以便它可以从您的 json 中反序列化项目字典。现在 items,顾名思义,是 json 中的一个数组,由其值周围的方括号表示。这意味着可以有多个项目,尽管在您的情况下只有一个项目。所以 C# 中的这个属性必须是一个数组(或集合)。 json 结果中的每个项目都不是一个简单的字符串,因此,再次,就像我们对 SourceUrl 所做的那样,我们需要定义一个持有者类来反序列化项目对象:GoogleSearchItem。这个类有一堆简单的字符串属性。如果 json 需要,C# 类中的属性也可以是 int 类型或其他类型。 最后,当打印出结果时,如果您只调用Console.WriteLine(result),您将看到Console.WriteLine 隐式调用的ToString() 方法的结果。这只会打印类型的名称,在这种情况下是“GoogleSearchResults”,我认为这不是你想要的。为了查看对象中的内容,您需要对其进行序列化,如我所展示的。在其输出中,您将只看到您反序列化的事物的值。使用我提供的类,结果信息会比原来的少,因为我没有在C#类中提供一些json属性对应的属性,所以没有反序列化。

【讨论】:

我已经更新了我的问题。我觉得我完全按照你的回答说,但我似乎无法得到正确的结果。是因为我错误地定义了类吗?如果你能看看就好了。谢谢。 @Cheeso - 哇,我需要消化一下。我认为我对正在发生的事情的概念仍然不坚定。当你“反序列化”一个 Json 文档时会发生什么?我不明白为什么我需要反序列化我想要的位然后重新序列化以便能够输出它,因为我已经将接收到的响应设置为数据类型string 关于概念:反序列化 json 文档(或字符串)是创建一个对象并使用从 json 字符串中提取的值填充其属性。将对象实例序列化为 json - 反之亦然 - 是将内存中(.NET 对象)形式转换为人类可以查看的 json 字符串。 您需要序列化您的 GoogleSearchResults 对象,以便在打印时将其视为字符串。显然反序列化然后(重新)序列化是循环的,真正的程序不会这样做。我在这里只是为了诊断目的:这样你就可以看到反序列化的结果。 @Cheeso - 非常感谢您抽出宝贵时间回答我。那么让我总结一下我的理解【参考方案2】:

您可以查看Json.NET 及其LINQ 对创建和查询 JSON 的支持。通过制作一个不错的 LINQ 查询,您将只获得您需要的东西(您可以选择、分组、计数、最小值、最大值,无论您喜欢什么)。

【讨论】:

好吧,我有点像初学者,所以我不知道LINQ 是什么。我是否需要知道LINQ 才能使用Json.NET @Nai,是的,事实上强烈建议在使用LINQ之前学习LINQ。而且不只是针对这种情况。作为 .NET 开发人员,这对您来说非常有益。 您的回复是否假定 JSON 数据是行/列而不是自定义对象? @Tim,没关系。我假设它是有效的 JSON,这是一个非常安全的假设,因为它的来源是 Google :-) 您可以使用 LINQ 随意查询它。与查询内存中的任何 .NET 对象的方式相同。这就是 LINQ 的力量。你的数据是什么格式并不重要。你用同样的方式查询它(SQL、XML、内存中的对象、JSON,你可以命名它......)。 我更喜欢使用 MS 已经在 .NET 中提供的东西 - JavaScriptSerializer。【参考方案3】:

http://msdn.microsoft.com/en-us/library/bb412170.aspx

http://msdn.microsoft.com/en-us/library/bb410770.aspx

在将 JSON 表示形式转换为 C# 应用程序中的类型后,取出所需的属性。我认为没有办法在转换之前从 JSON 表示中仅提取一个属性(尽管我不确定)。

【讨论】:

以上是关于使用 C# 反序列化 JSON的主要内容,如果未能解决你的问题,请参考以下文章

使用 C# 反序列化 JSON

C# 无法反序列化这个 json

在 C# 中从 JSON 反序列化数组

Json 反序列化 C#

使用 C# 反序列化复杂的嵌套 JSON

C# JSON 反序列化