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-удивительность: краткий обзор