在 Swift 中使用 Alamofire 处理 XML 数据
Handling XML data with Alamofire in Swift
我开始在我当前的 ios 项目中使用 cocoapods。我需要使用 SOAP 以简单的方式为我的 ios 项目获取内容。我用谷歌搜索了一下,Alamofire pod 对我来说很棒。因为我使用的是Swift编程语言。
我已经轻松地启动了这个 pod。但是我的网络服务 return 我 XML 结果。我想序列化以排列此 XML 结果。但是我不能。
当我用浏览器调用我的网络服务时,我得到了这种结果
Alamofire的响应方式是这样的:
Alamofire.request(.GET, "http://my-web-service-domain.com", parameters: nil)
.response { (request, response, data, error) in
println(request)
println(response)
println(error)
}
当我运行这个方法时,我在终端上看到这个输出:
<NSMutableURLRequest: 0x170010a30> { URL: http://my-web-service-domain.com }
Optional(<NSHTTPURLResponse: 0x1704276c0> { URL: http://my-web-service-domain.com } { status code: 200, headers {
"Cache-Control" = "private, max-age=0";
"Content-Length" = 1020;
"Content-Type" = "text/xml; charset=utf-8";
Date = "Thu, 18 Jun 2015 10:57:07 GMT";
Server = "Microsoft-IIS/7.5";
"X-AspNet-Version" = "2.0.50727";
"X-Powered-By" = "ASP.NET";
} })
nil
我想得到一个数组的结果,该数组在浏览器上显示我的情节提要。
谁能帮助我如何使用 Alamofire 框架或 Swift 语言序列化这些数据?
如果我没有误解你的描述,我想你会想要得到 XML 数据并解析它,对吧?关于这一点,您可能会在响应回调中处理错误的变量。您应该 println(data)
查看 XML 文档。
解析XML数据,可以考虑SWXMLHash。 Alamofire 请求可能如下所示:
Alamofire.request(.GET, "http://my-web-service-domain.com", parameters: nil)
.response { (request, response, data, error) in
println(data) // if you want to check XML data in debug window.
var xml = SWXMLHash.parse(data!)
println(xml["UserDTO"]["FilmID"].element?.text) // output the FilmID element.
}
有关XML管理的更多信息,请查看SWXMLHash。
使用截至 2015 年 9 月的 Alamofire 3.0 当前版本和 Xcode 7.
下面的实现的优点是不使用额外的外部库,例如 SWXMLHash
Alamofire.request(.GET, urlString, encoding: .PropertyList(.XMLFormat_v1_0, 0)).responsePropertyList { request, response, result in
//Note that result have two properties: error and value as of Alamofire 3.0, check the migration guide for more info
if let error = result.error {
print("Error: \(error)")
// parsing the data to an array
} else if let array = result.value as? [[String: String]] {
if array.isEmpty {
print("No data")
} else {
//Do whatever you want to do with the array here
}
}
}
Alamofire 4.x - Swift 3.x:
(请注意,在这个例子中我使用了 URLEncoding.default
而不是 URLEncoding.xml
因为 xml
参数排除了传递参数和 headers 的可能性,所以default
比较舒服。)
let url = "https://httpbin.org/get"
let parameters: Parameters = ["foo": "bar"]
let headers: HTTPHeaders = [
"Authorization": "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==",
"Accept": "application/json"
]
Alamofire.request(url, method: .get, parameters: parameters, encoding: URLEncoding.default, headers: headers)
.responseString { response in
print(" - API url: \(String(describing: response.request!))") // original url request
var statusCode = response.response?.statusCode
switch response.result {
case .success:
print("status code is: \(String(describing: statusCode))")
if let string = response.result.value {
print("XML: \(string)")
}
case .failure(let error):
statusCode = error._code // statusCode private
print("status code is: \(String(describing: statusCode))")
print(error)
}
}
Alamofire 3.0 2015 年 10 月和 Xcode 7 根据 3.0.0-beta.3 README and the Alamofire 3.0 Migration Guide。
对我来说正确的语法是:
Alamofire.request(.GET, url, parameters: params, encoding: ParameterEncoding.URL).responsePropertyList { response in
if let error = response.result.error {
print("Error: \(error)")
// parsing the data to an array
} else if let array = response.result.value as? [[String: String]] {
if array.isEmpty {
print("No data")
} else {
//Do whatever you want to do with the array here
}
}
}
如果你想要一个好的XML解析器,请看一看SWXMLHash。
例如:
let xml = SWXMLHash.parse(string)
我遇到了一个非常独特的问题,服务器返回了一个 XML,其中包含 JSON 作为字符串。希望对大家有帮助。
基本上 XML 看起来像这样:
<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">{"Response":{"Status":"success","Result_Count":"1","Error_Description":"","Result":{"Login_result":{"user_id":"1","user_type":"1","user_name":"h4cked","user_locked":"False","user_locked_message":""}}}}</string>
如您所见,实际的 JSON 是 {"Response":....
该解决方案仅基于 Alamofire 4.4。
你需要做的是:
- 使用
.responsePropertyList
- 检查错误
- 将值转换为数据
- 序列化为JSON对象
- 转换为字典
[String : Any]
这里是:
Alamofire.request(NetworkAPIPaths.pathForLogin(),
method: .get,
parameters: [APIParameters.userName.rawValue : "",
APIParameters.password.rawValue : ""]).responsePropertyList
{ (response : DataResponse<Any>) in
if let error = response.result.error
{
// Error...
}
else if let jsonFullString = response.result.value as? String
{
if let jsonStringAsData = jsonFullString.data(using: .utf8)
{
do
{
let jsonGhost = try JSONSerialization.jsonObject(with: jsonStringAsData, options: [])
if let actualJSON = jsonGhost as? [String : Any]
{
// actualJSON is ready to be parsed :)
}
}
catch
{
print (error.localizedDescription)
}
}
}
tsaiid 在Swift 3 和 Alamofire 4 中的回答:
Alamofire.request("http://my-web-service-domain.com", parameters: nil) //Alamofire defaults to GET requests
.response { response in
if let data = response.data {
println(data) // if you want to check XML data in debug window.
var xml = SWXMLHash.parse(data)
println(xml["UserDTO"]["FilmID"].element?.text) // output the FilmID element.
}
}
如果你想把XML映射到swift对象,你也可以考虑XMLMapper. (uses the same technique as the ObjectMapper)
通过实施 XMLMappable
协议创建模型:
class UserDTO: XMLMappable {
var nodeName: String!
var extensionData: String?
var canChangeDeviceConfig: BooleanAtttribute?
var canChangeDriverConfig: BooleanAtttribute?
var canChangeFleetConfig: BooleanAtttribute?
var canChangeGeofenceConfig: BooleanAtttribute?
var canSaveHistory: BooleanAtttribute?
var canViewReport: BooleanAtttribute?
var canWatchHistory: BooleanAtttribute?
var deliverDailyReportByEmail: BooleanAtttribute?
var deliverDailyReportBySms: BooleanAtttribute?
var email: String?
var firm: String?
var firmId: Int?
var firstName: String?
var id: Int?
var isActive: Bool?
var isAdmin: Bool?
var lastName: String?
var phone: String?
var recivesDailyReport: BooleanAtttribute?
var userName: String?
required init(map: XMLMap) {
}
func mapping(map: XMLMap) {
extensionData <- map["ExtensionData"]
canChangeDeviceConfig <- map["CanChangeDeviceConfig"]
canChangeDriverConfig <- map["CanChangeDriverConfig"]
canChangeFleetConfig <- map["CanChangeFleetConfig"]
canChangeGeofenceConfig <- map["CanChangeGeofenceConfig"]
canSaveHistory <- map["CanSaveHistory"]
canViewReport <- map["CanViewReport"]
canWatchHistory <- map["CanWatchHistory"]
deliverDailyReportByEmail <- map["DeliverDailyReportByEmail"]
deliverDailyReportBySms <- map["DeliverDailyReportBySms"]
email <- map["Email"]
firm <- map["Firm"]
firmId <- map["FirmId"]
firstName <- map["FirstName"]
id <- map["Id"]
isActive <- (map["IsActive"], BooleanTransformeType(trueValue: "true", falseValue: "false"))
isAdmin <- (map["IsAdmin"], BooleanTransformeType(trueValue: "true", falseValue: "false"))
lastName <- map["LastName"]
phone <- map["Phone"]
recivesDailyReport <- map["RecivesDailyReport"]
userName <- map["UserName"]
}
}
class BooleanAtttribute: XMLMappable {
var nodeName: String!
var booleanValue: Bool?
required init(map: XMLMap) {
}
func mapping(map: XMLMap) {
booleanValue <- (map.attributes["xsi:nil"], BooleanTransformeType(trueValue: "true", falseValue: "false"))
}
}
class Firm: XMLMappable {
var nodeName: String!
var extensionData: String?
var firmTypeId: Int?
var id: Int?
var name: String?
var parentFirmId: Int?
required init(map: XMLMap) {
}
func mapping(map: XMLMap) {
extensionData <- map["ExtensionData"]
firmTypeId <- map["FirmTypeId"]
id <- map["Id"]
name <- map["Name"]
parentFirmId <- map["ParentFirmId"]
}
}
class BooleanTransformeType<T: Equatable>: XMLTransformType {
typealias Object = Bool
typealias XML = T
private var trueValue: T
private var falseValue: T
init(trueValue: T, falseValue: T) {
self.trueValue = trueValue
self.falseValue = falseValue
}
func transformFromXML(_ value: Any?) -> Bool? {
if let value = value as? T {
return value == trueValue
}
return nil
}
func transformToXML(_ value: Bool?) -> T? {
if value == true {
return trueValue
}
return falseValue
}
}
并使用 XMLMapper
class 将 XML 字符串映射到模型对象中:
let userDTO = XMLMapper<UserDTO>().map(XMLString: xmlString)
或者,您可以使用 Requests 子规范和 responseXMLObject(completionHandler:)
函数将响应直接映射到模型对象中:
Alamofire.request("http://my-web-service-domain.com", method: .get).responseXMLObject { (response: DataResponse<UserDTO>) in
let userDTO = response.result.value
print(userDTO?.id ?? "nil")
}
希望有用。
如果你需要在 Alamofire 中使用 不同的解码器(JSON、URL、XML),最好和最简单的方法我发现正在使用 XMLCoder.
- Alamofire 5
- Swift 5
(它可能适用于旧版本)
在Alamofire的响应解码方法上,你只需要使用XMLDecoder()
@discardableResult
public func responseDecodable<T: Decodable>(of type: T.Type = T.self,
...
decoder: DataDecoder = JSONDecoder(),
...
completionHandler: @escaping (AFDataResponse<T>) -> Void) -> Self {
像这样:
import XMLCoder
...
dataRequest
.validate()
.responseDecodable(of: T.self, decoder: XMLDecoder()) { (response: DataResponse<T, AFError>) in
你的模型只需要符合 Codable 协议。
import Foundation
class ReportModel: Codable {
var connections: ConnectionModel?
var notifications: NotificationsModel?
enum CodingKeys: String, CodingKey {
case connections
case notifications
}
}
我创建了一个 GIST,其中包含如何使用 Alamofire 解码 XML 的完整结构,我添加了一些带有嵌套对象和 XML 属性的示例.
我开始在我当前的 ios 项目中使用 cocoapods。我需要使用 SOAP 以简单的方式为我的 ios 项目获取内容。我用谷歌搜索了一下,Alamofire pod 对我来说很棒。因为我使用的是Swift编程语言。
我已经轻松地启动了这个 pod。但是我的网络服务 return 我 XML 结果。我想序列化以排列此 XML 结果。但是我不能。
当我用浏览器调用我的网络服务时,我得到了这种结果
Alamofire的响应方式是这样的:
Alamofire.request(.GET, "http://my-web-service-domain.com", parameters: nil)
.response { (request, response, data, error) in
println(request)
println(response)
println(error)
}
当我运行这个方法时,我在终端上看到这个输出:
<NSMutableURLRequest: 0x170010a30> { URL: http://my-web-service-domain.com }
Optional(<NSHTTPURLResponse: 0x1704276c0> { URL: http://my-web-service-domain.com } { status code: 200, headers {
"Cache-Control" = "private, max-age=0";
"Content-Length" = 1020;
"Content-Type" = "text/xml; charset=utf-8";
Date = "Thu, 18 Jun 2015 10:57:07 GMT";
Server = "Microsoft-IIS/7.5";
"X-AspNet-Version" = "2.0.50727";
"X-Powered-By" = "ASP.NET";
} })
nil
我想得到一个数组的结果,该数组在浏览器上显示我的情节提要。 谁能帮助我如何使用 Alamofire 框架或 Swift 语言序列化这些数据?
如果我没有误解你的描述,我想你会想要得到 XML 数据并解析它,对吧?关于这一点,您可能会在响应回调中处理错误的变量。您应该 println(data)
查看 XML 文档。
解析XML数据,可以考虑SWXMLHash。 Alamofire 请求可能如下所示:
Alamofire.request(.GET, "http://my-web-service-domain.com", parameters: nil)
.response { (request, response, data, error) in
println(data) // if you want to check XML data in debug window.
var xml = SWXMLHash.parse(data!)
println(xml["UserDTO"]["FilmID"].element?.text) // output the FilmID element.
}
有关XML管理的更多信息,请查看SWXMLHash。
使用截至 2015 年 9 月的 Alamofire 3.0 当前版本和 Xcode 7.
下面的实现的优点是不使用额外的外部库,例如 SWXMLHash
Alamofire.request(.GET, urlString, encoding: .PropertyList(.XMLFormat_v1_0, 0)).responsePropertyList { request, response, result in
//Note that result have two properties: error and value as of Alamofire 3.0, check the migration guide for more info
if let error = result.error {
print("Error: \(error)")
// parsing the data to an array
} else if let array = result.value as? [[String: String]] {
if array.isEmpty {
print("No data")
} else {
//Do whatever you want to do with the array here
}
}
}
Alamofire 4.x - Swift 3.x:
(请注意,在这个例子中我使用了 URLEncoding.default
而不是 URLEncoding.xml
因为 xml
参数排除了传递参数和 headers 的可能性,所以default
比较舒服。)
let url = "https://httpbin.org/get"
let parameters: Parameters = ["foo": "bar"]
let headers: HTTPHeaders = [
"Authorization": "Basic QWxhZGRpbjpvcGVuIHNlc2FtZQ==",
"Accept": "application/json"
]
Alamofire.request(url, method: .get, parameters: parameters, encoding: URLEncoding.default, headers: headers)
.responseString { response in
print(" - API url: \(String(describing: response.request!))") // original url request
var statusCode = response.response?.statusCode
switch response.result {
case .success:
print("status code is: \(String(describing: statusCode))")
if let string = response.result.value {
print("XML: \(string)")
}
case .failure(let error):
statusCode = error._code // statusCode private
print("status code is: \(String(describing: statusCode))")
print(error)
}
}
Alamofire 3.0 2015 年 10 月和 Xcode 7 根据 3.0.0-beta.3 README and the Alamofire 3.0 Migration Guide。
对我来说正确的语法是:
Alamofire.request(.GET, url, parameters: params, encoding: ParameterEncoding.URL).responsePropertyList { response in
if let error = response.result.error {
print("Error: \(error)")
// parsing the data to an array
} else if let array = response.result.value as? [[String: String]] {
if array.isEmpty {
print("No data")
} else {
//Do whatever you want to do with the array here
}
}
}
如果你想要一个好的XML解析器,请看一看SWXMLHash。
例如:
let xml = SWXMLHash.parse(string)
我遇到了一个非常独特的问题,服务器返回了一个 XML,其中包含 JSON 作为字符串。希望对大家有帮助。
基本上 XML 看起来像这样:
<string xmlns="http://schemas.microsoft.com/2003/10/Serialization/">{"Response":{"Status":"success","Result_Count":"1","Error_Description":"","Result":{"Login_result":{"user_id":"1","user_type":"1","user_name":"h4cked","user_locked":"False","user_locked_message":""}}}}</string>
如您所见,实际的 JSON 是 {"Response":....
该解决方案仅基于 Alamofire 4.4。
你需要做的是:
- 使用
.responsePropertyList
- 检查错误
- 将值转换为数据
- 序列化为JSON对象
- 转换为字典
[String : Any]
这里是:
Alamofire.request(NetworkAPIPaths.pathForLogin(),
method: .get,
parameters: [APIParameters.userName.rawValue : "",
APIParameters.password.rawValue : ""]).responsePropertyList
{ (response : DataResponse<Any>) in
if let error = response.result.error
{
// Error...
}
else if let jsonFullString = response.result.value as? String
{
if let jsonStringAsData = jsonFullString.data(using: .utf8)
{
do
{
let jsonGhost = try JSONSerialization.jsonObject(with: jsonStringAsData, options: [])
if let actualJSON = jsonGhost as? [String : Any]
{
// actualJSON is ready to be parsed :)
}
}
catch
{
print (error.localizedDescription)
}
}
}
tsaiid 在Swift 3 和 Alamofire 4 中的回答:
Alamofire.request("http://my-web-service-domain.com", parameters: nil) //Alamofire defaults to GET requests
.response { response in
if let data = response.data {
println(data) // if you want to check XML data in debug window.
var xml = SWXMLHash.parse(data)
println(xml["UserDTO"]["FilmID"].element?.text) // output the FilmID element.
}
}
如果你想把XML映射到swift对象,你也可以考虑XMLMapper. (uses the same technique as the ObjectMapper)
通过实施 XMLMappable
协议创建模型:
class UserDTO: XMLMappable {
var nodeName: String!
var extensionData: String?
var canChangeDeviceConfig: BooleanAtttribute?
var canChangeDriverConfig: BooleanAtttribute?
var canChangeFleetConfig: BooleanAtttribute?
var canChangeGeofenceConfig: BooleanAtttribute?
var canSaveHistory: BooleanAtttribute?
var canViewReport: BooleanAtttribute?
var canWatchHistory: BooleanAtttribute?
var deliverDailyReportByEmail: BooleanAtttribute?
var deliverDailyReportBySms: BooleanAtttribute?
var email: String?
var firm: String?
var firmId: Int?
var firstName: String?
var id: Int?
var isActive: Bool?
var isAdmin: Bool?
var lastName: String?
var phone: String?
var recivesDailyReport: BooleanAtttribute?
var userName: String?
required init(map: XMLMap) {
}
func mapping(map: XMLMap) {
extensionData <- map["ExtensionData"]
canChangeDeviceConfig <- map["CanChangeDeviceConfig"]
canChangeDriverConfig <- map["CanChangeDriverConfig"]
canChangeFleetConfig <- map["CanChangeFleetConfig"]
canChangeGeofenceConfig <- map["CanChangeGeofenceConfig"]
canSaveHistory <- map["CanSaveHistory"]
canViewReport <- map["CanViewReport"]
canWatchHistory <- map["CanWatchHistory"]
deliverDailyReportByEmail <- map["DeliverDailyReportByEmail"]
deliverDailyReportBySms <- map["DeliverDailyReportBySms"]
email <- map["Email"]
firm <- map["Firm"]
firmId <- map["FirmId"]
firstName <- map["FirstName"]
id <- map["Id"]
isActive <- (map["IsActive"], BooleanTransformeType(trueValue: "true", falseValue: "false"))
isAdmin <- (map["IsAdmin"], BooleanTransformeType(trueValue: "true", falseValue: "false"))
lastName <- map["LastName"]
phone <- map["Phone"]
recivesDailyReport <- map["RecivesDailyReport"]
userName <- map["UserName"]
}
}
class BooleanAtttribute: XMLMappable {
var nodeName: String!
var booleanValue: Bool?
required init(map: XMLMap) {
}
func mapping(map: XMLMap) {
booleanValue <- (map.attributes["xsi:nil"], BooleanTransformeType(trueValue: "true", falseValue: "false"))
}
}
class Firm: XMLMappable {
var nodeName: String!
var extensionData: String?
var firmTypeId: Int?
var id: Int?
var name: String?
var parentFirmId: Int?
required init(map: XMLMap) {
}
func mapping(map: XMLMap) {
extensionData <- map["ExtensionData"]
firmTypeId <- map["FirmTypeId"]
id <- map["Id"]
name <- map["Name"]
parentFirmId <- map["ParentFirmId"]
}
}
class BooleanTransformeType<T: Equatable>: XMLTransformType {
typealias Object = Bool
typealias XML = T
private var trueValue: T
private var falseValue: T
init(trueValue: T, falseValue: T) {
self.trueValue = trueValue
self.falseValue = falseValue
}
func transformFromXML(_ value: Any?) -> Bool? {
if let value = value as? T {
return value == trueValue
}
return nil
}
func transformToXML(_ value: Bool?) -> T? {
if value == true {
return trueValue
}
return falseValue
}
}
并使用 XMLMapper
class 将 XML 字符串映射到模型对象中:
let userDTO = XMLMapper<UserDTO>().map(XMLString: xmlString)
或者,您可以使用 Requests 子规范和 responseXMLObject(completionHandler:)
函数将响应直接映射到模型对象中:
Alamofire.request("http://my-web-service-domain.com", method: .get).responseXMLObject { (response: DataResponse<UserDTO>) in
let userDTO = response.result.value
print(userDTO?.id ?? "nil")
}
希望有用。
如果你需要在 Alamofire 中使用 不同的解码器(JSON、URL、XML),最好和最简单的方法我发现正在使用 XMLCoder.
- Alamofire 5
- Swift 5
(它可能适用于旧版本)
在Alamofire的响应解码方法上,你只需要使用XMLDecoder()
@discardableResult
public func responseDecodable<T: Decodable>(of type: T.Type = T.self,
...
decoder: DataDecoder = JSONDecoder(),
...
completionHandler: @escaping (AFDataResponse<T>) -> Void) -> Self {
像这样:
import XMLCoder
...
dataRequest
.validate()
.responseDecodable(of: T.self, decoder: XMLDecoder()) { (response: DataResponse<T, AFError>) in
你的模型只需要符合 Codable 协议。
import Foundation
class ReportModel: Codable {
var connections: ConnectionModel?
var notifications: NotificationsModel?
enum CodingKeys: String, CodingKey {
case connections
case notifications
}
}
我创建了一个 GIST,其中包含如何使用 Alamofire 解码 XML 的完整结构,我添加了一些带有嵌套对象和 XML 属性的示例.