2014-08-27 69 views
3

我试图通过Json文件递归运行并检索名为“fileName”的属性,然后将该属性的值添加到ListView中。然而,问题在于,正如标题所述,同一模式中有两个相同属性的实例,这是我认为会导致错误的原因。在同一模式下具有相同名称的两个属性。尝试检索属性值时出错

我想忽略包含“spigot.jar”的“fileName”属性,并且只检索包含“spigot-1.7.10-R0.1-SNAPSHOT.jar”的属性。

样品JSON的我试图解析(或使用http://ci.md-5.net/job/Spigot/api/json?depth=1为参考)的:

"artifacts" : [ 
    { 
     "displayPath" : "spigot-1.7.10-R0.1-SNAPSHOT.jar", 
     "fileName" : "spigot-1.7.10-R0.1-SNAPSHOT.jar", 
     "relativePath" : "Spigot-Server/target/spigot-1.7.10-R0.1-SNAPSHOT.jar" 
    }, 
    { 
     "displayPath" : "spigot.jar", 
     "fileName" : "spigot.jar", 
     "relativePath" : "Spigot-Server/target/spigot.jar" 
    } 
    ] 


如何我试图解析,并把它添加到ListView在C#:

var url = "http://ci.md-5.net/job/Spigot/api/json?depth=1"; 
var content = (new WebClient()).DownloadString(url); 

dynamic json = JsonConvert.DeserializeObject(content); 

foreach (var builds in json.builds) 
{ 
    string fileName = builds.artifacts.fileName; 

    lvServers.Items.Add(fileName); 
} 


我该如何去成功检索“fileName”属性?

+0

你的代码工作真棒,但我们为什么需要使用动态字? – MonsterMMORPG 2014-08-28 00:29:03

回答

3

请尝试以下操作。这将列出的版本号以及每个打造的第一个文件名:

var url = "http://ci.md-5.net/job/Spigot/api/json?depth=1"; 
var content = (new WebClient()).DownloadString(url); 

JObject root = JObject.Parse(content); 

var list = root["builds"].Select(b => 
      b["number"].ToString() + " - " + 
      b["artifacts"].Select(a => a["fileName"].ToString()) 
         .FirstOrDefault()); 

foreach (var fileName in list) 
{ 
    lvServers.Items.Add(fileName); 
} 

演示https://dotnetfiddle.net/54l8YX

需要注意的是内部版本号1603有没有文物(我猜是因为结果是失败的该建立),所以文件名是空的。


结合发生了什么事情在上面的代码

我使用Json.Net的LINQ-to-JSON API(JObjects,JTokens,JArrays等)的说明内置的.NET扩展方法System.Linq命名空间(Select,FirstOrDefault)和一对lambda expressions从JSON层次结构中提取数据。

下面是它的分解:

  1. 我第一次解析下载内容到JObject使用JObject.Parse(content)

  2. 使用JObject,我可以使用方括号语法(就像Dictionary那样)来获取该对象内直接子属性的值。 root["builds"]为我提供JArrayJObjects代表构建的列表。

  3. Select方法可以让我拿东西的IEnumerable(在这种情况下JObjectsJArray代表的版本),遍历该列表,并以将其改造成一个函数应用到每个项目列表其他东西的列表(在这种情况下是一个字符串列表)。

  4. 我应用于每个版本JObject的函数是lambda expressionb => b["number"] + " - " + b["artifacts"] ...。在此表达我说:“从构建b,得到number属性作为一个字符串,用隔离-和子表达式从文物为构建列表中获得的第一个文件名串连它。

  5. 在子表达式中,我得到构建的artifacts属性的值(这是JObjects的另一个JArray),然后使用Select将其转换为具有lambda表达式a => a[fileName].ToString()的文件名列表。但是,由于我只是想要第一个文件名,我使用FirstOrDefault()将列表剔除为单个项目(如果没有项目,则为null)

希望这是有道理的。如果你不熟悉LINQ或lambda表达式,那么代码看起来有点神秘。下面是不使用这些构造的替代版本,但是完全一样。这可能会更容易理解。

var url = "http://ci.md-5.net/job/Spigot/api/json?depth=1"; 
var content = (new WebClient()).DownloadString(url); 

JObject root = JObject.Parse(content); 

foreach (JObject build in root["builds"]) 
{ 
    string buildName = build["number"].ToString() + " - "; 

    foreach (JObject artifact in build["artifacts"]) 
    { 
     JToken fileName = artifact["fileName"]; 
     if (fileName != null) 
     { 
      buildName += fileName.ToString(); 
     } 
     break; 
    } 

    lvServers.Items.Add(buildName); 
} 

演示https://dotnetfiddle.net/vwebrY

+0

现在我更了解他想要的更多,我更喜欢这种方法。简单而直接。 – 2014-08-27 23:30:41

+0

@Raxdiam我已经更新了我的答案,以解释发生了什么,并提供了一个替代版本,它可以做同样的事情,但不是很神秘。希望这可以帮助你。如果你有另一个具体的问题,你可以打开一个新的问题来问它。如果您需要引用该问题,您可以包含回到此问题的链接或回答(使用“分享”按钮获取URL)。另外,请务必首先在StackOverflow中搜索其他答案。有很多关于解析JSON的问题和答案;有一个很好的机会可以帮助你。 – 2014-08-28 02:07:19

4

它看起来像文物是一个数组,所以你需要通过一个索引要么在它们之间迭代或访问:

foreach (var artifact in builds.artifacts) 
{ 
    var fileName = artifact.fileName; 
} 

var fileName = builds.artifacts[0].fileName; 
+0

这似乎不起作用,而且我对这个主题还不太了解,所以不知道为什么。 我可以提供的唯一信息是,我收到此错误: “其他信息:索引超出范围,必须是非负值,并且小于集合的大小。”在JContainer.cs中 另外,作为参考,这个:http://ci.md-5.net/job/Spigot/api/json?depth=1是我试图解析的json文档。而这个网站:http://www.jsoneditoronline。org /应该使它更易于阅读。 – Raxdiam 2014-08-27 22:04:47

+0

@Raxdiam - 只有在数组中至少有一个项目时,索引器方法才起作用。 foreach选项应该始终有效。 – 2014-08-27 22:08:36

+0

嗯,我不怀疑你什么。我可能只是在做错事。我不知道我是否正确使用你的例子。 – Raxdiam 2014-08-27 22:10:30

0

强类型的转换JSON到C#对象将让你编译时间错误。因为您正在使用动态关键字,所以在尝试运行应用程序之前,您将不会收到编译器错误。

创建这些类: Classes

然后修改当前的代码是这样的:

var url = "http://ci.md-5.net/job/Spigot/api/json?depth=1"; 
var content = (new WebClient()).DownloadString(url); 

var responseObj = JsonConvert.DeserializeObject<RootObject>(content); 

因为他们现在是强类型,你将能够获得编译器错误,告诉你,你做错了。尽量远离动态对象。

现在,这将错误,因为你不使用它的权利:

foreach (var builds in json.builds) 
{ 
    string fileName = builds.artifacts.fileName; 

    lvServers.Items.Add(fileName); 
} 

现在您的代码会产生这样的错误通知你,这是不对的:

'System.Collections.Generic.IEnumerable<UserQuery.Artifact>' does not contain a definition for 'fileName' and no extension method 'fileName' accepting a first argument of type 'System.Collections.Generic.IEnumerable<UserQuery.Artifact>' could be found (press F4 to add a using directive or assembly reference) 

如果你需要生成未来班级使用工具JSON2CSHARP。只要知道你需要清除重复的东西,那很糟糕。

+0

Json经常在我从中提取的服务器上更新。这对于我正在尝试使用此代码而言至关重要。如果我以你为榜样,我还能够获得新增的内容吗? – Raxdiam 2014-08-27 22:54:25

+0

您只需通过JSON2CSHARP网站运行代码即可更新代码。此外,似乎我不知道该怎么做关于一个奇怪的属性名称,你有“起源/主”<---不知道该怎么做。 但是,如果你走这条路线,你必须更新StrongType类,但是如果你添加属性,你也将不得不更新动态调用,所以没关系。 – 2014-08-27 22:59:59

+0

我更新了从GistHub链接到的类,删除了大量重复项。现在当你说你的JSON一直在更新时,你的意思是说,JSON属性是不断变化的,还是你的意思是说你一直在提取新数据? 因为无论属性是否发生变化,您都必须更新您的C#代码。 – 2014-08-27 23:22:41

相关问题