ios 在 Swift 中使用 Alamofire 处理 XML 数据

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/30913594/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-31 06:29:04  来源:igfitidea点击:

Handling XML data with Alamofire in Swift

iosxmlswiftalamofire

提问by Mehmet

I started to use cocoapods with my current ios project. I need to use SOAP to get content with easy way for my ios project. I have googled it and Alamofire pod is great for me. Because I am using Swift programming language.

我开始在我当前的 ios 项目中使用 cocoapods。我需要使用 SOAP 以简单的方式为我的 ios 项目获取内容。我在谷歌上搜索过它,Alamofire pod 对我来说很棒。因为我使用的是 Swift 编程语言。

I have inited easily this pod. But my web services return me XML result. And I want to serialisation to array this XML result. But I can't.

我已经很容易地初始化了这个 pod。但是我的 Web 服务返回 XML 结果。我想序列化来排列这个 XML 结果。但我不能。

When I call my web service with a browser I get this kind of result

当我用浏览器调用我的网络服务时,我得到了这种结果

enter image description here

在此处输入图片说明

Alamofire response method is like this:

Alamofire 响应方法是这样的:

Alamofire.request(.GET, "http://my-web-service-domain.com", parameters: nil)
         .response { (request, response, data, error) in
                     println(request)
                     println(response)
                     println(error)
                   }

When I run this method I see this output on the terminal:

当我运行这个方法时,我会在终端上看到这个输出:

<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

I want to get result to an array which see on browser to show my storyboard. Can anybody help me how to serialise this data with Alamofire framework or Swift language?

我想将结果发送到在浏览器上看到的数组以显示我的故事板。有人可以帮助我如何使用 Alamofire 框架或 Swift 语言序列化这些数据吗?

回答by tsaiid

If I did not misunderstand your description, I think you would like to get the XML data and parse it, right? Regarding to this, you may handle with wrong variables in the response callback. You should println(data)to check the XML document.

如果我没有误解你的描述,我想你会想要获取 XML 数据并解析它,对吧?对此,您可能会在响应回调中处理错误的变量。您应该println(data)检查 XML 文档。

For parsing XML data, you could consider SWXMLHash. The Alamofire request could look like:

对于解析 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.
         }

Further information about XML management, please check SWXMLHash.

有关 XML 管理的更多信息,请查看SWXMLHash

回答by Alessandro Ornano

Alamofire 4.x - Swift 3.x:

Alamofire 4.x - Swift 3.x

(please note that in this example I've used URLEncoding.defaultinstead of URLEncoding.xmlbecause the xmlparameter exclude the possibility to pass parameters and headers, so defaultis more confortable.)

(请注意,在这个例子中我使用了URLEncoding.default而不是URLEncoding.xml因为xml参数排除了传递参数和标题的可能性,所以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.0october 2015 and Xcode 7 according to the 3.0.0-beta.3 READMEand the Alamofire 3.0 Migration Guide.

Alamofire 3.0根据3.0.0-beta.3 2015年10月和7的Xcode自述Alamofire 3.0迁移指南

For me the correct syntax is:

对我来说,正确的语法是:

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
                }
            }
        }

If you want a good XMLparser, please take a look to SWXMLHash.

如果您想要一个好的XML解析器,请查看SWXMLHash

An example could be: let xml = SWXMLHash.parse(string)

一个例子可能是: let xml = SWXMLHash.parse(string)

回答by irkinosor

Using Alamofire 3.0 current version as of Sept 2015 and Xcode 7.

使用截至 2015 年 9 月的 Alamofire 3.0 当前版本和 Xcode 7。

The implementation bellow has the advantage of not using an additional external library such as SWXMLHash

下面的实现的优点是不使用额外的外部库,如 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
    }
  }
}

回答by gcharita

If you want to map the XML to swift objects, you may also consider XMLMapper. (uses the same technique as the ObjectMapper)

如果你想将 XML 映射到 swift 对象,你也可以考虑 XMLMapper。(使用与ObjectMapper相同的技术)

Create your model by implementing XMLMappableprotocol:

通过实现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
    }
}

And use the XMLMapperclass to map the XML string into the model objects:

并使用XMLMapper该类将 XML 字符串映射到模型对象中:

let userDTO = XMLMapper<UserDTO>().map(XMLString: xmlString)

Altenatively you can use Requestssubspec and the responseXMLObject(completionHandler:)function to map the response directly into the model objects:

或者,您可以使用Requestssubspec 和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")
}

I hope this is useful.

我希望这是有用的。

回答by OhadM

I had a really unique issue where the server returned an XML that has a JSON as a string. Hope it will help someone.

我遇到了一个非常独特的问题,即服务器返回了一个以 JSON 为字符串的 XML。希望它会帮助某人。

Basically the XML looked like this:

基本上 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>

As you can see the actual JSON is the {"Response":....

如您所见,实际的 JSON 是 {"Response":....

The solution is based only on Alamofire 4.4.

该解决方案仅基于 Alamofire 4.4。

What you need to do is this:

你需要做的是:

  1. Use the .responsePropertyList
  2. Check for error
  3. Convert the value to Data
  4. Serialize to JSON object
  5. Cast to Dictionary [String : Any]
  1. 使用 .responsePropertyList
  2. 检查错误
  3. 将值转换为数据
  4. 序列化为 JSON 对象
  5. 投射到字典 [String : Any]

Here it is:

这里是:

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)
             }
        }
    }

回答by Jason

tsaiid's answer in Swift 3 and Alamofire 4:

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.
        }
     }