I know some basics about ksoap requests, if it's simple i can do it no problem. But i don't have a clue how to make a request that will parse into request dump that would look like that:
<Organizer xsi:type="tns:Person"><name xsi:type="xsd:string">hisname</name>
<lastname xsi:type="xsd:string">hislast</lastname>
Person is defined like that:
<xsd:complexType name="Person"><xsd:all>
<xsd:element name="name" type="xsd:string" nillable="true"/>
<xsd:element name="lastname" type="xsd:string" nillable="true"/>
</xsd:all></xsd:complexType>
After that i need to send an array of Persons. It should look like
<guests xsi:type="soap-enc:Array" soap-enc:arrayType="tns:Person[1]">
<item xsi:type="tns:Person">
<name xsi:type="xsd:string">mitja</name>
<lastname xsi:type="xsd:string">last</lastname>
</item></guests>
Any ideas how to do it?
Handling of arrays with KSoap2 can be tricky and it is performed in a different way, depending on the version of KSoap2 you are using. In our case we defined our extensible SoapObject (ExtendedSoapObject) that accepted array fields as properties when used as request DTO and overcame array handling issues when used as response DTO.
We defined different versions of ExtendedSoapObject object for both Android and J2ME versions of Ksoap2.
This is the Android version:
/**
* Clase que extiende la funcionalidad de SoapObject para poder establecer
* propiedades de tipo array dado que la implementación de KSoap2 tiene la
* limitación de tratar los objetos de un array como múltiples propiedades con
* el mismo nombre. Pero si intentamos recuperar la propiedad en cuestión a
* partir del nombre sólo nos devuelve la primera instancia.
*
* @author BIFMP
*/
public class ExtendedSoapObject extends SoapObject
{
/**
* Crea una instancia de {@link ExtendedSoapObject}
*
* @param namespace
* namespace del objeto
* @param name
* nombre del objeto
*/
public ExtendedSoapObject(String namespace, String name)
{
super(namespace, name);
}
/**
* Crea una instancia de {@link ExtendedSoapObject} a partir de una
* instancia de la clase base.
*
* @param o
* instancia de {@link SoapObject}
*/
public ExtendedSoapObject(SoapObject o)
{
super(o.getNamespace(), o.getName());
for (int i = 0; i < o.getAttributeCount(); i++)
{
AttributeInfo ai = new AttributeInfo();
o.getAttributeInfo(i, ai);
ai.setValue(o.getAttribute(i));
addAttribute(ai);
}
for (int i = 0; i < o.getPropertyCount(); i++)
{
PropertyInfo pi = new PropertyInfo();
o.getPropertyInfo(i, pi);
pi.setValue(o.getProperty(i));
addProperty(pi);
}
}
/**
* Permite pasar objetos de tipo array.
*/
@Override
public SoapObject addProperty(String name, Object value)
{
if (value instanceof Object[])
{
Object[] subValues = (Object[]) value;
for (int i = 0; i < subValues.length; i++)
{
super.addProperty(name, subValues[i]);
}
}
else
{
super.addProperty(name, value);
}
return this;
}
/**
* Este método devuelve un objeto {@link SoapObject} o valor primitivo
* {@link SoapPrimitive} o un array de los mismos. Puede devolver null si es
* el valor que tiene la propiedad (porque fue lo que devolvió el método
* remoto) o si no se encuentra la propiedad.
*/
@Override
public Object getProperty(String name)
{
List<Object> result = new ArrayList<Object>();
for (int i = 0; i < properties.size(); i++)
{
PropertyInfo prop = (PropertyInfo) properties.elementAt(i);
if (prop.getName() != null && prop.getName().equals(name))
{
result.add(unwrap(prop));
}
}
if (result.size() == 1)
{
return result.get(0);
}
else if (result.size() > 1)
{
return result.toArray(new Object[0]);
}
else
{
return null;
}
}
/**
* Este método siempre devuelve un array de objetos.
*
* @param name
* @return
*/
public Object[] getArrayProperty(String name)
{
Object o = getProperty(name);
Object values[] = null;
if (o != null)
{
if (o instanceof Object[])
{
values = (Object[]) o;
}
else
{
values = new Object[1];
values[0] = o;
}
}
return values;
}
Object unwrap(Object o)
{
if (o instanceof PropertyInfo)
{
return unwrap(((PropertyInfo) o).getValue());
}
else if (o instanceof SoapPrimitive || o instanceof SoapObject)
{
return o;
}
return null;
}
}
And the J2ME version:
/**
* Clase que extiende la funcionalidad de SoapObject para poder establecer
* propiedades de tipo array dado que la implementación de KSoap2 tiene la
* limitación de tratar los objetos de un array como múltiples propiedades con
* el mismo nombre. Pero si intentamos recuperar la propiedad en cuestión a
* partir del nombre sólo nos devuelve la primera instancia.
*
* @author BIFMP
*/
public class ExtendedSoapObject extends SoapObject
{
/**
* Crea una instancia de {@link ExtendedSoapObject}
*
* @param namespace
* namespace del objeto
* @param name
* nombre del objeto
*/
public ExtendedSoapObject(String namespace, String name)
{
super(namespace, name);
}
/**
* Crea una instancia de {@link ExtendedSoapObject} a partir de una
* instancia de la clase base.
*
* @param o
* instancia de {@link SoapObject}
*/
public ExtendedSoapObject(SoapObject o)
{
super(o.getNamespace(), o.getName());
for (int i = 0; i < o.getPropertyCount(); i++)
{
PropertyInfo pi = new PropertyInfo();
o.getPropertyInfo(i, null, pi);
addProperty(pi, o.getProperty(i));
}
}
/**
* Permite pasar objetos de tipo array.
*/
public SoapObject addProperty(String name, Object value)
{
if (value instanceof Object[])
{
Object[] subValues = (Object[]) value;
for (int i = 0; i < subValues.length; i++)
{
super.addProperty(name, subValues[i]);
}
}
else
{
super.addProperty(name, value);
}
return this;
}
/**
* Este método devuelve un objeto {@link SoapObject} o valor primitivo
* {@link SoapPrimitive} o un array de los mismos. Puede devolver null si es
* el valor que tiene la propiedad (porque fue lo que devolvió el método
* remoto) o si no se encuentra la propiedad.
*/
public Object getProperty(String name)
{
Vector result = new Vector();
PropertyInfo info = new PropertyInfo();
for (int i = 0; i < getPropertyCount(); i++)
{
getPropertyInfo(i, null, info);
if (info.name != null && info.name.equals(name))
{
result.addElement(getProperty(i));
}
}
if (result.size() == 1)
{
return result.elementAt(0);
}
else if (result.size() > 1)
{
Object resultArray[] = new Object[result.size()];
result.copyInto(resultArray);
return resultArray;
}
else
{
return null;
}
}
/**
* Este método siempre devuelve un array de objetos.
*
* @param name
* @return
*/
public Object[] getArrayProperty(String name)
{
Object o = getProperty(name);
Object values[] = null;
if (o != null)
{
if (o instanceof Object[])
{
values = (Object[]) o;
}
else
{
values = new Object[1];
values[0] = o;
}
}
return values;
}
}