Android Full App,第3部分:解析XML响应

这是“ Android完整应用程序教程”系列的第三部分。 完整的应用程序旨在提供一种通过互联网搜索表演电影/演员的简便方法。 在本系列的第一部分( “主要活动UI” )中,我们创建了Eclipse项目并为应用程序的主要活动设置了基本界面。 在第二部分( “使用HTTP API” )中,我们使用Apache HTTP客户端库来使用外部HTTP API并将API的搜索功能集成到我们的应用程序中。 在这一部分中,我们将看到如何使用Android内置的XML解析功能来解析XML响应。

TMDb API支持HTTP响应的XML和JSON格式。 我们将在应用程序中使用XML。 首先,让我们看一下对搜索查询的一些示例响应:

响应是典型的XML文档,可以使用SAXDOM使用标准过程对其进行解析。 SAX规范定义了一种基于事件的方法,其中,已实现的解析器扫描XML数据,并在到达文档的某些部分时使用回调处理程序。 另一方面,DOM规范定义了一种基于树的方法来浏览XML文档。

通常,SAX的使用更具挑战性,因为API需要开发用于处理事件的回调函数,而DOM方法需要更大的内存占用空间。 出于这个原因,我们将选择XML解析器实现的SAX,因为我们的应用程序将处于资源受限的环境中,例如移动设备。

在继续进行XML解析之前,我们将创建一些模型类,这些模型类会将XML元素映射到Java类。 通过简单地查看XML响应,可以得出以下模型类:

package com.javacodegeeks.android.apps.moviesearchapp.model;

import java.util.ArrayList;

public class Person {
    
    public String score;
    public String popularity;
    public String name;
    public String id;
    public String biography;
    public String url;
    public String version;
    public String lastModifiedAt;
    public ArrayList<Image> imagesList;

}
package com.javacodegeeks.android.apps.moviesearchapp.model;

import java.util.ArrayList;

public class Movie {
    
    public String score;
    public String popularity;
    public boolean translated;
    public boolean adult;
    public String language;
    public String originalName;
    public String name;
    public String type;
    public String id;
    public String imdbId;
    public String url;
    public String votes;
    public String rating;
    public String certification;
    public String overview;
    public String released;
    public String version;
    public String lastModifiedAt;
    public ArrayList<Image> imagesList;
    
    public String retrieveThumbnail() {
        if (imagesList!=null && !imagesList.isEmpty()) {
            for (Image movieImage : imagesList) {
                if (movieImage.size.equalsIgnoreCase(Image.SIZE_THUMB) &&
                        movieImage.type.equalsIgnoreCase(Image.TYPE_POSTER)) {
                    return movieImage.url;
                }
            }
        }
        return null;
    }    

}
package com.javacodegeeks.android.apps.moviesearchapp.model;

public class Image {
    
    public static final String SIZE_ORIGINAL = "original";
    public static final String SIZE_MID = "mid";
    public static final String SIZE_COVER = "cover";
    public static final String SIZE_THUMB = "thumb";

    public static final String TYPE_PROFILE = "profile";
    public static final String TYPE_POSTER = "poster";
    
    public String type;
    public String url;
    public String size;
    public int width;
    public int height;
    
}

这里没有什么特别的,我们只是为每个XML元素添加String字段。 请注意,Person和Movie类将共同使用Image类。 此外,Movie类提供了retrieveThumbnail方法,该方法循环遍历可用的Image并返回大小为“ thumb”和类型为“ poster”的图片。

我们继续创建一个名为XmlParser的类,该类使用SAX方法来解析XML响应。 该类使用两个自定义处理程序(PersonH​​andler和MovieHandler)来执行解析。 该类的代码如下:

package com.javacodegeeks.android.apps.moviesearchapp.services;

import java.io.StringReader;
import java.util.ArrayList;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;

import com.javacodegeeks.android.apps.moviesearchapp.handlers.MovieHandler;
import com.javacodegeeks.android.apps.moviesearchapp.handlers.PersonHandler;
import com.javacodegeeks.android.apps.moviesearchapp.model.Movie;
import com.javacodegeeks.android.apps.moviesearchapp.model.Person;

public class XmlParser {
    
    private XMLReader initializeReader() throws ParserConfigurationException, SAXException {
        SAXParserFactory factory = SAXParserFactory.newInstance();
        // create a parser
        SAXParser parser = factory.newSAXParser();
        // create the reader (scanner)
        XMLReader xmlreader = parser.getXMLReader();
        return xmlreader;
    }
    
    public ArrayList<Person> parsePeopleResponse(String xml) {
        
        try {
            
            XMLReader xmlreader = initializeReader();
            
            PersonHandler personHandler = new PersonHandler();

            // assign our handler
            xmlreader.setContentHandler(personHandler);
            // perform the synchronous parse
            xmlreader.parse(new InputSource(new StringReader(xml)));
            
            return personHandler.retrievePersonList();
            
        } 
        catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        
    }
    
    public ArrayList<Movie> parseMoviesResponse(String xml) {
        
        try {
            
            XMLReader xmlreader = initializeReader();
            
            MovieHandler movieHandler = new MovieHandler();

            // assign our handler
            xmlreader.setContentHandler(movieHandler);
            // perform the synchronous parse
            xmlreader.parse(new InputSource(new StringReader(xml)));
            
            return movieHandler.retrieveMoviesList();            
            
        } 
        catch (Exception e) {
            e.printStackTrace();
            return null;
        }

    }

}

在每种方法中,我们首先使用SAXParserFactorynewInstance静态方法检索SAX解析器工厂类的引用。 该方法返回适当的Android实现。 然后,使用newSAXParser方法创建一个SAXParser对象,该方法使用当前配置的工厂参数创建一个SAXParser的新实例。 SAXParser类定义包装XMLReader实现类的API。 XMLReader是用于使用回调读取XML文档的接口。 回调通常是通过扩展DefaultHandler类的类定义的,该类是SAX2事件处理程序的默认基类。 我们提供了两个处理程序,一个用于解析人物搜索响应(PersonH​​andler),另一个用于解析电影搜索响应(MovieHandler)。 以下是PersonH​​andler类的代码(MovieHandler类非常相似,为简洁起见,省略了该类的源代码,可以在本教程结尾的可用Eclipse项目中找到该类的源代码):

package com.javacodegeeks.android.apps.moviesearchapp.handlers;

import java.util.ArrayList;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

import com.javacodegeeks.android.apps.moviesearchapp.model.Image;
import com.javacodegeeks.android.apps.moviesearchapp.model.Person;

public class PersonHandler extends DefaultHandler {
    
    private StringBuffer buffer = new StringBuffer();
    
    private ArrayList<Person> personList;
    private Person person;
    private ArrayList<Image> personImagesList;
    private Image personImage;
    
    @Override
    public void startElement(String namespaceURI, String localName,
            String qName, Attributes atts) throws SAXException {
        
        buffer.setLength(0);
        
        if (localName.equals("people")) {
            personList = new ArrayList<Person>();
        }
        else if (localName.equals("person")) {
            person = new Person();
        }
        else if (localName.equals("images")) {
            personImagesList = new ArrayList<Image>();
        }
        else if (localName.equals("image")) {
            personImage = new Image();
            personImage.type = atts.getValue("type");
            personImage.url = atts.getValue("url");
            personImage.size = atts.getValue("size");
            personImage.width = Integer.parseInt(atts.getValue("width"));
            personImage.height = Integer.parseInt(atts.getValue("height"));
        }

    }
    
    @Override
    public void endElement(String uri, String localName, String qName)throws SAXException {
        
        if (localName.equals("person")) {
            personList.add(person);
        }
        else if (localName.equals("score")) {
            person.score = buffer.toString();
        }
        else if (localName.equals("popularity")) {
            person.popularity = buffer.toString();
        }
        else if (localName.equals("name")) {
            person.name = buffer.toString();
        }
        else if (localName.equals("id")) {
            person.id = buffer.toString();
        }
        else if (localName.equals("biography")) {
            person.biography = buffer.toString();
        }
        else if (localName.equals("url")) {
            person.url = buffer.toString();
        }
        else if (localName.equals("version")) {
            person.version = buffer.toString();
        }
        else if (localName.equals("last_modified_at")) {
            person.lastModifiedAt = buffer.toString();
        }    
        else if (localName.equals("image")) {
            personImagesList.add(personImage);
        }    
        else if (localName.equals("images")) {
            person.imagesList = personImagesList;
        }
        
    }
    
    @Override
    public void characters(char[] ch, int start, int length) {
        buffer.append(ch, start, length);
    }
        
    public ArrayList<Person> retrievePersonList() {
        return personList;
    }
    
}

使用了SAX解析的标准方法(在许多在线教程中都有介绍),因此如果您之前解析过XML文档,则上面的代码应该看起来很熟悉。 请注意,尽管不是qName参数,而是localName变量保存了元素的数据。

在我们的类中,我们定义必要的回调函数:

  • startElement :在找到新元素时调用。 我们在那里初始化适当的字段。
  • endElement :在到达元素末尾时调用。 相应的字段在那里填充。
  • 字符 :在元素内找到新文本时调用。 内部缓冲区填充有元素的内容。

请注意,在响应中,可能会找到许多Person元素,并且在每个元素中都可以找到许多Images。 特别是对于图像,相关信息位于元素属性内,而不位于文本节点内。 因此,使用适当的getValue方法来提取该信息。

至此,该系列的第三部分已经结束。 在这一部分中,我们准备了使用SAX方法执行API响应的XML解析的基础结构。 在以下教程中,我们将使用它来将响应映射到我们的模型类。 您可以在此处下载到目前为止创建的Eclipse项目。

相关文章 :

翻译自: https://www.javacodegeeks.com/2010/10/android-full-app-part-3-parsing-xml.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值