web-dev-qa-db-fra.com

Gestion des données XML avec Alamofire dans Swift

J'ai commencé à utiliser des cocoapodes avec mon projet iOS actuel. Je dois utiliser SOAP pour obtenir du contenu de manière simple pour mon projet ios. Je l'ai googlé et Alamofire pod est idéal pour moi. Parce que j'utilise le langage de programmation Swift.

J'ai inité facilement ce pod. Mais mes services Web me renvoient un résultat XML. Et je veux sérialiser pour obtenir ce résultat XML. Mais je ne peux pas.

Lorsque j'appelle mon service Web avec un navigateur, j'obtiens ce genre de résultat.

enter image description here

La méthode de réponse Alamofire est la suivante:

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

Lorsque je lance cette méthode, je vois cette sortie sur le 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

Je veux obtenir un résultat sur un tableau qui se trouve sur le navigateur afin d'afficher mon storyboard ... Quelqu'un peut-il m'aider à mettre en série ces données avec le framework Alamofire ou le langage Swift?

17
Mehmet

Si je ne comprenais pas mal votre description, je pense que vous aimeriez obtenir les données XML et les analyser, n'est-ce pas? En ce qui concerne cela, vous pouvez gérer des variables erronées dans le rappel de réponse. Vous devriez println(data) pour vérifier le document XML. 

Pour analyser les données XML, vous pouvez envisager SWXMLHash . La requête Alamofire pourrait ressembler à: 

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

Pour plus d’informations sur la gestion XML, veuillez vérifier SWXMLHash .

19
tsaiid

Alamofire 4.x - Swift 3.x:

(Veuillez noter que dans cet exemple, j'ai utilisé URLEncoding.default au lieu de URLEncoding.xml car le paramètre xml exclut la possibilité de passer des paramètres et des en-têtes, donc default est plus confortable.)

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 octobre 2015 et Xcode 7 selon le 3.0.0-beta.3 README et le Guide de migration Alamofire 3.0

Pour moi, la syntaxe correcte est la suivante:

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

Si vous voulez un bon analyseur XML, jetez un œil à SWXMLHash .

Un exemple pourrait être: let xml = SWXMLHash.parse(string)

7

Utilisation de la version actuelle d’Alamofire 3.0 à compter de septembre 2015 et de Xcode 7.

L'implémentation ci-dessous présente l'avantage de ne pas utiliser de bibliothèque externe supplémentaire telle que 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
    }
  }
}
6
irkinosor

Si vous souhaitez mapper le XML sur des objets Swift, vous pouvez également considérer XMLMapper . (utilise la même technique que ObjectMapper )

Créez votre modèle en implémentant le protocole 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
    }
}

Et utilisez la classe XMLMapper pour mapper la chaîne XML dans les objets de modèle:

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

Vous pouvez également utiliser Requests subspec et la fonction responseXMLObject(completionHandler:) pour mapper la réponse directement dans les objets du modèle:

Alamofire.request("http://my-web-service-domain.com", method: .get).responseXMLObject { (response: DataResponse<UserDTO>) in
    let userDTO = response.result.value
    print(userDTO?.id ?? "nil")
}

J'espère que c'est utile.

2
gcharita

J'ai eu un problème vraiment unique où le serveur a renvoyé un XML qui a un JSON comme chaîne J'espère que ça va aider quelqu'un.

En gros, le XML ressemblait à ceci:

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

Comme vous pouvez le voir, le JSON réel est le {"Response":....

La solution est basée uniquement sur Alamofire 4.4.

Ce que vous devez faire est la suivante:

  1. Utilisez le .responsePropertyList
  2. Vérifier l'erreur
  3. Convertir la valeur en données
  4. Sérialiser sur un objet JSON
  5. Cast vers le dictionnaire [String : Any]

C'est ici:

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

la réponse de tsaiid dans Swift 3 et 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.
        }
     }
0
Jason