2016-11-29 49 views
2

以下是我用集成密钥,用户名和密码向我的Web服务发送SOAP消息的代码。我能够得到响应并将其解析为foundCharacters。在swift中处理XML解析的响应

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

我一直在寻找各地的教程,但我不能安静地理解这些教程,因为它们大多数都是关于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 

回答

2

我看到你想你的应用程序中保存的凭证。通过编写文件,不需要在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 Web服务。

那么,我们如何从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] 

为了请求HTTP的SOAP,你必须写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。祝你好运!

+0

我对常量有一些疑问。 public let verify_token =“VerifyToken”<<我有一个安全令牌来授权连接,但它必须在soap消息中发送,就像userName和password一样,还是我误解了它? –

+0

不,这些变量只是一个让你理解的例子,包括SOAP消息。 –

+0

在SOAP中,有SOAPAction,BASE_URL和WSDL_URL的权利吗?这就是为什么我让它声明为常量。让我简单回顾一下 –