Android知识Android技术知识半栈工程师

Retrofit之SimpleXml解析的简单用法

2017-09-22  本文已影响0人  walle9

在遇到服务器返回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

image.png

我们简单修改下上个案例的代码:

接口:
改为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...

上一篇下一篇

猜你喜欢

热点阅读