Retrofit之SimpleXml解析的简单用法

作者: walle9 | 来源:发表于2017-09-22 12:40 被阅读0次

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

    相关文章

      网友评论

        本文标题:Retrofit之SimpleXml解析的简单用法

        本文链接:https://www.haomeiwen.com/subject/epwxextx.html