Swift Codable:使用字典解析JSON?多个不同的条目?

路加

我有一个很大的Json文件要解析(几MB),并且没有合适的文档。生活艰难。据我所知,文件中的对象很容易。但是有些事情我不理解,简单的Codable协议失败了。在数组中,layers我可以找到三个Layer对象,每个对象都有property elementselements我能找到不止一个elementData-在第一层有"ImageID":32dd...component,在第二层和第三层"name":..."contours": [...]可能会有更多的可能性。我的每一次尝试都以错误结束。

抱歉,这段代码将持续很长时间,但是我不想削减可能的重要部分:

    "layers":[
    {
      "name":"img",
      "elements":[
        {
          "elementData":{
            "imageId":"32dd800000002"
          },
          "transform":{
            "xScale":100,
            "yScale":100
          },
          "active":true
        },
        {
          "component":{
            "glyphName":"e",
            "layerName":"img"
          }
        },
        {
          "elementData":{
            "composite":{
              "builder":{
                "builderGroup":{
                }
              }
            }
          },
          "transform":{
            "xOffset":120
          },
          "nonSpacing":true
        }
      ],
      "color":"maroon",
      "active":true
    },
    {
      "name":"Black",
      "elements":[
        {
          "component":{
            "glyphName":"e",
            "layerName":"Black"
          }
        },
        {
          "elementData":{
            "name":"caron",
            "contours":[
              {
                "nodes":[
                  "80 577",
                  "107 549  142 550  167 575 s"
                ]
              }
            ]
          }
        }
      ],
      "color":"#00802a"
    },
    {
      "name":"Thin",
      "elements":[
        {
          "component":{
            "glyphName":"e",
            "layerName":"Thin"
          }
        },
        {
          "elementData":{
            "name":"caron",
            "contours":[
              {
                "nodes":[
                  "102 597 s",
                  "118 580  132 580  148 597 s",
                  "250 710",
                  "235 726",
                  "110 613",
                  "140 613",
                  "14 726",
                  "-1 710"
                ]
              }
            ]
          }
        }
      ],
      "color":"#6a8000"
    }
  ],

怎么处理呢?

Sh_Khan

https://app.quicktype.io,正确的json

{ "layers":[
{
  "name":"img",
  "elements":[
    {
      "elementData":{
        "imageId":"32dd800000002"
      },
      "transform":{
        "xScale":100,
        "yScale":100
      },
      "active":true
    },
    {
      "component":{
        "glyphName":"e",
        "layerName":"img"
      }
    },
    {
      "elementData":{
        "composite":{
          "builder":{
            "builderGroup":{
            }
          }
        }
      },
      "transform":{
        "xOffset":120
      },
      "nonSpacing":true
    }
  ],
  "color":"maroon",
  "active":true
},
{
  "name":"Black",
  "elements":[
    {
      "component":{
        "glyphName":"e",
        "layerName":"Black"
      }
    },
    {
      "elementData":{
        "name":"caron",
        "contours":[
          {
            "nodes":[
              "80 577",
              "107 549  142 550  167 575 s"
            ]
          }
        ]
      }
    }
  ],
  "color":"#00802a"
},
{
  "name":"Thin",
  "elements":[
    {
      "component":{
        "glyphName":"e",
        "layerName":"Thin"
      }
    },
    {
      "elementData":{
        "name":"caron",
        "contours":[
          {
            "nodes":[
              "102 597 s",
              "118 580  132 580  148 597 s",
              "250 710",
              "235 726",
              "110 613",
              "140 613",
              "14 726",
              "-1 710"
            ]
          }
        ]
      }
    }
  ],
  "color":"#6a8000"
}
]}

解析

struct Welcome: Codable {
    let layers: [Layer]
}

struct Layer: Codable {
    let name: String
    let elements: [Element]
    let color: String
    let active: Bool?
}

struct Element: Codable {
    let elementData: ElementData?
    let transform: Transform?
    let active: Bool?
    let component: Component?
    let nonSpacing: Bool?
}

struct Component: Codable {
    let glyphName, layerName: String
}

struct ElementData: Codable {
    let imageID: String?
    let composite: Composite?
    let name: String?
    let contours: [Contour]?

    enum CodingKeys: String, CodingKey {
        case imageID = "imageId"
        case composite, name, contours
    }
}

struct Composite: Codable {
    let builder: Builder
}

struct Builder: Codable {
    let builderGroup: BuilderGroup
}

struct BuilderGroup: Codable {
}

struct Contour: Codable {
    let nodes: [String]
}

struct Transform: Codable {
    let xScale, yScale, xOffset: Int?
}

do {
     let res = try JSONDecoder().decode(Welcome.self,from:data)
 }
catch { 
    print(error)
}

编辑:

struct Welcome: Codable {
    let layers: [Layer]
}

struct Layer: Codable {
    let name: String
    let elements: [Element]
    let color: String
    let active: Bool?
}

struct Element: Codable {
    let elementData: ElementDataUnion?
    let transform: Transform?
    let active: Bool?
    let component: Component?
    let nonSpacing: Bool?
}

struct Component: Codable {
    let glyphName, layerName: String
}

enum ElementDataUnion: Codable {
    case elementDataClass(ElementDataClass)
    case string(String)

    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if let x = try? container.decode(String.self) {
            self = .string(x)
            return
        }
        if let x = try? container.decode(ElementDataClass.self) {
            self = .elementDataClass(x)
            return
        }
        throw DecodingError.typeMismatch(ElementDataUnion.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for ElementDataUnion"))
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        switch self {
        case .elementDataClass(let x):
            try container.encode(x)
        case .string(let x):
            try container.encode(x)
        }
    }
}

struct ElementDataClass: Codable {
    let composite: Composite?
    let name: String?
    let contours: [Contour]?
}

struct Composite: Codable {
    let builder: Builder
}

struct Builder: Codable {
    let builderGroup: BuilderGroup
}

struct BuilderGroup: Codable {
}

struct Contour: Codable {
    let nodes: [String]
}

struct Transform: Codable {
    let xScale, yScale, xOffset: Int?
}

如果您需要elementData成为字典/字符串,则要elements成为数组/字符串,请使用

struct Welcome: Codable {
    let layers: [Layer]
}

struct Layer: Codable {
    let name: String
    let elements: Elements
    let color: String
    let active: Bool?
}

enum Elements: Codable {
    case elementArray([Element])
    case string(String)

    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if let x = try? container.decode([Element].self) {
            self = .elementArray(x)
            return
        }
        if let x = try? container.decode(String.self) {
            self = .string(x)
            return
        }
        throw DecodingError.typeMismatch(Elements.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for Elements"))
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        switch self {
        case .elementArray(let x):
            try container.encode(x)
        case .string(let x):
            try container.encode(x)
        }
    }
}

struct Element: Codable {
    let component: Component?
    let elementData: ElementDataUnion?
}

struct Component: Codable {
    let glyphName, layerName: String
}

enum ElementDataUnion: Codable {
    case elementDataClass(ElementDataClass)
    case string(String)

    init(from decoder: Decoder) throws {
        let container = try decoder.singleValueContainer()
        if let x = try? container.decode(String.self) {
            self = .string(x)
            return
        }
        if let x = try? container.decode(ElementDataClass.self) {
            self = .elementDataClass(x)
            return
        }
        throw DecodingError.typeMismatch(ElementDataUnion.self, DecodingError.Context(codingPath: decoder.codingPath, debugDescription: "Wrong type for ElementDataUnion"))
    }

    func encode(to encoder: Encoder) throws {
        var container = encoder.singleValueContainer()
        switch self {
        case .elementDataClass(let x):
            try container.encode(x)
        case .string(let x):
            try container.encode(x)
        }
    }
}

struct ElementDataClass: Codable {
    let name: String
    let contours: [Contour]
}

struct Contour: Codable {
    let nodes: [String]
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章