我的来源是JSON-fied Wordpress Feed。这意味着,JSON多次出现相同的标记<item>
。
<channel>
<item>
<title>Titel 1</title>
</item>
<item>
<title>Titel 2</title>
</item>
</channel>
我还有两个结构Channel
和Item
。两者都实现了Codable
协议。
频道
struct Channel: Codable {
// Channel name
let title: String?
// All items (blog entries) from the channel
let items = [Item]()
enum CodingKeys: String, CodingKey {
case title = "title"
case items = "item"
}
init(from decoder: Decoder) throws {
let values = try decoder.container(keyedBy: CodingKeys.self)
title = try values.decode(String.self, forKey: .title)
let itemValues = try values.nestedContainer(keyedBy: Item.CodingKeys, forKey: Feed.CodingKeys.items)
items = try values.decode([Item.self], forKey: .title) // <-- Crash!!
}
func encode(to encoder: Encoder) throws {
// ...
}
}
我的问题是,我的let items = [Item]()
永远不会被填满。我尝试了quickbytes.io中的示例,但它有另一种数据结构。
在我的经理中,我会打电话:
let jsonData = try? JSONSerialization.data(withJSONObject: jsonDict, options: .prettyPrinted)
try? decoder.decode(Feed.self, from: jsonData)
感谢您的帮助!
答案 0 :(得分:1)
您说您正在将该XML转换为JSON。我建议您编辑一个问题,向我们展示生成的JSON的样子。但让我们想象它最终看起来像:
{"channel":
[
{"title": "Title 1"},
{"title": "Title 2"}
]
}
在这种情况下,你可以这样做:
struct Item: Codable {
let title: String
}
struct Channel: Codable {
let items: [Item]
enum CodingKeys: String, CodingKey {
case items = "channel"
}
}
然后:
do {
let channel = try JSONDecoder().decode(Channel.self, from: data)
print(channel)
} catch {
print(error)
}
但是,很明显,如果您的JSON看起来与我上面假设的不同,我们必须相应地更改实现。但是我们不能看到JSON实际上看起来像什么。
下面,在我的原始答案中,我将展示如何直接解析XML,绕过XML提要的JSON化。
我们不能说没有看到实际的JSON,但这一行显然是错误的:
items = try values.decode([Item.self], forKey: .title)
应该是:
items = try values.decode([Item].self, forKey: .items)
请注意]
的位置,以及使用.items
而不是.title
。
坦率地说,整个init(from:)
看起来没什么必要,但是如果没有看到你的实际JSON看起来是什么就不可能说出来。
-
这是XML,而不是JSON。因此,您既不能使用JSONSerialization
也不能使用JSONDecoder
。因此,您可能希望使用XMLParser
:
let delegate = ChannelParserDelegate()
let parser = XMLParser(data: data)
parser.delegate = delegate
guard parser.parse(), let channel = delegate.channel else {
print(parser.parserError ?? "Unknown error")
return
}
print(channel)
其中
struct Channel {
let items: [Item]
}
struct Item {
let title: String
}
和
class ChannelParserDelegate: NSObject, XMLParserDelegate {
var channel: Channel?
private var items: [Item]?
private var currentValue: String?
private var values: [String: Any]?
func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) {
if elementName == "channel" {
items = []
} else if elementName == "item" {
values = [:]
} else if elementName == "title" {
currentValue = ""
}
}
func parser(_ parser: XMLParser, foundCharacters string: String) {
currentValue? += string
}
func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
if elementName == "title" {
values?[elementName] = currentValue
currentValue = nil
} else if elementName == "item" {
items?.append(Item(title: values!["title"] as! String))
values = nil
} else if elementName == "channel" {
channel = Channel(items: items!)
}
}
func parser(_ parser: XMLParser, parseErrorOccurred parseError: Error) {
channel = nil
items = nil
}
}
如果您最终获得的Item
属性不仅仅是title
,那么只需为title
didStartElement
和didEndElement
中的JSONDecoder
添加条款即可。 }。
为了完全公开,有一些WordPress插件可以为其生成JSON提要。那么,理论上你可以使用JSONSerialization
(或者,如果你必须,XMLParser
)。但是,如果您不想调整服务器配置,可以在客户端代码中使用-----------------------
| Column 1 | Column 2 |
-----------------------
| 1 | a |
-----------------------
| 1 | b |
-----------------------
| 2 | a |
-----------------------
| 2 | a |
-----------------------
| 3 | a |
-----------------------
| 4 | b |
-----------------------
| 4 | a |
-----------------------
,如上所述。