在Swift中如何使用Alamofire解析非标准JSON数据?
解决思路与步骤
你遇到的是API返回了Swift/Objective-C字典的调试打印格式(非标准JSON),同时其中customerData字段是XML字符串。可以分两步解析:
1. 先提取外层的字段值
首先处理这个非标准的字典格式,有两种简单方式:
方式一:转成标准JSON手动处理
把打印的字符串做以下替换,转换成标准JSON:
- 把所有
=替换成: - 把所有
;替换成, - 给所有键名(比如
customerData、message)加上双引号
转换后的标准JSON如下:
{ "customerData": "<zakaznik><zkznid>475301</zkznid><titul></titul><jmeno>757B746D</jmeno><prijmeni>DÁRKOVÁ KARTA</prijmeni><rozliseni></rozliseni><osloveniok>false</osloveniok><kontos></kontos><skupzak1_klic>DK</skupzak1_klic><skupzak2_klic>default</skupzak2_klic><cenkat_klic>1</cenkat_klic><platido>2118-07-31</platido><valid>true</valid></zakaznik>", "message": "Informace o zákazníkovi \"DÁRKOVÁ KARTA 757B746D\" načteny." }
之后就可以用Swift自带的JSONSerialization或者Codable正常解析成字典。
方式二:用正则直接提取字段
如果不想转JSON,直接用正则表达式提取需要的内容:
let responseStr = """ { customerData = "<zakaznik><zkznid>475301</zkznid><titul></titul><jmeno>757B746D</jmeno><prijmeni>D\U00c1RKOV\U00c1 KARTA</prijmeni><rozliseni></rozliseni><osloveniok>false</osloveniok><kontos></kontos><skupzak1_klic>DK</skupzak1_klic><skupzak2_klic>default</skupzak2_klic><cenkat_klic>1</cenkat_klic><platido>2118-07-31</platido><valid>true</valid></zakaznik>"; message = "Informace o z\U00e1kazn\U00edkovi \"D\U00c1RKOV\U00c1 KARTA 757B746D\" na\U010dteny."; } """ // 提取customerData的XML内容 if let xmlRange = responseStr.range(of: #"customerData = "(.*?)";"#, options: .regularExpression) { let xmlStr = String(responseStr[xmlRange]) .replacingOccurrences(of: #"customerData = ""#, with: "") .replacingOccurrences(of: """;""", with: "") // 拿到xmlStr后进入下一步解析XML } // 提取message内容 if let messageRange = responseStr.range(of: #"message = "(.*?)";"#, options: .regularExpression) { let message = String(responseStr[messageRange]) .replacingOccurrences(of: #"message = ""#, with: "") .replacingOccurrences(of: """;""", with: "") print(message) }
2. 解析customerData里的XML字符串
拿到XML字符串后,推荐用第三方库XMLCoder(基于Codable,用法和JSON解析一致),或者系统自带的XMLParser。
方式一:用XMLCoder(推荐)
- 先通过CocoaPods安装:
pod 'XMLCoder'
- 定义对应XML结构的Codable模型:
import XMLCoder // 对应XML的<zakaznik>节点结构 struct Customer: Codable { let zkznid: String let titul: String? let jmeno: String let prijmeni: String let rozliseni: String? let osloveniok: String let kontos: String? let skupzak1_klic: String let skupzak2_klic: String let cenkat_klic: String let platido: String let valid: String } // 解析XML的方法 func parseCustomerXML(_ xmlStr: String) -> Customer? { guard let data = xmlStr.data(using: .utf8) else { return nil } do { let decoder = XMLDecoder() return try decoder.decode(Customer.self, from: data) } catch { print("XML解析失败: \(error)") return nil } }
- 调用解析:
if let customer = parseCustomerXML(xmlStr) { print("用户ID: \(customer.zkznid)") print("姓名: \(customer.prijmeni) \(customer.jmeno)") }
方式二:用系统XMLParser(无第三方依赖)
如果不想用第三方库,手动实现解析逻辑:
class CustomerParser: NSObject, XMLParserDelegate { private var currentElement = "" private var zkznid = "" private var jmeno = "" private var prijmeni = "" // 其他字段同理定义 var result: Customer? func parse(xmlStr: String) { guard let data = xmlStr.data(using: .utf8) else { return } let parser = XMLParser(data: data) parser.delegate = self parser.parse() } func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) { currentElement = elementName } func parser(_ parser: XMLParser, foundCharacters string: String) { let trimmed = string.trimmingCharacters(in: .whitespacesAndNewlines) guard !trimmed.isEmpty else { return } switch currentElement { case "zkznid": zkznid += trimmed case "jmeno": jmeno += trimmed case "prijmeni": prijmeni += trimmed // 处理其他字段... default: break } } func parserDidEndDocument(_ parser: XMLParser) { result = Customer( zkznid: zkznid, titul: nil, jmeno: jmeno, prijmeni: prijmeni, rozliseni: nil, osloveniok: "", kontos: nil, skupzak1_klic: "", skupzak2_klic: "", cenkat_klic: "", platido: "", valid: "" ) } }
使用方式:
let parser = CustomerParser() parser.parse(xmlStr: xmlStr) if let customer = parser.result { print(customer.prijmeni) }
额外建议
最好联系API开发者,让他们返回标准JSON格式,这样解析会更简单可靠,毕竟当前的返回格式只是调试用的打印格式,不是正式的API响应规范。
内容的提问来源于stack exchange,提问作者user22038725
相关产品推荐
相关产品推荐

