Val Okafor
Val Okafor

Reputation: 3437

Fetching XML Data using Retrofit and Simple XML Converter

I needed to fetch data from SupermarketApi. Here is what the raw data looks like using Postman.

<?xml version="1.0" encoding="utf-8"?>
<ArrayOfProduct xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns="http://www.SupermarketAPI.com">
    <Product>
        <Itemname>Flake Parsley Seasoning  - 0.375 Oz. Plastic Peg Bag</Itemname>
        <ItemDescription>Flake Parsley Seasoning  - 0.375 Oz. Plastic Peg Bag</ItemDescription>
        <ItemCategory>Condiments/Spices &amp; Bake</ItemCategory>
        <ItemID>84309</ItemID>
        <ItemImage>http://smapistorage.blob.core.windows.net/thumbimages/2/3C07125.jpg</ItemImage>
        <AisleNumber>Aisle:N/A</AisleNumber>
    </Product>
    <Product>
        <Itemname>El Guapo Flake Parsley Spice  - 0.25 Oz. Plastic Bag</Itemname>
        <ItemDescription>El Guapo Flake Parsley Spice  - 0.25 Oz. Plastic Bag</ItemDescription>
        <ItemCategory>Condiments/Spices &amp; Bake</ItemCategory>
        <ItemID>89721</ItemID>
        <ItemImage>http://smapistorage.blob.core.windows.net/thumbimages/2/no_image_sm.jpg</ItemImage>
        <AisleNumber>Aisle:N/A</AisleNumber>
    </Product>
    <Product>
        <Itemname>Superline Deal Flake Parsley Seasoning  - 1.2 Oz Shaker</Itemname>
        <ItemDescription>Superline Deal Flake Parsley Seasoning  - 1.2 Oz Shaker</ItemDescription>
        <ItemCategory>Condiments/Spices &amp; Bake</ItemCategory>
        <ItemID>85817</ItemID>
        <ItemImage>http://smapistorage.blob.core.windows.net/thumbimages/2/5E59BCF.jpg</ItemImage>
        <AisleNumber>Aisle:N/A</AisleNumber>
    </Product>
</ArrayOfProduct>

Here is my POJO representation of that data.

public class ProductDto {

    @Element(name = "itemID")
    private String itemID;

    @Element(name = "Itemname")
    private String Itemname;

    @Element(name = "AisleNumber")
    private String AisleNumber;

    @Element(name = "ItemCategory")
    private String ItemCategory;

    @Element(name = "ItemImage")
    private String ItemImage;

    @Element(name = "ItemDescription")
    private String ItemDescription;
}

And here is the Retrofit interface

 public interface SuperMarketApiService {
        public static final String BASE_URL = "http://www.SupermarketAPI.com/api.asmx/";

        @GET("SearchByProductName")
        Call<ProductDto> getProduct(
                @Query("APIKEY") String key,
                @Query("ItemName") String itemName
        );

        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(BASE_URL)
                .addConverterFactory(SimpleXmlConverterFactory.create())
                .build();   

    }

Problem is when I make the call, I get the error message

org.simpleframework.xml.core.ElementException: Element 'Product' does not have a match in class Data.ProductDto at line 3

How can I update POJO to correctly map XML ArrayOfProducts to Java ArrayList of Products.

Here is how I make the call

 private void getProducts() {
        SuperMarketApiService apiService = SuperMarketApiService.retrofit.create(SuperMarketApiService.class);
        Call<ArrayOfProduct> call = apiService.getProduct("jdmdldfdd", "Parsley");
        call.enqueue(new Callback<ArrayOfProduct>() {
            @Override
            public void onResponse(Call<ArrayOfProduct> call, Response<ArrayOfProduct> response) {
                ArrayOfProduct products = response.body();
                Log.d(LOG_TAG, "Product Count: " + products.getProductDtos().size());
            }

            @Override
            public void onFailure(Call<ArrayOfProduct> call, Throwable t) {
                Log.d(LOG_TAG, t.getLocalizedMessage());
            }
        });
    }

Upvotes: 2

Views: 504

Answers (1)

davidxxx
davidxxx

Reputation: 131346

I think that you should change the returned ProductDto type in getProduct() by a type matching with your xml that waits as root element an enclosing type containing multiple Products and not only a Product.
You could introduce ArrayOfProduct, a wrapper class that contains a List of ProductDto.

You method could be so :

    @GET("SearchByProductName")
    Call<ArrayOfProduct> getProducts(
            @Query("APIKEY") String key,
            @Query("ItemName") String itemName
    );

Upvotes: 1

Related Questions