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

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...

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,175评论 5 466
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,674评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,151评论 0 328
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,597评论 1 269
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,505评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,969评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,455评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,118评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,227评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,213评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,214评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,928评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,512评论 3 302
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,616评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,848评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,228评论 2 344
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,772评论 2 339

推荐阅读更多精彩内容