使用 Swift 3 解析 JSON

Posted

技术标签:

【中文标题】使用 Swift 3 解析 JSON【英文标题】:JSON Parsing using Swift 3 【发布时间】:2017-06-08 09:24:05 【问题描述】:

我正在我的应用程序中调用一个肥皂服务。我从服务器收到此 JSON 响应

  
  "CustomerName":"Muneer Ahmad/ Ejaz Ahmad (User)  ",
  "IsCorporate":false,
  "ID":48,
  "Name":"Muneer Ahmad/ Ejaz Ahmad (User)  ",
  "GroupID":null,
  "GroupName":null,
  "CustomerID":48

我已经尝试过在线教程的建议,但我无法解析数据。它给我的错误是“字符 0 周围的值无效”。我的代码是这样的

 let is_URL: String = "http://labs2.unitedtracker.com/WTService.asmx?op=GetTerminalNumber"

    let lobj_Request = NSMutableURLRequest(url: NSURL(string: is_URL)! as URL)
    let session = URLSession.shared

    lobj_Request.httpMethod = "POST"
    lobj_Request.httpBody = is_SoapMessage.data(using: String.Encoding.utf8)
    lobj_Request.addValue("labs2.unitedtracker.com", forHTTPHeaderField: "Host")
    lobj_Request.addValue("text/xml; charset=utf-8", forHTTPHeaderField: "Content-Type")
    lobj_Request.addValue(String(is_SoapMessage.characters.count), forHTTPHeaderField: "Content-Length")
    lobj_Request.addValue("http://tempuri.org/GetTerminalNumber", forHTTPHeaderField: "SOAPAction")

    let task = session.dataTask(with: lobj_Request as URLRequest, completionHandler: data, response, error -> Void in

        do 
            if let data = data,
                let json = try JSONSerialization.jsonObject(with: data) as? [String: Any],
                let customerID = json["CustomerID"] as? [[String: Any]] 
                print(customerID)
            
         catch 
            print("Error deserializing JSON: \(error)")
        

        if error != nil
        
            print("Error: " + String(describing: error))
        
    )
    task.resume()

谁能告诉我我在做什么错。以及应该如何解析来自 Soap Service 的 JSON 响应。

这是来自我的服务器的完整响应。

<?xml version="1.0" encoding="utf-8"?><soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema"><soap:Body><GetAuthenticateUserResponse xmlns="http://tempuri.org/"><GetAuthenticateUserResult>["CustomerName":"Muneer Ahmad/ Ejaz Ahmad (User)  ","IsCorporate":false,"ID":48,"Name":"Muneer Ahmad/ Ejaz Ahmad (User)  ","GroupID":null,"GroupName":null,"CustomerID":48]</GetAuthenticateUserResult></GetAuthenticateUserResponse></soap:Body></soap:Envelope>

【问题讨论】:

catch 处理程序中的哪里收到错误?您可以将传入的data 记录为字符串吗? 不!我从 catch 处理程序中得到错误。当我尝试打印 customerID 时,它会说“字符 0 周围的值无效。” 为什么将 customerID 解析为字典数组?查看 JSON 响应,customerID 显然是一个 Int,因此您应该像这样解析它。 let customerID = json["CustomerID"] as? Int print(customerID) 提出了很好的观点@David Pasztor 实际上它是一个字符串值。我试试你说的。 显然服务器响应是 XML 而不是 JSON。 【参考方案1】:
lobj_Request.addValue("text/xml; charset=utf-8", forHTTPHeaderField: "Content-Type")

你如何保证服务器会返回 json 作为响应?似乎它会返回text/xml 作为响应。

关于JSON解析,我建议SwiftyJSON。

更多建议

几年前,我使用了一个soap客户端引擎,它将wsdl解析为objective-c代码。今天,也许有些工具可以帮助您从wsdl 生成Swift 代码,以便与soap 服务器通信。

关于 wsdl 到 swift 客户端生成器

https://***.com/a/32798709/419348 作者发布了关于 wsdltoswift 的答案。 http://wsdl2swift.comwsdl2swift 网址。

【讨论】:

开头的 JSON 是我从服务器接收的字符串。我们可以看到它是JSON格式的。 作为@zoul 的评论,您能否将传入的data 记录为字符串? 我已经更新了我的问题,现在服务器的完整响应也在其中 显然,&lt;xml version ... &gt;xml 格式,而不是json。我已经更新了我的答案。也许调查一些 wsdl 解析工具可以帮助你。【参考方案2】:

问题是您从服务器接收 XML 并尝试将其解析为 JSON。您必须首先从 XML 信封中提取 JSON 有效负载。这是完整的回应:

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <soap:Body>
    <GetAuthenticateUserResponse xmlns="http://tempuri.org/">
      <GetAuthenticateUserResult>["CustomerName":"Muneer Ahmad/ Ejaz Ahmad (User)  ","IsCorporate":false,"ID":48,"Name":"Muneer Ahmad/ Ejaz Ahmad (User)  ","GroupID":null,"GroupName":null,"CustomerID":48]</GetAuthenticateUserResult>
    </GetAuthenticateUserResponse>
  </soap:Body>
</soap:Envelope>

您需要将&lt;GetAuthenticateUserResult&gt; 标记的内容提取为字符串,只有这样您才能使用NSJSONSerialization 对其进行解析。有点像这样:

class Extractor: NSObject, XMLParserDelegate 

    var payload = ""
    private var recording = false
    let wantedElement = "GetAuthenticateUserResult"

    func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?,
        qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) 
        if elementName == wantedElement 
            recording = true
        
    

    func parser(_ parser: XMLParser, foundCharacters string: String) 
        if recording 
            payload += string
        
    

    func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) 
        recording = false
    


let response = "<?xml version=\"1.0\" encoding=\"utf-8\"?><soap:Envelope xmlns:soap=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xmlns:xsd=\"http://www.w3.org/2001/XMLSchema\"><soap:Body><GetAuthenticateUserResponse xmlns=\"http://tempuri.org/\"><GetAuthenticateUserResult>[\"CustomerName\":\"Muneer Ahmad/ Ejaz Ahmad (User)\",\"IsCorporate\":false,\"ID\":48,\"Name\":\"Muneer Ahmad/ Ejaz Ahmad (User)  \",\"GroupID\":null,\"GroupName\":null,\"CustomerID\":48]</GetAuthenticateUserResult></GetAuthenticateUserResponse></soap:Body></soap:Envelope>"
let parser = XMLParser(data: response.data(using: .utf8)!)
let extractor = Extractor()
parser.delegate = extractor
parser.parse()
let payload = extractor.payload
let parsedPayload = try? JSONSerialization.jsonObject(with: payload.data(using: .utf8)!, options: [])

这给了你:


    CustomerID = 48;
    CustomerName = "Muneer Ahmad/ Ejaz Ahmad (User)";
    GroupID = "<null>";
    GroupName = "<null>";
    ID = 48;
    IsCorporate = 0;
    Name = "Muneer Ahmad/ Ejaz Ahmad (User)  ";

XML 提取代码有点笨,因为我不知道有什么更好的内置 XML 解析器。

【讨论】:

【参考方案3】:

您的代码:

let customerID = json["CustomerID"] as? [[String: Any]] 
    print(customerID)

customerID 视为字典而不是字符串。

应该是:

let customerID = json["CustomerID"] as? String 
    print(customerID)

您应该使用其他方式的网络请求和 JSON 解析器,例如 Alamofire and AlamofireObjectMapper。

【讨论】:

【参考方案4】:

错误是将String 包装成[[String:Any]]

而不是这个:

if let data = data,
    let json = try JSONSerialization.jsonObject(with: data) as? [String: Any],
    let customerID = json["CustomerID"] as? [[String: Any]] 
        print(customerID)

试试这个:

if let data = data,
   let json = try JSONSerialization.jsonObject(with: data) as? [[String: Any]],
   let customerID = json["CustomerID"] as? String 
       print(customerID)

【讨论】:

customerId 在 JSON 响应中看起来像一个数字:"CustomerID":48。所以也许let customerID = json["CustomerID"] as? Int 会更合适。 @Bala Karunakaran 我仍然遇到错误。 “JSON 文本没有以数组或对象开头,并且允许未设置片段的选项。”我想我应该尝试允许片段 @MattLeFleur 我试过了。 if let data = data, let json = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as? [String: Any],让 customerID = json["CustomerID"] as?诠释打印(客户ID)。但仍然没有运气。给我同样的无效字符错误。 而不是 [String: Any] 尝试使用 [[String: Any]]

以上是关于使用 Swift 3 解析 JSON的主要内容,如果未能解决你的问题,请参考以下文章

如何使用 Alamofire 在 Swift 3 中解析 JSON?

使用 Swift 3 解析 JSON

使用 Alamofire 在 swift 3 中解析 Json

如何使用 Swift 3.0 解析这个 JSON 对象

如何在 Swift 3 中使用 Alamofire 4 解析这个 json?

使用 Alamofire Swift 3 和 Xcode 8 beta 解析 JSON 没有数据