简体   繁体   中英

Getting JSON From SOAP Response

I am new in making requests to soap APIs and extracting data from them. I would like to know how I can parse the Json data from this Soap response:

<?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope   xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <soapenv:Body>[{"nationalid":"2135199186","countrylist":[{"countryCode":"AFG","CountryName":"Afghanistan"},{"countryCode":"DZA","CountryName":"Algeria"},{"countryCode":"BHR","CountryName":"Bahrain"},{"countryCode":"COM","CountryName":"Comoros"},{"countryCode":"DJI","CountryName":"Djibouti"},{"countryCode":"EGY","CountryName":"Egypt"},{"countryCode":"ERI","CountryName":"Eritrea"},{"countryCode":"IRQ","CountryName":"Iraq"},{"countryCode":"JOR","CountryName":"Jordan"},{"countryCode":"KWT","CountryName":"Kuwait"},{"countryCode":"LBN","CountryName":"Lebanon"},{"countryCode":"LBY","CountryName":"Libyan Arab Jamahiriya"},{"countryCode":"MRT","CountryName":"Mauritania"},{"countryCode":"MAR","CountryName":"Morocco"},{"countryCode":"OMN","CountryName":"Oman"},{"countryCode":"PAK","CountryName":"Pakistan"},{"countryCode":"PSE","CountryName":"Palestinian Territory, Occupie"},{"countryCode":"QAT","CountryName":"Qatar"},{"countryCode":"SOM","CountryName":"Somalia"},{"countryCode":"SDN","CountryName":"Sudan"},{"countryCode":"SYR","CountryName":"Syrian Arab Republic"},{"countryCode":"TUN","CountryName":"Tunisia"},{"countryCode":"ARE","CountryName":"United Arab Emirates"},{"countryCode":"YEM","CountryName":"Yemen"}],"isError":false}]</soapenv:Body>
</soapenv:Envelope>

EDIT:

Request packet looks like this:

    <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:name="http://www.example.org/Name">
    <soapenv:Header><wsse:Security soapenv:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
   <wsse:UsernameToken> 
   <wsse:Username>UODA_GUEST</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">@password123</wsse:Password>
   </wsse:UsernameToken>
 </wsse:Security>
   </soapenv:Header> 
   <soapenv:Body>
      <Name>
         <NATIONAL_ID>2135199186</NATIONAL_ID>
         <SEC_KEY>1adb445f8815e450b25addad899cab156e63088c</SEC_KEY>
         <LANG_CODE>ENG</LANG_CODE>
         <SEC_CODE>@password123</SEC_CODE>
      </Name>
   </soapenv:Body>
</soapenv:Envelope>

For the api url: http://pscstestserver.iau.edu.sa:8888/PSIGW/PeopleSoftServiceListeningConnector/U_COUNTRYLIST_ADM.1.wsdl

The response looks like this:

    <?xml version="1.0" encoding="UTF-8"?>
<soapenv:Envelope   xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
    <soapenv:Body>[{"nationalid":"2135199186","countrylist":[{"countryCode":"AFG","CountryName":"Afghanistan"},{"countryCode":"DZA","CountryName":"Algeria"},{"countryCode":"BHR","CountryName":"Bahrain"},{"countryCode":"COM","CountryName":"Comoros"},{"countryCode":"DJI","CountryName":"Djibouti"},{"countryCode":"EGY","CountryName":"Egypt"},{"countryCode":"ERI","CountryName":"Eritrea"},{"countryCode":"IRQ","CountryName":"Iraq"},{"countryCode":"JOR","CountryName":"Jordan"},{"countryCode":"KWT","CountryName":"Kuwait"},{"countryCode":"LBN","CountryName":"Lebanon"},{"countryCode":"LBY","CountryName":"Libyan Arab Jamahiriya"},{"countryCode":"MRT","CountryName":"Mauritania"},{"countryCode":"MAR","CountryName":"Morocco"},{"countryCode":"OMN","CountryName":"Oman"},{"countryCode":"PAK","CountryName":"Pakistan"},{"countryCode":"PSE","CountryName":"Palestinian Territory, Occupie"},{"countryCode":"QAT","CountryName":"Qatar"},{"countryCode":"SOM","CountryName":"Somalia"},{"countryCode":"SDN","CountryName":"Sudan"},{"countryCode":"SYR","CountryName":"Syrian Arab Republic"},{"countryCode":"TUN","CountryName":"Tunisia"},{"countryCode":"ARE","CountryName":"United Arab Emirates"},{"countryCode":"YEM","CountryName":"Yemen"}],"isError":false}]</soapenv:Body>
</soapenv:Envelope>

I'm creating a request like this:

        static func createServiceRequest(params : Dictionary<String,String>, serviceName:String, urlString: String, method: String) -> URLRequest {
        var parameters : String = ""
        for (key, param) in params {
            parameters = "\(parameters)<\(key)>\(param)</\(key)>"
        } 
        let soapMessage =  "<Envelope xmlns=\"http://schemas.xmlsoap.org/soap/envelope/\"><Body><\(serviceName) xmlns=\"http://ud.edu.sa/api/ldap\">\(parameters)</\(serviceName)></Body></Envelope>"
        let soapLenth = String(soapMessage.count)
        let theURL = URL(string: urlString)
        var mutableR = URLRequest(url: theURL!) 
        // MUTABLE REQUEST
        mutableR.addValue("text/xml; charset=utf-8", forHTTPHeaderField: "Content-Type")
        mutableR.addValue("text/html; charset=utf-8", forHTTPHeaderField: "Content-Type")
        mutableR.addValue(soapLenth, forHTTPHeaderField: "Content-Length")
        mutableR.httpMethod = method
        mutableR.httpBody = soapMessage.data(using: String.Encoding.utf8)
        return mutableR
    }
}

Then creating a url session and using Stimorol's XMLElementExtractor class :

    func fetchJsonFor(request: URLRequest, completion: @escaping ((Any?) -> Void)){ 
    let task = URLSession.shared.dataTask(with: request) { (data, response, error) in
        if error != nil{
            print(error?.localizedDescription ?? "Error")
            completion(nil)
        }
        guard let data = data else{
            completion(nil)
            return
        }
        let jsonString = XMLElementExtractor.extractElement("soapenv:Body", fromXML: data) ?? "NO JSON STRING"
        print("JSON STRING:") 
        print(jsonString)
    }
    task.resume()
}

But I get jsonString showing nothing with jsonString.count = 1

EDIT:

print(String(data: data, encoding: .utf8) ?? "NO UTF8 DATA")

Will print the text in this screenshot:

在此处输入图片说明

Apparently, I need to do extra steps to execute this line

<wsdl:operation name="U_COUNTRYLIST"

because when I click the U_COUNTRYLIST button on the top corner of the screenshot, another screen comes up. Then, when I paste the entire request packet in that screen, I get the end soap response with desired json in it.

you can use this XML parsing Like this one AEXML

Just check this

print(String(describing: xmlDoc.root["soapenv:Body"].value))

here is code

import UIKit
import AEXML

class ViewController: UIViewController {


    override func viewDidLoad() {
        super.viewDidLoad()

        // example from README.md
        guard
            let xmlPath = Bundle.main.path(forResource: "example", ofType: "xml"),
            let data = try? Data(contentsOf: URL(fileURLWithPath: xmlPath))
        else {
            print("resource not found!")
            return
        }

        // example of using NSXMLParserOptions
        var options = AEXMLOptions()
        options.parserSettings.shouldProcessNamespaces = false
        options.parserSettings.shouldReportNamespacePrefixes = false
        options.parserSettings.shouldResolveExternalEntities = false

        do {
            let xmlDoc = try AEXMLDocument(xml: data, options: options)

            // prints the same XML structure as original
            print(xmlDoc.xml)

            // prints cats, dogs
            for child in xmlDoc.root.children {
                print(child.name)
            }

          print(String(describing: xmlDoc.root["soapenv:Body"].value)) // Print your REsponse


        }
        catch {
            print("\(error)")
        }
    }
}

In case you don't want external dependencies and the only XML element you need is this Body , you can make simple parser for this:

import Foundation

final class XMLElementExtractor: NSObject, XMLParserDelegate {
    private var isTarget = false
    private var value: String?
    private let elementName: String

    private init(elementName: String) {
        self.elementName = elementName
    }

    static func extractElement(_ elementName: String, fromXML data: Data) -> String? {
        let extractor = XMLElementExtractor(elementName: elementName)
        let parser = XMLParser(data: data)
        parser.delegate = extractor
        parser.parse()
        return extractor.value
    }

    func parser(_ parser: XMLParser, didStartElement elementName: String, namespaceURI: String?, qualifiedName qName: String?, attributes attributeDict: [String : String] = [:]) {
        isTarget = elementName == self.elementName
    }

    func parser(_ parser: XMLParser, foundCharacters string: String) {
        if isTarget {
            value = value?.appending(string) ?? string
        }
    }

    func parser(_ parser: XMLParser, didEndElement elementName: String, namespaceURI: String?, qualifiedName qName: String?) {
        if elementName == self.elementName {
            parser.abortParsing()
        }
    }
}

let jsonString = XMLElementExtractor.extractElement("soapenv:Body", fromXML: data)

Then just parse returned string using Codable or JSONSerialization .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM