TMDb API поддерживает форматы XML и JSON для ответов HTTP. Мы собираемся использовать XML для нашего приложения. Давайте сначала посмотрим, как выглядят некоторые примеры ответов на поисковые запросы:
Ответы — это типичные XML-документы, которые можно анализировать с использованием стандартных процедур с использованием SAX или DOM . Спецификация SAX определяет основанный на событиях подход, при котором реализованные анализаторы сканируют данные XML и используют обработчики обратного вызова при достижении определенных частей документа. С другой стороны, спецификация DOM определяет древовидный подход к навигации по документу XML.
В общем, использование SAX более сложное, потому что API требует разработки функций обратного вызова, которые обрабатывают события, в то время как подход DOM требует большего объема памяти. По этой причине мы собираемся выбрать SAX для нашей реализации XML-парсеров, так как наше приложение будет работать в довольно ограниченной среде, такой как мобильное устройство.
Прежде чем мы приступим к синтаксическому анализу XML, мы собираемся создать несколько классов моделей, которые будут сопоставлять элементы XML с классами Java. Просто взглянув на ответы XML, можно получить следующие классы моделей:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
|
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;} |
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
|
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; } } |
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
|
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; } |
Здесь нет ничего особенного, мы просто добавляем поля String для каждого элемента XML. Обратите внимание, что класс Image будет обычно использоваться как классом Person, так и классом Movie. Кроме того, класс Movie предоставляет метод retrieveThumbnail, который перебирает доступные изображения и возвращает метод размером «большой палец» и типа «плакат».
Мы приступаем к созданию класса с именем XmlParser, который использует SAX-подход для анализа XML-ответов. Класс использует два пользовательских обработчика (PersonHandler и MovieHandler) для выполнения анализа. Код для этого класса следующий:
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
|
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; } }} |
В каждом методе мы сначала извлекаем ссылку на класс фабрики синтаксического анализатора SAX, используя статический метод newInstance SAXParserFactory . Этот метод возвращает соответствующую реализацию Android. Затем объект SAXParser создается с использованием метода newSAXParser , который создает новый экземпляр SAXParser, используя текущие настроенные заводские параметры. Класс SAXParser определяет API, который оборачивает класс реализации XMLReader . XMLReader — это интерфейс для чтения XML-документа с использованием обратных вызовов. Обратные вызовы обычно определяются через классы, расширяющие класс DefaultHandler , который является базовым классом по умолчанию для обработчиков событий SAX2. Мы предоставляем два обработчика, один для анализа ответов на поиск людей (PersonHandler) и один для анализа ответов на поиск фильмов (MovieHandler). Далее следует код для класса PersonHandler (класс MovieHandler практически одинаков, поэтому для краткости опущен — исходный код этого класса можно найти в доступном проекте Eclipse в конце учебника):
|
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
|
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, а внутри каждого из них может быть найдено несколько изображений. В частности, для изображений соответствующая информация находится в атрибутах элементов, а не внутри текстового узла. Таким образом, соответствующий метод getValue используется для извлечения этой информации.
На этом этапе третья часть серии подошла к концу. В этой части мы подготовили инфраструктуру для выполнения XML-анализа ответов API с использованием подхода SAX. В следующих уроках мы будем использовать это для сопоставления ответов с нашими модельными классами. Вы можете скачать здесь созданный проект Eclipse.
- Серия «Android Full Tutorial»
- Android-приложение для преобразования текста в речь
- Обратное геокодирование Android с помощью Yahoo API — PlaceFinder
- Приложение для определения местоположения Android — GPS местоположение
- Установите ОС Android на свой компьютер с VirtualBox
- Охватывая Android-удивительность: краткий обзор