TMDb API支持HTTP响应的XML和JSON格式。 我们将在应用程序中使用XML。 首先,让我们看一下对搜索查询的一些示例响应:
响应是典型的XML文档,可以使用SAX或DOM使用标准过程对其进行解析。 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响应。 该类使用两个自定义处理程序(PersonHandler和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;
}
}
}
在每种方法中,我们首先使用SAXParserFactory的newInstance静态方法检索SAX解析器工厂类的引用。 该方法返回适当的Android实现。 然后,使用newSAXParser方法创建一个SAXParser对象,该方法使用当前配置的工厂参数创建一个SAXParser的新实例。 SAXParser类定义包装XMLReader实现类的API。 XMLReader是用于使用回调读取XML文档的接口。 回调通常是通过扩展DefaultHandler类的类定义的,该类是SAX2事件处理程序的默认基类。 我们提供了两个处理程序,一个用于解析人物搜索响应(PersonHandler),另一个用于解析电影搜索响应(MovieHandler)。 以下是PersonHandler类的代码(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