我试图以递归方式运行Json文件并检索名为" fileName"的属性,然后将该属性的值添加到ListView。但问题是,正如标题所说,同一模式中有两个相同属性的实例,这就是我认为导致错误的原因。
我想忽略" fileName"包含" spigot.jar"的属性,仅检索包含" 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"
}
]
我如何尝试解析,并将其添加到C#中的ListView:
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 :(得分:4)
看起来工件是一个数组,所以你需要迭代它们或通过索引器访问:
foreach (var artifact in builds.artifacts)
{
var fileName = artifact.fileName;
}
或
var fileName = builds.artifacts[0].fileName;
答案 1 :(得分: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没有工件(我猜测因为该构建的结果是FAILURE)所以文件名为空。
解释上述代码中的内容
我使用Json.Net的LINQ-to-JSON API(JObjects,JTokens,JArrays等)与System.Linq命名空间中的内置.NET扩展方法相结合({ {3}},Select
)和几个FirstOrDefault
从JSON层次结构中提取数据。
以下是它如何分解:
我首先使用JObject
将下载的内容解析为JObject.Parse(content)
。
使用JObject
,我可以使用方括号语法(就像Dictionary
一样)来获取该对象中的直接子属性的值。 root["builds"]
为我提供JArray
JObjects
代表构建列表。
Select
方法允许我获取某些内容的lambda expressions(在这种情况下代表构建的JArray
JObjects
),迭代该列表并将一个函数应用于列表中的每个项目,以便将其转换为其他内容的列表(在本例中为字符串列表)。
我应用于每个版本JObject
的功能是IEnumerable
:b => b["number"] + " - " + b["artifacts"] ...
。在这个表达式中,我说#34;来自构建b
,将number
属性作为字符串,将其与分隔符-
连接,并使用获得第一个的子表达式构建工件列表中的文件名。
在子表达式中,我得到构建的artifacts
属性的值(JArray
的另一个JObjects
),然后使用{{1}使用lambda表达式Select
将其转换为文件名列表。但是,因为我只想要第一个fileName,所以我使用a => a[fileName].ToString()
来剔除列表到单个项目(如果没有项目,则为null)。
希望这有点道理。如果您不熟悉LINQ或lambda表达式,那么代码肯定会有点神秘。下面是一个不使用这些结构的替代版本,但完全相同。这可能会更容易理解。
FirstOrDefault()
答案 2 :(得分: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。只知道你需要清除重复的东西,但这很可怕。