Weird SOAP response, is it JSON? How to parse it?
Asked Answered
R

3

3

I am using ksoap2 to consume a SOAP based web-service, and the format of the response I am getting is something like:

anyType{
    key1=value1;
    key2=value2;

    key3=anyType{

        key4=value4;
        key5=value5;
        key6= anyType{
                key7= anyType{
                    key8= value8;
                };
            };

    };

    key9=value9;
}

That is the JSON objects (if we assume that this is JSON) begin with anyType{ and end with }, keys and values are separated by =, and ; are field separators/statement terminators/whatever.

I tried to validate the response string using online validators but it failed. This points out that this is not a valid JSON object.

A similar example can be found in this question. But the accepted answer did not work for me because, well first the response string does not begin with { but with anyType{, and if I put anyType{ in the if condition, it still raises an exception next time when it encounters an anyType{ (a nested JSON object)

The second answer seems to work to some extent, but the problem is that my entire response string appears to come as a single property (since the propertyCount is 1), so when I print out the name or value of the property, the entire response string is printed.

I have googled it a lot and tried everything I could find. So I suppose I'll have to parse it myself.

My question is what is the best way to parse this kind of response.

Should I try to parse it using regex or should I convert the response string to a JSON format by replacing all occurances of anyType{ by {, = by :, ; by , etc. etc. , and then converting this string to a JSONObject by something like:

jsonObject= new JSONObject(responseString);

and then extract keys and values by something like:

Iterator itr= jsonObject.keys();

        while(itr.hasNext()) {
            String value = null; 

            String key= (String) itr.next();
            try {
                value= jsonObject.getString(key);
            } catch (JSONException e) {
                e.printStackTrace();
            }

            Log.i(TAG, key + " : " + value); 

            // ......
        }

   import java.util.Iterator;

import org.json.JSONException;
import org.json.JSONObject;

public class JSONPracticeOne {

    private static JSONObject jsonObject;

    private static String key;
    private static String value;

    public static void main(String[] args) {

        String responseString= " anyType{key1=value1;key2=value2;key3=anyType{key4=value4;key5=value5;key6=anyType{key7=anyType{key8=value8};};};key9=value9;}";

        responseString = responseString.replaceAll("anyType\\Q{\\E", "{");

        responseString = responseString.replaceAll("\\Q=\\E", ":");

        responseString = responseString.replaceAll(";", ",");

        responseString = responseString.replaceAll(",\\Q}\\E","}");

        //System.out.println(responseString); 

        //System.out.println();

        responseString= responseString.replaceAll("(:\\{)", "-"); //Replace :{ by -
        responseString= responseString.replaceAll("[:]", "\":\""); //Replace : by ":"
        responseString= responseString.replaceAll("-", "\":{\""); //Replace - back to :{

        //System.out.println(responseString);

        //System.out.println();

        responseString = responseString.replaceAll("[,]",",\"");

        //System.out.println(responseString); 

        //System.out.println();

        //String string= responseString.charAt(1) + "";  System.out.println("CHECHE " + string); 

        responseString = responseString.replaceFirst("[\\{]","{\"");

        //System.out.println(responseString);

        //System.out.println(); 

        //responseString= responseString.replaceAll("([^\\}],)","\","); // truncation

        responseString= responseString.replaceAll("(\\},)", "-"); // replace }, by -

        responseString= responseString.replaceAll(",","\","); //replace , by ",

        responseString = responseString.replaceAll("-","},"); // replace - back to },

        //System.out.println(responseString);

        //System.out.println();

        responseString = responseString.replaceAll("(?<![\\}])\\}","\"}");

        System.out.println(responseString);

        System.out.println("**********************************************************************************************\n\n");}}

OUTPUT:-

{
    "key1":"value1",
    "key2":"value2",
    "key3":{
        "key5":"value5",
        "key6":{
            "key7":{
                "key8":"value8"
            }
        },
        "key4":"value4"
    },
    "key9":"value9"
}
Rubato answered 17/6, 2014 at 16:26 Comment(7)
I dont know whatever anyone says but what you are getting is not jsonDemote
@IllegalArgument Thank you, I had reached the same conclusion after much toil, but the question (shown as bold font in the question) still being whatever will be the best way to parse it?Rubato
post your entire response parsing code is dependent on it I assume the final code will result in something like string manipulationDemote
Actually I did try something like that and posted in the question. I still have to enclose the keys and values in "; but manipulating the response string like that does not seem to be an efficient way. There must be a better way to deal with ti.Rubato
Can you tell what you want to parse out? Is key8 enough while neglecting 7 and 6?Haze
@Haze Nope, I will need the names and values of all the keys.Rubato
@Haze Moreover, there are a number of responses the web-service can generate (depending on what the user asks for). They will have the same format ofcourse, but different degree of nesting, we don't know how many fields will be nested inside a field. I hope I am making my point clear!Rubato
S
5

Response is not JSON, it is JSON-like object and you can parse it using ksoap2's abilities.

In SoapObject.java, there are some methods like as follow:

 public Object getProperty(int index) {
        Object prop = properties.elementAt(index);
        if(prop instanceof PropertyInfo) {
            return ((PropertyInfo)prop).getValue();
        } else {
            return ((SoapObject)prop);
        }
    }

and

 /**
* Get the toString value of the property.
*
* @param index
* @return
*/
    public String getPropertyAsString(int index) {
        PropertyInfo propertyInfo = (PropertyInfo) properties.elementAt(index);
        return propertyInfo.getValue().toString();
    }

and

/**
* Get the property with the given name
*
* @throws java.lang.RuntimeException
* if the property does not exist
*/
    public Object getProperty(String name) {
        Integer index = propertyIndex(name);
        if (index != null) {
            return getProperty(index.intValue());
        } else {
            throw new RuntimeException("illegal property: " + name);
        }
    }

and

/**
* Get the toString value of the property.
*
* @param name
* @return
*/

    public String getPropertyAsString(String name) {
        Integer index = propertyIndex(name);
        if (index != null) {
            return getProperty(index.intValue()).toString();
        } else {
            throw new RuntimeException("illegal property: " + name);
        }
    }

etc..

And you can try parse your object like this:

try {
            androidHttpTransport.call(SOAP_ACTION, envelope);
            SoapObject response = (SoapObject) envelope.getResponse();

            if (response.toString().equals("anyType{}") || response == null) {
                return;
            } else {
                String value1 = response.getPropertyAsString("key1");
                String value2 = response.getPropertyAsString("key2");

                SoapObject soapKey3 = (SoapObject) response.getProperty("key3");
                String value4 = soapKey3.getPropertyAsString("key4");
                String value5 = soapKey3.getPropertyAsString("key5");

                SoapObject soapKey6 = (SoapObject) soapKey3.getProperty("key6");
                SoapObject soapKey7 = (SoapObject) soapKey6.getProperty("key7");

                String value8 = soapKey7.getPropertyAsString("key8");

                String value9 = response.getPropertyAsString("key9");

                System.out.println(value1 + ", " + value2 + ", " + value4 + ", " + value5 + ", " + value8 + ", " + value9);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
Shwalb answered 20/6, 2014 at 7:43 Comment(2)
Nice, you beat me to it.Merritt
Your solution is very simple and easy to use and to be honest I am more inclined towards using it but trying to use it brings up a Runtime Exception: illegal Property'; and looking at the SoapObject class, I found that the index of the property appears to be null`Rubato
Z
2

Try This I think it will work

          SoapObject response = (SoapObject) envelope.getResponse();

          int cols = response.getPropertyCount();

            for (int i = 0; i < cols; i++) {
                Object objectResponse = (Object) response.getProperty(i);




                SoapObject r =(SoapObject) objectResponse;

             String   key1=(String) r.getProperty("key1").toString();

                // Get the rest of your Properties by 
                // (String) r.getProperty("PropertyName").toString();

            }
Zaidazailer answered 28/8, 2014 at 8:25 Comment(0)
M
1
  1. Cast your response string as a soap object.
  2. Do a property count for the soap object and iterate the count.
  3. For each property, cast to Object and check if Object is of class type Soap. If the Object is a soap class type, cast to Soap Object and redo from step 2 else retrieve the property as a string value.

    SoapObject result=(SoapObject)responseString;
    if (result.getPropertyCount() > 0){
        Object obj = result.getProperty(0);
        if (obj!=null && obj.getClass().equals(SoapObject.class)){
            SoapObject j = (SoapObject)obj;
        }
    }   
    
    for (int i = 0; i < j.getPropertyCount(); i++) {
        Object obj0 = j.getProperty(i);                     
        if (obj0!=null && obj0.getClass().equals(SoapObject.class)){
            SoapObject j0 =(SoapObject) j.getProperty(i);
            for (int i0 = 0; i0 < j0.getPropertyCount(); i0++) {
                Object obj1 = j0.getProperty(i0);
                if (obj1!=null && obj1.getClass().equals(SoapObject.class)){
                    SoapObject j1 =(SoapObject) j0.getProperty(i0);
                    //TODO retrieve the properties for this soap object
                }else{
                    // retrieve soap property as string
                    String keyValue = obj1.toString()
                }   
            }
        }else{
            // retrieve soap property as string
            String keyValue0 = obj0.toString();
        }
    }
    
Merritt answered 20/6, 2014 at 8:26 Comment(4)
Thank you very much. Although it took me some time to completely understand it since I am a newbie, but this is great; except that there is one problem. In the application I want to make, there will be different responses from the web-service (depending on what the user asks for) with different levels of nesting. For example in your code you nested one for loop in another, in my code in which I adapted your code to test the real webservice response, I used one property nested in another, nested in another, in another, in another and yet another (that is 5 times nesting)... thatRubato
... that was one type of response based on one soap request. Now the user will have different options to choose what they want to request of the webservice. On the basis of request, the response will have different properties, so we can't predict the degree to which the properties will be nested inside other properties. If you can suggest me something about it, I'll appreciate. Thank you again for your answer.Rubato
@Zarah: unfortunately due to the fact that KSOAP does not consume the wsdl itself; you will have to have a very good understanding of the web service and it's response. Something that you have already experienced; hence the code provided was to assist in this understanding. You can take a look at a code generator www.wsdl2code.com; though from my experience the classes that were generated to map the web service response were incorrectly mapped in my case.Merritt
The code that is used to validate if a property is a soap class type, assists with determining the level of nesting when iterating.Merritt

© 2022 - 2024 — McMap. All rights reserved.