在swift中处理XML解析的响应

时间:2016-11-29 15:44:26

标签: ios xml swift web-services

以下是我使用我的集成密钥,用户名和密码向我的Web服务发送SOAP消息的代码。我能够获得响应并将其一直解析为foundCharacters。

现在我需要存储在解析后的响应中找到的两个元素,以便稍后我可以将它们用于另一个请求。

我一直在寻找各种教程,但我无法理解这些教程,因为大多数都是关于本地存储的XML文件,而不是真正的WebService。

class LoginCentralViewController: UIViewController, XMLParserDelegate, NSURLConnectionDelegate {

    var chaveWS = ChaveWebService().chave()
    var mutableData:NSMutableData = NSMutableData()
    var currentElement:NSString = ""

    @IBAction func btnAcessarACTION(_ sender: Any) {
        let soapMessage = "<soapenv:Envelope xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance' xmlns:xsd='http://www.w3.org/2001/XMLSchema' xmlns:soapenv='http://schemas.xmlsoap.org/soap/envelope/' xmlns:log='LoginCentral'><soapenv:Header/><soapenv:Body><log:LoginCentral soapenv:encodingStyle='http://schemas.xmlsoap.org/soap/encoding/'><Autenticacao xsi:type='urn:Autenticacao' xmlns:urn='urn:RouterBoxMobile'><ChaveIntegracao xsi:type='xsd:string'>\(chaveWS)</ChaveIntegracao></Autenticacao><DadosLoginCentral xsi:type='urn:DadosLoginCentral' xmlns:urn='urn:RouterBoxMobile'><Usuario xsi:type='xsd:string'>wagner</Usuario><Senha xsi:type='xsd:string'>mudar123</Senha></DadosLoginCentral></log:LoginCentral></soapenv:Body></soapenv:Envelope>"

        let urlString = "https://example.com?wsdl"

        let url = NSURL (string: urlString)

        let theRequest = NSMutableURLRequest(url: url! as URL)

        let msgLength = soapMessage.characters.count

        theRequest.addValue("text/xml; charset=utf-8", forHTTPHeaderField: "Content-Type")
        theRequest.addValue(String(msgLength), forHTTPHeaderField: "Content-Length")
        theRequest.httpMethod = "POST"
        theRequest.httpBody = soapMessage.data(using: String.Encoding.utf8, allowLossyConversion: false)

        let connection = NSURLConnection(request: theRequest as URLRequest, delegate: self, startImmediately: true)
        connection!.start()

        if (connection != nil) {
            var mutableData : Void = NSMutableData.initialize()
        }
        print("passou")

    }


    override func viewDidLoad() {
        super.viewDidLoad()

    }
    func connection(_ connection: NSURLConnection!, didReceiveResponse response: URLResponse!) {
        mutableData.length = 0;
        print("passou aqui tbm")
    }

    func connection(_ connection: NSURLConnection!, didReceiveData data: NSData!) {
        mutableData.append(data as Data)

    }


    func connectionDidFinishLoading(_ connection: NSURLConnection!)  {
        let response = NSString(data: mutableData as Data, encoding: String.Encoding.utf8.rawValue)

        let xmlParser = XMLParser(data: mutableData as Data)
        xmlParser.delegate = self
        xmlParser.parse()
        xmlParser.shouldResolveExternalEntities = true
        //print(response)

    }

    //XMLParser
    func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) {
        currentElement = elementName as NSString
        //print(elementName)
    }

    func parser(_ parser: XMLParser, foundCharacters string: String) {
        if currentElement == "LoginCentralResponse" {
            print(currentElement, string)
        }
        print(currentElement, string)
    }
}

以下是我需要存储和重用的解析响应:

ClientCode : 8
Permissions : 70,73,77,75,71,72

1 个答案:

答案 0 :(得分:3)

我发现您要在应用中存储凭据。通过编写文件,无需在XML中存储此类文件。您可以使用Keychain存储此类敏感数据,您可以随时从Keychain接收更多HTTP请求。它安全可靠。

这是我使用的钥匙串库

https://github.com/marketplacer/keychain-swift

另一个建议是,您不需要像这样解析XML这样的困难,请尝试使用它。

https://github.com/drmohundro/SWXMLHash

您的SOAP Web服务代码似乎已过时。它是一种罕见的网络服务,我们大部分时间都不会使用它和罕见的文档。现在,人们正在转向REST。您正在使用在iOS 8中弃用的NSURLConnection。因此,让我们开始使用URLSession。我会在这里使用Delegate Pattern。我让你的答案非常简单,让你明白。您可以更改任何想要处理响应的内容。

所以,我有两个Swift类。一个是ViewController.swift,另一个是SOAPService.swift

  

以下是我们将如何使用委托模式处理SOAPService。

import Foundation
import SWXMLHash

// At here you define your constants at global variables, or you can use structs
public let verify_token = "VerifyToken"
public let WSDL_URL = "https://api.example.com/services?wsdl"
public let BASE_URL = "https://api.example.com/"
public let VERIFY_TOKEN = BASE_URL + "VerifyToken"

// Creating protocol for data transfering
protocol SOAPServiceProtocol{
    func didSuccessRequest(results : String, requestName : String)
    func didFailRequest(err : String, requestName : String)
}

// I have extended the URLSessionDelegate and URLSessionTaskDelegate for passing TLS, so you might not needed until you handle HTTPS
class SOAPService : NSObject, URLSessionDelegate, URLSessionTaskDelegate{

// Here the initialization of delegate pattern to transfer data between classes
var delegate : SOAPServiceProtocol
init(delegate : SOAPServiceProtocol){
    self.delegate=delegate
}

func post(wsdlURL : String, soapAction : String, soapMessage : String, serviceName : String, method : String){

    // Here your request configurations
    var request = URLRequest(url: URL(string: wsdlURL)!)
    let msgLength  = String(soapMessage.characters.count)

    // Configure your soap message here
    let data = soapMessage.data(using: String.Encoding.utf8, allowLossyConversion: false)

    // Setting HTTP Header,Body and Method
    request.httpMethod = method
    request.addValue("text/xml; charset=utf-8", forHTTPHeaderField: "Content-Type")
    request.addValue(msgLength, forHTTPHeaderField: "Content-Length")
    request.addValue(soapAction, forHTTPHeaderField: "SOAPAction")
    request.httpBody = data

    // URLSession configuration such as TIME OUT,etc
    let urlconfig = URLSessionConfiguration.default
    urlconfig.timeoutIntervalForRequest = 15
    urlconfig.timeoutIntervalForResource = 15

    // Initiating URLSession before making a request, I will use default here
    var session = URLSession.shared
    session = URLSession(configuration: urlconfig, delegate: nil, delegateQueue: nil)

    // Start HTTP Request
    let task = session.dataTask(with: request) {
        data, response, error in

        if error != nil {
            // If error include,return fail
            self.delegate.didFailRequest(err: "Request failed", requestName: serviceName)
            return
        }

        guard let datastring = String(data: data!, encoding:String.Encoding(rawValue: String.Encoding.utf8.rawValue)) else{
            return self.delegate.didFailRequest(err: "No Data", requestName: verify_token)
        }

        let xml = SWXMLHash.parse(datastring)

        guard let xmlResult : String = xml["soap:Envelope"]["soap:Body"]["\(serviceName)Response"]["\(serviceName)Result"].element?.text else{
            print("XML is NIL")
            self.delegate.didFailRequest(err: "XML is NIL", requestName: verify_token)
            return
        }

        // when parsing complete return the parse result
        self.delegate.didSuccessRequest(results: xmlResult, requestName: verify_token)

    }
    task.resume()

}

// Start Writing Your SOAP Services and messages HERE
func doVerify(userName : String, password : String, methodName : String){
    let soapMessage = String(format:"<?xml version=\"1.0\" encoding=\"UTF-8\"?><SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:ns1=\"https://api.example.com/\"><SOAP-ENV:Body><ns1:VerifyToken><ns1:UserName>%@</ns1:UserName><ns1:Password>%@</ns1:Password></ns1:VerifyToken></SOAP-ENV:Body></SOAP-ENV:Envelope>",userName,password)

    post(wsdlURL: WSDL_URL, soapAction: VERIFY_TOKEN, soapMessage: soapMessage, serviceName: verify_token, method: "POST")
}

}

因此,我们将使用 URLSession 处理 SOAP 网络服务。

  

那么,我们如何从ViewController获取响应数据?

这很容易。我们在这里实施协议方法。

import UIKit

class ViewController: UIViewController, SOAPServiceProtocol{

var soapService : SOAPService?

override func viewDidLoad() {
    super.viewDidLoad()

    // You need to initialize the SOAP Service to call SOAP Web Service.
    soapService = SOAPService(delegate: self)

    // Do any additional setup after loading the view, typically from a nib.
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

@IBAction func doVerify(sender : AnyObject){
    // Here I started HTTP Request
    soapService?.doVerify(userName: "Thiha6245", password: "dsadafwa", methodName: verify_token)
}

// Here you implement the results which success
func didSuccessRequest(results : String, requestName: String) {
    print("Results : \(results)")
    switch requestName {
    case verify_token:
        // do handling xml parsing from result to model object and get data from model
        break
    default :
        break
    }
}

// Here you implement the failure
func didFailRequest(err: String, requestName: String) {
    print("Error : \(err)")
    switch requestName {
    case verify_token:
        // do error handling here // Request TIME OUT,Internet connection error or data error,etc
        break
    default :
        break
    }
}

}
  

什么是SOAP消息?像REST一样,我们必须向每个人发送参数   特定服务权?

eg. "www.api.com/services/verifytoken?username=Thiha&password=dwadwdada"
(BASE_URL/SOAPAction?ParamName1=""&ParamName2="")
[GET Request in REST Web Service]
  

为了在SOAP中请求HTTP,您必须编写SOAP消息   为了让SOAP Web服务理解

<?xml version=\"(Here your SOAP Version)\" encoding=\"UTF-8\"?>
<SOAP-ENV:Envelope xmlns:SOAP-ENV=\"http://schemas.xmlsoap.org/soap/envelope/\" xmlns:ns1=\"(Your API Base URL)/\">
   <SOAP-ENV:Body>
       <ns1:(SOAPAction)>
          <ns1: ParamName1>""</ns1: ParamName1>
          <ns1: ParamName2>""</ns1: ParamName2>
       </ns1:(SOAPAction)>
   </SOAP-ENV:Body>
</SOAP-ENV:Envelope>

我希望它可以帮到你。由于您是初学者,我建议您阅读有关NSURLSession的文档以进行进一步配置,并阅读如何使用我提到的SWXMLHash解析XML。祝你好运!