Reputation: 37556
I have a server response in xml, that is not well formatted and have no root element:
<option value="stationAValue">stationADescription</option>
<option value="stationBValue">stationBDescription</option>
I trying to use SimpleXmlConverterFactory
like this:
Retrofit retrofit = new Retrofit.Builder()
.baseUrl(Params.BASE_URL)
.client(okHttpClient)
.addConverterFactory(SimpleXmlConverterFactory.create())
.build();
This is my class that represents a row:
public class Station {
@Element(name = "option")
private String mName;
@Attribute(required = false)
private String value;
}
But of course it can't be parsed without a root element,
Is there a way to manipulate the response before the SimpleXmlConverterFactory
is trying to parse it, and add a root element?
Or maybe another solution?
Upvotes: 0
Views: 1610
Reputation: 34542
With Retrofit / OkHttp you have 2 options for intercepting those requests:
Both is somewhat a decorator pattern.
Modify the response as part of the http stack directly:
public class XmlInterceptor implements Interceptor {
@Override
public Response intercept(Chain chain) throws IOException {
Response response = chain.proceed(chain.request());
ResponseBody body = response.body();
String wrappedBody = "<root>" + body.string() + "</root>";
return response.newBuilder()
.body(ResponseBody.create(body.contentType(), wrappedBody))
.build();
}
}
And just add the interceptor to OkHttp
new OkHttpClient.Builder()
.addInterceptor(new XmlInterceptor())
.build();
Wrap the parser you want to use and again just modify the response. The nice thing here is, you could add a custom annotation for your wrapping. e.g. to pass in the name of the root element.
public class XmlParser extends Converter.Factory {
private Converter.Factory factory = SimpleXmlConverterFactory.create();
@Override
public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
// here you can actually look at the annotations, type, etc.
return new WrappedResponseBodyConverter(factory.responseBodyConverter(type, annotations, retrofit));
}
private class WrappedResponseBodyConverter<T> implements Converter<ResponseBody, T> {
private Converter<ResponseBody, T> responseBodyConverter;
public WrappedResponseBodyConverter(Converter<ResponseBody, T> responseBodyConverter) {
this.responseBodyConverter = responseBodyConverter;
}
@Override
public T convert(ResponseBody value) throws IOException {
String body = "<root>" + value.string() + "</root>";
ResponseBody wrapped = ResponseBody.create(value.contentType(), body);
return responseBodyConverter.convert(value);
}
}
}
And use this one instead.
new Retrofit.Builder()
.addConverterFactory(new XmlParser())
.build();
Choose whichever you prefer, as there is no right or wrong imho.
The code is not tested. It's just an example.
Upvotes: 5
Reputation: 417
I have done something almost similar to your current ptoblem. Once you receive the xml response in java, you can use + operation to include you root element, like so :
String xml = "<?xml version=\"1.0\" encoding=\"utf-8\"?>" + "<root>" + response + "</root>";
here, response is the xml response you get you get in String format. Note that you can also manipulate the xml respose to suit your needs by treating it as a string, so you can concat any additional data into your response and you can also split the response at different parts to suit the format that you require. Hope this will assist.
Upvotes: -1