Retrofit之SimpleXml解析的简单用法
在遇到服务器返回xml数据的时候,有木有想把服务器吃掉的冲动?
废话不说了.赶紧干活.
下面我们演示两个使用Retrofit中使用SimpleXml来解析xml数据的案例.
案例1:
开源中国登陆:
http://www.oschina.net/action/api/login_validate
首先我们还是简单完成下Retrofit的相关代码吧:
接口:
public interface ApiService {
@FormUrlEncoded
@POST("action/api/login_validate")
Call<XmlLogin> login(@FieldMap Map<String,String> params);
}
main:
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void go(View view) {
//创建 Retrofit对象
Retrofit retrofit = new Retrofit.Builder().baseUrl("http://www.oschina.net/") //设置域名
.addConverterFactory(SimpleXmlConverterFactory.create()) //添加数据解析器,需要添加对应依赖
.build();
//通过Retrofit创建对应的请求服务
ApiService apiService = retrofit.create(ApiService.class);
//对发送请求进行封装
//封装请求参数
Map<String, String> params = new HashMap<>();
params.put("keep_login", "1");
params.put("username", "walle9");//大哥,你账号是错的.大哥幽幽的说:.............
params.put("pwd", "@walle9t");
Call<XmlLogin> xmlLoginCall = apiService.login(params);
xmlLoginCall.enqueue(new Callback<XmlLogin>() {
@Override
public void onResponse(Call<XmlLogin> call, Response<XmlLogin> response) {
XmlLogin xmlLogin = response.body();
Toast.makeText(MainActivity.this, "请求成功" + xmlLogin, Toast.LENGTH_SHORT).show();
Log.d(TAG, "onResponse: " + xmlLogin);
}
@Override
public void onFailure(Call<XmlLogin> call, Throwable t) {
String message = t.getMessage();
Toast.makeText(MainActivity.this, "失败" + message, Toast.LENGTH_SHORT).show();
Log.d(TAG, "onFailure: " + message);
}
});
}
}
添加
compile 'com.squareup.retrofit2:converter-simplexml:2.3.0'
时出错
Warning:WARNING: Dependency xpp3:xpp3:1.1.3.3 is ignored for debug as it may be conflicting with the internal version provided by Android.
请使用:
compile ('com.squareup.retrofit2:converter-simplexml:2.3.0'){
exclude module: 'stax-api'
exclude module: 'stax'
exclude module: 'xpp3'
}
OK.下面我们来完成我们的重点SimpleXml的使用:
我们还是先来看下登陆后返回的数据吧!
成功:
<?xml version="1.0" encoding="UTF-8"?>
<oschina>
<result>
<errorCode>1</errorCode>
<errorMessage>
<![CDATA[登录成功]]>
</errorMessage>
</result>
<user>
<uid>3688039</uid>
<location>
<![CDATA[安徽 蚌埠]]>
</location>
<name>
<![CDATA[walle9t]]>
</name>
<followers>0</followers>
<fans>0</fans>
<score>0</score>
<portrait></portrait>
<favoritecount>0</favoritecount>
<gender>1</gender>
</user>
<notice>
<atmeCount>0</atmeCount>
<msgCount>0</msgCount>
<reviewCount>0</reviewCount>
<newFansCount>0</newFansCount>
<newLikeCount>0</newLikeCount>
</notice>
</oschina>
失败:
<?xml version="1.0" encoding="UTF-8"?>
<oschina>
<result>
<errorCode>0</errorCode>
<errorMessage>
<![CDATA[用户名或口令错]]>
</errorMessage>
</result>
<notice>
<atmeCount>0</atmeCount>
<msgCount>0</msgCount>
<reviewCount>0</reviewCount>
<newFansCount>0</newFansCount>
<newLikeCount>0</newLikeCount>
</notice>
</oschina>
开始封装:
注意哦!不能使用内部类,所以我们一个一个慢慢玩吧!
/**
* Created by walle9 on 2017/9/21.
* 描述:
*/
//root:此根注释用于注释需要序列化的类。 而且,由ElementList注释表示的元素列表中的元素需要此注释,以便可以确定元素名称。
// 可以使用注释来确定所有其他字段或方法名称,因此不需要此类对象的Root注释。
//name:这表示XML元素的名称。 这是可选的,当类的名称不适合作为元素名称时使用。
// 如果未指定,那么XML元素的名称将是该类的名称。 如果指定,类将被序列化和反序列化与给定的名称。
//strict:这用于确定所表示的对象是否应以严格的方式进行解析。 严格解析需要XML文档中的每个元素和属性与类模式中的一个字段相匹配。
// 如果某个元素或属性与某个字段不匹配,那么解析失败并带有异常。 将严格解析设置为false可以在反序列化期间跳过源XML文档中的细节。
@Root(strict = false) //下面的通知不想解析了,及登录失败时没有user,所以这里启用strict = false
public class XmlLogin {
//Element:该注释用于表示显示为XML元素的字段或方法。
@Element
public Result result; //结果
@Element(name = "user", required = false)
//name:如果字段或方法名称不适合作为XML元素名称,则提供该名称。
//required = false:确定XML文档中是否需要该元素。当对象被反序列化时,任何标记为不需要的字段将不会设置其值。
//也就是说当xml中没有该字段的时候,需要用required = false注明,但是当xml中有该字段时,标记了required = false也会正确解析
public User yonghu; //用户
/* @Element
public List<Notice> notice; //通知*/
}
/*以上注释来自 http://simple.sourceforge.net/home.php 中Javadoc
谷歌翻译:你懂的
*/
/**
* Created by walle9 on 2017/9/21.
* 描述:
*/
@Root
public class Result {
@Element
public int errorCode;
@Element(name = "errorMessage") //别名
public String Message;
}
/**
* Created by walle9 on 2017/9/21.
* 描述:
*/
@Root(strict = false) //strict:是否严格解析(这里我只想拿到uid,location,name)
public class User {
@Element(name = "uid") //当xml中元素与下面字段中的名字不匹配时需要使用name来表示,即别名
public String id;
@Element
public String location;
@Element
public String name;
}
看下效果:
登录失败:
image.png登录成功:
image.png我们在封装XmlLogin时,在 public User yonghu 字段的注解中设置了required = false.表示xml数据可以没有此字段对应的标签.登录失败时返回的xml中没有user标签,我们发现数据可以正确反序列化为javaBean,而登录成功时返回的xml含有user标签,并没有受到影响,也能够正确解析.
[========]
矮!矮!客官,先别走啊!我这里还有一个更简单的...
下面我们再来看一个案例:
案例2:
来看一下w3school给我们提供的一个实例:
http://www.w3school.com.cn/example/xmle/cd_catalog.xml
我们简单修改下上个案例的代码:
接口:
改为get请求
public interface ApiService {
@GET("example/xmle/cd_catalog.xml")
Call<Catalog> getCatalog();
}
main:
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
public void go(View view) {
//创建 Retrofit对象
Retrofit retrofit = new Retrofit.Builder().baseUrl("http://www.w3school.com.cn/") //设置域名
.addConverterFactory(SimpleXmlConverterFactory.create()) //添加数据解析器,需要添加对应依赖
.build();
//通过Retrofit创建对应的请求服务
ApiService apiService = retrofit.create(ApiService.class);
//对发送请求 进行封装
Call<Catalog> catalogCall = apiService.getCatalog();
//开始异步请求
catalogCall.enqueue(new Callback<Catalog>() {
@Override
public void onResponse(Call<Catalog> call, Response<Catalog> response) {
Catalog catalog = response.body();
Toast.makeText(MainActivity.this, "请求成功:" + catalog, Toast.LENGTH_SHORT).show();
Log.d(TAG, "onResponse: " + catalog);
}
@Override
public void onFailure(Call<Catalog> call, Throwable t) {
Log.d(TAG, "onFailure: 失败" + t.getMessage());
}
});
}
}
下面我们还是关注下我们的重点.实体类的封装:
/**
* Created by walle9 on 2017/9/21.
* 描述:
*/
@Root
public class Catalog {
//inline = true 内联,如下面这种
/* <entry name =“one”/>
<entry name =“two”/>
<entry name =“three”/> */
//entry:这用于提供表示列表中条目的XML元素的名称,需要和xml中保持一致(也可以理解为入口)
@ElementList(entry = "CD", inline = true)
private List<Cd> cd;
}
/**
* Created by walle9 on 2017/9/21.
* 描述:
*/
//strict:严格解析需要XML文档中的每个元素和属性与类模式中的一个字段相匹配。
//取值为false时实体类中可以缺少字段
//即xml有,实体类中没有,使用strict = false
@Root//(strict = false)
public class Cd {
@Element
private String TITLE; //标题
@Element(name = "ARTIST") //如果字段名字和XML中不一样的话,需要设置名字(别名)
private String artist; //艺术家
@Element(name = "COUNTRY")
private String country; //国家
@Element(name = "COMPANY")
private String company; //公司
@Element(name = "PRICE")
private String price; //价格
@Element(required = false) //如果我们需要实体类中添加xml中没有的字段,需要用required = false注明
private String nimei; //你妹
@Element(required = false)
private String YEAR; //年代
//required = false:确定XML文档中是否需要该元素。当对象被反序列化时,任何标记为不需要的字段将不会设置其值。
//注意:这里的任何字段不包括和xml中名字一模一样的,例如YEAR,还是会被反序列化,而上面的字段nimei却不会有值.
//上面的案例1中对此效果展示的更加清晰.
}
看下效果:
image.png[========]
OK.案例我们就演示到这里:
授人以鱼不如授人以渔
更多SimpleXml用法请查看:
http://simple.sourceforge.net/
据说和谷歌翻译搭配更妙哦!
等等.walle9你别走啊!....我的谷歌翻译不了怎么办呀!
谷歌不翻译,多半是废了!打一顿就好了!
image.png
image.png
image.png
什么?你没装谷歌翻译?那真的是废了,嗯,拖出去打一顿...
over...