How to parse the SOAP response with complex objects in Android
Android :: Ksoap2 Kullanarak Webservislere Erişme yazımda Android üzerinden webservislerin nasıl çağrılacağı hakkında bir şeyler yazmıştım. Oradaki örnekte gelen yanıtın derinliği 1’di ve parse edilecek tüm değerler aynı seviyede property’ler olarak gelmişti.
Eğer iç içe yapıda bir yanıt gelirse ya da gelen yanıt bir obje listesi olursa ve listenin boyutu önceden belli değilse ilk örneğimizdeki kod yetersiz kalacaktır. Bu gibi durumlarda ne yapmak gerektiğini bir örnekle inceleyelim.
Öncelikle uygun bir public webservis arayıp bulmak zor geldi, kendi webservisimi yazdım. Örnek olarak bir şirketin çalışanlarının listesini bize döndürsün, biz de onu Android’den çağırıp parse edelim yeterli diye düşündüm. Listesi dönecek olan çalışanları tutacak Employee classı aşağıdaki gibi:
public class Employee { private int id; private String name; private String surName; private String department; private Double salary; public Employee() { super(); } public Employee(int id, String name, String surName, String department, Double salary) { super(); this.id = id; this.name = name; this.surName = surName; this.department = department; this.salary = salary; } public int getId() { return id; } public void setId(int id) { this.id = id; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getSurName() { return surName; } public void setSurName(String surName) { this.surName = surName; } public String getDepartment() { return department; } public void setDepartment(String department) { this.department = department; } public Double getSalary() { return salary; } public void setSalary(Double salary) { this.salary = salary; } @Override public String toString() { return "Employee [id=" + id + ", name=" + name + ", surName=" + surName + ", department=" + department + ", salary=" + salary + "]"; } }
Çağırdığımızda bize bu classtan oluşmuş nesnelerin biz listesini döndürecek servis metodunu da burada göstermek istersek:
public class ComplexWebserviceDemo implements Serializable { private static final long serialVersionUID = 8058591245625624821L; public Employee[] getEmployeeList() { try { Employee[] array = new Employee[5]; array [0] = new Employee(1, "F. Oğuz", "ÖZKEROĞLU", "Yazılım", 0.0); array [1] = new Employee(2, "Ad1", "Soyad1", "Yazılım", 1000.0); array [2] = new Employee(3, "Ad2", "Soyad2", "Arge", 2000.0); array [3] = new Employee(4, "Ad3", "Soyad3", "Muhasebe", 1000.0); array [4] = new Employee(5, "Ad4", "Soyad4", "Yazılım", 750.0); return array; } catch (Exception e) { e.printStackTrace(); return null; } } }
Metodun içinde sanki database’den veri çekiyormuşuz gibi olayı simule edip elle birkaç veri ekliyoruz. Bu arada yazılım departmanının maaş ortalamasının düşüklüğüne de dikkat çekmiş olalım :)
Sıra geldi servisi çağırmaya.. Parametre almayan getEmployeeList() metodunu çağırdığımızda aşağıdaki SOAP response bize geri dönecektir.
<?xml version="1.0" encoding="utf-8"?> <soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"> <soapenv:Body> <getEmployeeListResponse xmlns="http://demo.webservice.ozkeroglu.com"> <getEmployeeListReturn> <employee> <employee> <department>Yazılım</department> <id>1</id> <name>F. Oğuz</name> <salary>0.0</salary> <surName>ÖZKEROĞLU</surName> </employee> <employee> <department>Yazılım</department> <id>2</id> <name>Ad1</name> <salary>1000.0</salary> <surName>Soyad1</surName> </employee> <employee> <department>Arge</department> <id>3</id> <name>Ad2</name> <salary>2000.0</salary> <surName>Soyad2</surName> </employee> <employee> <department>Muhasebe</department> <id>4</id> <name>Ad3</name> <salary>1000.0</salary> <surName>Soyad3</surName> </employee> <employee> <department>Yazılım</department> <id>5</id> <name>Ad4</name> <salary>750.0</salary> <surName>Soyad4</surName> </employee> </employee> </getEmployeeListReturn> </getEmployeeListResponse> </soapenv:Body> </soapenv:Envelope>
Burada ksoap2’nin bize vereceği response, getEmployeeListReturn node’una karşılık gelecektir. Onun altında employee isminde bir node var. Bu da servisten gelen Employee listesine karşılık geliyor. Onun altında da her bir çalışan için yine employee isminde bir node var ve her bir employee için id, name, surName, department ve salary değerleri bulunmaktadır.
Böyle bir durumda şu gibi bir strateji izlenebilir: İlk adımda gelen response zaten bir SoapObject olarak elimizde var. Bu SoapObject nesnesinin içinde 1 tane de employee listesini karşılayan property var. Bu property’e ya ismi ile (employee) ya da bulunduğu indexi ile (0) erişip onu da SoapObject olarak alacağız. Daha sonra elimizdeki yeni SoapObject (employee listesi)’ne bakıyoruz ve içinde hala objeler olduğunu görüyoruz. Onlara da ulaşmak için bir döngüde listenin boyutu kadar defa dönüp, her bir elamanı yeniden bir SoapObject olarak alıp, ondan sonra parse edip kullanmamız gerekecek.
Bunu yapacak metodu barındıran class da aşağıdaki gibi olabilir:
public class WebserviceClient { private static final String METHOD_NAME = "getEmployeeList"; private static final String NAMESPACE = "http://demo.webservice.ozkeroglu.com"; private static final String SOAP_ACTION = ""; private static final String URL = "http://192.168.1.2:8080/ComplexTypeWebServiceDemo/services/ComplexWebserviceDemo?wsdl"; public static List<Employee> getEmployeeList() { List<Employee> list = null; SoapObject request = new SoapObject(NAMESPACE, METHOD_NAME); SoapSerializationEnvelope envelope = new SoapSerializationEnvelope(SoapEnvelope.VER11); envelope.setOutputSoapObject(request); HttpTransportSE androidHttpTransport = new HttpTransportSE(URL); androidHttpTransport.debug = true; try { androidHttpTransport.call(SOAP_ACTION, envelope); SoapObject response = (SoapObject) envelope.getResponse(); if (response.toString().equals("anyType{}") || response == null) { list = null; } else { SoapObject soapEmployeeList = (SoapObject) response.getProperty("employee"); // ya da // SoapObject soapEmployeeList = (SoapObject) response.getProperty(0); list = new ArrayList<Employee>(); int employeeCount = soapEmployeeList.getPropertyCount(); for (int i = 0; i < employeeCount; i++) { Employee item = new Employee(); SoapObject soapEmployee = (SoapObject) soapEmployeeList.getProperty(i); if (soapEmployee.hasProperty("id")) { item.setId(Integer.parseInt(soapEmployee.getPropertyAsString("id"))); } if (soapEmployee.hasProperty("name")) { item.setName(soapEmployee.getPropertyAsString("name")); } if (soapEmployee.hasProperty("surName")) { item.setSurName(soapEmployee.getPropertyAsString("surName")); } if (soapEmployee.hasProperty("department")) { item.setDepartment(soapEmployee.getPropertyAsString("department")); } if (soapEmployee.hasProperty("name")) { item.setSalary(Double.parseDouble(soapEmployee.getPropertyAsString("salary"))); } list.add(item); } } } catch (Exception e) { e.printStackTrace(); list = null; } return list; } }
SoapObject.getPropertyCount() metodu bize o SoapObject’in kaç tane özelliği olduğu bilgisini vermektedir. Servisin liste döndürdüğü ve liste boyutunun değişken olduğu durumlarda, döngüdeki iterasyon sayısını belirlemede oldukça kullanışlı bir metod olacaktır.
Test için şu metodu kullandığımda:
private void invokeService() { List<Employee> employeeList = WebserviceClient.getEmployeeList(); for (Employee employee : employeeList) { System.out.println(employee); } }
Console çıktısı aşağıdaki gibi oldu:
Employee [id=1, name=F. Oguz, surName=ÖZKEROGLU, department=Yazilim, salary=0.0]
Employee [id=2, name=Ad1, surName=Soyad1, department=Yazilim, salary=1000.0]
Employee [id=3, name=Ad2, surName=Soyad2, department=Arge, salary=2000.0]
Employee [id=4, name=Ad3, surName=Soyad3, department=Muhasebe, salary=1000.0]
Employee [id=5, name=Ad4, surName=Soyad4, department=Yazilim, salary=750.0]
Umarım faydalı bir yazı olmuştur.
http://www.oguzozkeroglu.com/android-webservisten-donen-ic-ice-yapidaki-xmlin-parse-edilmesi/
“Android :: Webservisten Dönen İç İçe Yapıdaki XML’in Parse Edilmesi” yazısına 8 yorum yapılmış.