Search code examples
androidxmlnestedksoap2

Don't receive nested XML nodes from SOAP Web Service using ksoap2


ciao everybody, I am becoming stupid about this question. I hope someone can help me!! I searched in the web for a solution, but everiting I found doesn't work for me. This is the scenario: I am trying to make a request to a .net ws. The request is simple, but the response is the nested 2 level XML structure that follows:

<soap:Body>
    <ProgettoResponse xmlns="http://tempuri.org/">
      <ProgettoResult xmlns="">
        <Success>boolean</Success>
        <Message>string</Message>
        <Progetto>
          <Titolo>string</Titolo>
          <Descrizione>string</Descrizione>
        </Progetto>
      </ProgettoResult>
    </ProgettoResponse>
  </soap:Body>

but the response I receive from WS is always: anyType {Success=true; Message=OK; Progetto=anyType{};}

this situation is confirmed by logcat

The node is always empty. Obviusly I am shure that the WS, invoked with the same parameters sends a complete structure (via a web application and via ad app i-phone).

I am using ksoap2-android-assembly-2.6.0-jar-with-dependencies in android 2.1 / 2.2 environment.

This is the class that I use to invoke ws:

package feronia.culturando.android;

import org.ksoap2.SoapEnvelope;
import org.ksoap2.serialization.PropertyInfo;
import org.ksoap2.serialization.SoapObject;
import org.ksoap2.serialization.SoapSerializationEnvelope;
import org.ksoap2.transport.HttpTransportSE;


public class webService 
{
    public final String SOAP_ACTION = "http://tempuri.org/Progetto";
public  final String METHOD_NAME = "Progetto"; 
public  final String NAMESPACE = "http://tempuri.org/";
public  final String URL = "http://www.feronia.it/intra/webservice/wsCulturando.asmx";

    public webService() 
    { 
    }

    public String Call(String a,int b)
    {
            SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME);
            PropertyInfo pi=new PropertyInfo();
                            pi.setName("a");
                    pi.setValue(a);
                    pi.setType(String.class);
                    request.addProperty(pi);
                    pi=new PropertyInfo();
                    pi.setName("b");
                    pi.setValue(b);
                    pi.setType(Integer.class);
                    request.addProperty(pi);

            SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(
            SoapEnvelope.VER11);

            envelope.dotNet = true;         
            envelope.setOutputSoapObject(request);

            envelope.addMapping(NAMESPACE, "ProgettoResult", new ProgettoResult().getClass());
            envelope.addMapping(NAMESPACE, "Progetto", new Progetto().getClass());


            HttpTransportSE httpTransport = new HttpTransportSE(URL);
            SoapObject response=null;

            String totalCount = "";
            try
            {
                    httpTransport.call(SOAP_ACTION, envelope);

                    response = (SoapObject)envelope.getResponse();
                    //totalCount = response.getPropertyAsString("Progetto").toString();     
                    //totalCount = response.toString();
                    //Progetto prog = response.getProgetto();
                    totalCount =  response.toString();
                    ////////////Progetto prog = (Progetto) response.getProperty(3);
                    //////////////totalCount = prog.toString();
            }
            catch (Exception e)
            {
                     e.printStackTrace();
            }


            //String totalCount = response.getProperty("Success").toString();
            //Object totalCount = response.getProperty(Progetto.class);



            //Object resultData = (SoapObject)response.getProperty(2);

            return "risposta dal WS = " + totalCount;
    }


}

and these are the classes for ProgettoResult and Progetto

package feronia.culturando.android;

import java.util.Hashtable;

import org.ksoap2.serialization.KvmSerializable;
import org.ksoap2.serialization.PropertyInfo;

public class ProgettoResult implements KvmSerializable {


    private String          pSuccess;
    private String          pMessage;
    private Progetto        pProgetto;

    public Progetto getProgetto()
    {
            return pProgetto;
    }

    public void setProgetto(Progetto Progetto)
    {
            this.pProgetto = Progetto;
    }

    public ProgettoResult()
    {
            this.setSuccess("");
            this.setMessage("");
    }

    public ProgettoResult(String Success, String Message)
    {
            this.setSuccess(Success);
            this.setMessage(Message);
    }

    public Object getProperty(int arg0)
    {
            switch(arg0)
            {
            case 0:
                    return this.getSuccess();
            case 1:
                    return this.getMessage();
            case 2:
                    return this.getProgetto();
            }
            return null;
    }


    public int getPropertyCount()
    {
            return 3;
    }

    public void getPropertyInfo(int index, Hashtable arg1, PropertyInfo info) 
    {
            switch(index)
            {
            case 0:
                    info.name="Success";
                    info.type=PropertyInfo.STRING_CLASS;
                    break;
            case 1:
                    info.name="Message";
                    info.type=PropertyInfo.STRING_CLASS;
                    break;
            case 2:
                    info.name="Progetto";
                    info.type=Progetto.class;
                    break;
            default:
                    break;
            }
    }


    public void setProperty(int index, Object value) 
    {
            switch(index)
            {
            case 0:
                    this.setSuccess(value.toString());
                    break;
            case 1:
                    this.setMessage(value.toString());
                    break;
            case 2:
                    this.setProgetto((Progetto)value);
                    break;
            default:
                    break;
            }
    }
    /*********** GET - SET   *****************/

    public void setSuccess(String Success)
    {
            this.pSuccess = Success;
    }

    public String getSuccess()
    {
            return pSuccess;
    }

    public void setMessage(String Message)
    {
            this.pMessage = Message;
    }

    public String getMessage()
    {
            return pMessage;
    }
}

and

package feronia.culturando.android;

import java.util.Hashtable;

import org.ksoap2.serialization.KvmSerializable;
import org.ksoap2.serialization.PropertyInfo;

public class Progetto implements KvmSerializable{

    private String pTitolo;
    private String pDescrizione;

    public Progetto()
    {
            this.setTitolo("");
            this.setDescrizione("");
    }

    public Progetto(String t,String d)
    {
            this.setTitolo(t);
            this.setDescrizione(d);
    }

    public Object getProperty(int index) 
    {
            switch(index)
            {
            case 0:
                    return this.getTitolo();
            case 1:
                    return this.getDescrizione();
            }
            return null;
    }


    public int getPropertyCount() 
    {
            return 2;
    }


    public void getPropertyInfo(int index, Hashtable arg1, PropertyInfo info) 
    {
            switch(index)
            {
            case 0:
                    info.name="Titolo";
                    info.type=PropertyInfo.STRING_CLASS;
                    break;
            case 1:
                    info.name="Descrizione";
                    info.type=PropertyInfo.STRING_CLASS;
                    break;
            default: 
                    break;
            }
    }


    public void setProperty(int index, Object value) 
    {
            switch(index)
            {
            case 0:
                    this.setTitolo(value.toString());
                    break;
            case 1:
                    this.setDescrizione(value.toString());
                    break;
            default: 
                    break;
            }
    }

    /*********** GET - SET   *****************/

    public void setTitolo(String Titolo)
    {
            this.pTitolo = Titolo;
    }


    public String getTitolo()
    {
            return pTitolo;
    }

    public void setDescrizione(String Descrizione)
    {
            this.pDescrizione = Descrizione;
    }

    public String getDescrizione()
    {
            return pDescrizione;
    }
}

is there anybody who can tell me where is the mistake??? Please help me if You can!!!

================================================================================

thank You very much himanshu and shadesco for your interest to my question!! here is the code of my activity class where is the calling funcion. string a of the calling is not significant in this moment (not yet implemented the controls upon it: I pass a not significant string), while int b is simply che code of the project (progetto = 2) whose data are requested to web service.

the request:

<soap:Body>
    <Progetto xmlns="http://tempuri.org/">
      <Guid>string</Guid>
      <Id_Progetto>int</Id_Progetto>
    </Progetto>
</soap:Body>

the code of the calling class: consider that I can see correctly the (wrong) response on the emulator

package feronia.culturando.android;

import android.app.Activity;
import android.os.Bundle;
import android.text.Html;
import android.widget.TextView;

public class Presentazione extends Activity {
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.presentazione);


    webService cs=new webService();

    String appo=cs.Call("oi", 2);

    TextView pres_prog = (TextView) findViewById(R.id.pres_prog);

    pres_prog.setText(Html.fromHtml(appo));
}

}

I don't believe it is important, but the complete response of the method is:

<soap:Body>
<ProgettoResponse xmlns="http://tempuri.org/">
  <ProgettoResult xmlns="">
    <Success>boolean</Success>
    <Message>string</Message>
    <Progetto>
      <Titolo>string</Titolo>
      <Descrizione>string</Descrizione>
      <Immagini>
        <Immagine xsi:nil="true" />
        <Immagine xsi:nil="true" />
      </Immagini>
    </Progetto>
  </ProgettoResult>
</ProgettoResponse>

there is another block but requesting progetto = 2 this section of the response is not present (the project has no images associated and the tag

<Immagini /> 

is not generated. I am trying to go on step by step...


Solution

  • yeah Franco instead of keeping writing my comments above, i will write it here.

    Well the Structure of your request/response is accurate. however the response has:

    <ProgettoResult xmlns="">
     <Success>boolean</Success>
     <Message>string</Message>
     <Progetto>
      <Titolo>string</Titolo>
      <Descrizione>string</Descrizione>
      <Immagini>
        <Immagine xsi:nil="true" />
        <Immagine xsi:nil="true" />
      </Immagini>
     </Progetto>
    

    which means Object Progetto requires a parameter Immagini ( it is not obvious here, but i think it is a complex type ie object) BUT, it allows its inside parameters to be NULL, ie

    <Immagine xsi:nil="true" />
    <Immagine xsi:nil="true" />
    

    -->nil="true" ... so what that means is that Immagini can be a sort of "empty" object. So, you need to create a class for it implementing kvm serializable:

     public class Immagini implements KvmSerializable{
     //implement the overriden methods just like you did to Progetto
     }
    

    And thent you still need to reference it in the Progetto class. So you need to put a reference for Immagini:

    public class Progetto implements KvmSerializable{
    
    private String pTitolo;
    private String pDescrizione;
    private Immagini immagini;
    
    public Progetto()
    {
            this.setTitolo("");
            this.setDescrizione("");
           //Say put it null
           immagini = null;
    }
    //continue the rest of the code
    

    So what that means, is your response which Progetto requires THREE attributes (Titolo,Descrizione,Immagini):

     <Progetto>
      <Titolo>string</Titolo>
      <Descrizione>string</Descrizione>
      <Immagini>
        <Immagine xsi:nil="true" />
        <Immagine xsi:nil="true" />
      </Immagini>
     </Progetto>
    

    You now have created a reference for all 3 of them. It is most probably that the response was requiring 3 property count, but you were giving only 2 thus it couldn't build an appropriate array for it, it build an empty one Progetto=anyType{}

    let me know if this works.