2014-08-27 24 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

相關問題