0
votes

Décodage de JSON en modèle Swift et non au niveau racine

J'ai le modèle suivant:

{
  status: "ok",
  totalResults: 70,
  articles: [
    {
      source: {
        id: null,
        name: "Oilprice.com"
      },
      author: "Tim Daiss",
      title: "$70 Oil Could Be Right Around The Corner | OilPrice.com - OilPrice.com",
      description: "A recent Bloomberg survey of oil analysts suggests that many believe oil could hit $70 per barrel in 2019, but are they just downplaying the bearish signals?",
      url: "https://oilprice.com/Energy/Crude-Oil/70-Oil-Could-Be-Right-Around-The-Corner.html",
      urlToImage: "https://d32r1sh890xpii.cloudfront.net/article/718x300/d7b8868e80d766d6a5d401219c65d6a0.jpg",
      publishedAt: "2019-01-01T00:00:08Z",
      content: "Oil markets have always been cyclical, and now even more so with advanced electronic trading, more speculation (which often results in wider oil price swings) and more producers, including the resurgence of U.S. oil production, now reaching over 11 million ba… [+4696 chars]"
    },
    {
      source: {
        id: "cnbc",
        name: "CNBC"
      },
      author: "Jordan Novet",
      title: "Activision Blizzard plans to fire its CFO for an unspecified cause - CNBC",
      description: "Shares of gaming company Activision Blizzard moved lower Monday after it announced plans to let go of its chief financial officer.",
      url: "https://www.cnbc.com/2018/12/31/activision-blizzard-plans-to-fire-its-cfo-for-an-unspecified-cause.html",
      urlToImage: "https://fm.cnbc.com/applications/cnbc.com/resources/img/editorial/2012/08/02/48465125-activision-200.1910x1000.jpg",
      publishedAt: "2018-12-31T23:18:17Z",
      content: "Activision Blizzard shares moved down 1 percent in after-hours trading on Monday after the company said that it has informed its chief financial officer, Spencer Neumann, that it plans to let him go. For now he has been placed on a paid leave of absence. div … [+950 chars]"
    }
  ]
}

Le JSON provenant de l'URL est comme ceci:

struct Article: Decodable {

    let title: String
    let description: String
    let imageURL: String

    private enum CodingKeys: String, CodingKey {
        case title
        case description
        case imageURL = "urlToImage"
    }

}

Tout ce que je veux, c'est la valeur dans la clé articles . Comment puis-je l'obtenir en utilisant Swift 4 JSONDecoder.

Je sais comment le faire en créant une structure parent puis en créant la propriété "articles" à l'intérieur du parent. Mais comment puis-je faire cela sans la structure parent.


3 Réponses :


0
votes

Vous pouvez essayer de combiner JSONSerialization avec JSONDecoder

do
{
    let tr = try JSONSerialization.jsonObject(with:data, options:[]) as! [String:Any] 
    guard let content =  tr["articles"] else { return }
    let articlesData = try JSONSerialization.data(withJSONObject:content, options: [])
    let res = try JSONDecoder().decode([Article].self, from: articlesData) 
    print(res) 
}
catch 
{
    print(error)
}


0 commentaires

3
votes

En utilisant JSONDecoder seul, vous ne pouvez pas décoder sans une sorte de structure externe, car votre résultat sera un tableau d'article, qui est une entité externe. Le simple fait de définir un article seul ne peut donc jamais être suffisant.

Si vous n'aimez pas déclarer une structure externe dont vous n'avez pas besoin à d'autres fins que pour explorer la clé "articles" , c'est facilement résolu en le déclarant seulement temporairement dans la portée limitée où vous descendez jusqu'à la clé "articles" . Le reste de votre programme est donc laissé avec la structure Article mais la structure externe n'existe pas ici.

Par exemple:

struct Article: Decodable {
    // ... your code here ...
}
func getArticles(_ d:Data) -> [Article] {
    struct Articles: Decodable { // this struct is temporary
        let articles:[Article]
    }
    return try! JSONDecoder().decode(Articles.self, from: d).articles
}

Un autre code peut maintenant, voyez la structure Article et pouvez appeler getArticles pour analyser le JSON et recevoir le tableau Article, mais un autre code ne sait jamais (et ne peut jamais découvrir) qu'une structure Articles supplémentaire existe; il n'existe que temporairement dans la fonction getArticles comme une sorte de local. Ce n'est pas plus répréhensible que toute autre variable locale créée temporairement dans le corps d'une fonction.


0 commentaires

0
votes

Pensez à restructurer vos données. Vous devez structurer votre modèle de données pour qu'il corresponde à la structure de données des données JSON. Vous ne pouvez inclure que ce que vous voulez, mais vous devez inclure chaque parent ou niveau de la ou des propriétés auxquelles vous souhaitez accéder. Prenons l'exemple suivant de l'API wikipedia. Il imprime la propriété title qui se trouve à trois niveaux dans la structure de données JSON. Il laisse de côté plusieurs propriétés comme vous pouvez le voir dans l'exemple de code JSON, mais il inclut tous les parents dont j'ai besoin pour accéder aux propriétés que je souhaite.

//Swift
//Swift (programming language)
//Taylor Swift

Exemple JSON:

{
"batchcomplete": "",
"continue": {
    "sroffset": 10,
    "continue": "-||"
},
"query": {
    "searchinfo": {
        "totalhits": 30349
    },
    "search": [
        {
            "ns": 0,
            "title": "Swift",
            "pageid": 219023,
            "size": 13896,
            "wordcount": 1496,
            "snippet": "The <span class=\"searchmatch\">swifts</span> are a family, Apodidae, of highly aerial birds. They are superficially similar to swallows, but are not closely related to any passerine species",
            "timestamp": "2018-12-28T21:29:44Z"
        },
        {
            "ns": 0,
            "title": "Swift (programming language)",
            "pageid": 42946389,
            "size": 49365,
            "wordcount": 5244,
            "snippet": "2015. <span class=\"searchmatch\">Swift</span> 3.0 was released on September 13, 2016. <span class=\"searchmatch\">Swift</span> <span class=\"searchmatch\">4</span>.0 was released on September 19, 2017. <span class=\"searchmatch\">Swift</span> <span class=\"searchmatch\">4</span>.1 was released on March 29, 2018. <span class=\"searchmatch\">Swift</span> won first",
            "timestamp": "2018-12-19T02:52:33Z"
        },
        {
            "ns": 0,
            "title": "Taylor Swift",
            "pageid": 5422144,
            "size": 237225,
            "wordcount": 18505,
            "snippet": "Taylor Alison <span class=\"searchmatch\">Swift</span> (born December 13, 1989) is an American singer-songwriter. One of the world's leading contemporary recording artists, she is known",
            "timestamp": "2018-12-26T21:55:51Z"
        },

Voici la sortie de l'impression:

import UIKit

struct Item: Decodable {
    var title: String
}

struct Search: Decodable {
    var search: [Item]
}

struct Result: Decodable {
    var query: Search
}

func getSearchResults(){
    let url = URL(string: "https://en.wikipedia.org/w/api.php?action=query&list=search&srsearch=swift%204&utf8=&format=json")!

    URLSession.shared.dataTask(with: url) { (data, response, error) in
    if let urlResponse = response as? HTTPURLResponse, urlResponse.statusCode == 200 {
        guard let data = data else { return }
        do {
            let results = try JSONDecoder().decode(Result.self, from: data)
            for item in results.query.search {
                print(item.title)
            }
        } catch let error as NSError {
            print("error: \(error)")
        }
    }
}.resume()
}
getSearchResults()


0 commentaires