Использование XML и JSON с Android: Часть 1. Преимущества JSON и XML для Android-приложений

Форматы обмена данными XML и JSON для использования на платформе Android

В этой статье из двух частей рассматриваются методы работы с двумя наиболее распространенными форматами данных, используемых в Интернете – XML и JavaScript Object Notation (JSON) – на платформе Android. Эта первая часть охватывает основы XML и JSON и показывает, как построить Android-приложение, которое анализирует и отображает информацию об обновлении состояния Twitter в обоих форматах.

Фрэнк Эйблсон, проектировщик ПО, Независимый разработчик

Когда Фрэнк Эйблсон (Frank Ableson) закончил карьеру баскетболиста в команде своего колледжа, не заключив многолетнего контракта с «Лос-Анджедес Лейкерс», он занялся разработкой компьютерных программ. Он любит решать сложные задачи, особенно из области связи и интерфейсов с аппаратурой. Свободное время Фрэнк проводит со своей женой Никки и детьми. С ним можно связаться по адресу: frank@cfgsolutions.com.



13.04.2011

С каждой новой версией мобильные устройства и платформы предоставляют все больше возможностей и функциональности, а важные анонсы ведущих поставщиков зачастую разделяют всего несколько месяцев. Последние новости в основном связаны с функциями пользовательского интерфейса (такими как расширенные multitouch-возможности и технология Adobe® Flash®) и усовершенствованиями аппаратуры (быстродействие процессора, емкость памяти и т.п.). Но решающим фактором остается контент. Контент – или, в более общем смысле, данные – постоянно перемещается между приложениями, серверами, мобильными устройствами и пользователями. Без возможности работать с данными смартфоны, такие как Apple iPhone и Google Android, становятся просто слишком дорогими и малоэффективными сотовыми телефонами.

Часто используемые сокращения

  • API: Application Programming Interface – интерфейс программирования приложений
  • DOM: Document Object Model
  • HTML: HyperText Markup Language – язык разметки гипертекста
  • IDE: Integrated development environment – интегрированная среда разработки
  • SAX: Simple API for XML – простой API для XML
  • SDK: Software Developer Kit – комплект разработчика ПО
  • UI: User Interface – интерфейс пользователя
  • XML: Extensible Markup Language – расширяемый язык разметки

Посмотрите на феноменальный успех платформ социальных сетей, таких как Facebook, LinkedIn и Twitter. С чисто функциональной точки зрения эти платформы малоэффективны. Они популярны только потому, что члены и посетители сайтов извлекают выгоду из опубликованных там материалов. И этот контент все больше доступен через мобильные устройства.

В настоящей статье показано, как использовать форматы обмена данными XML и JSON на платформе Android. Источником данных для примера приложения служит канал обновления статуса учетной записи Twitter. Этот канал данных доступен в Twitter в обоих форматах XML и JSON. Как вы увидите, при переходе от одного формата к другому подход к программированию для манипулирования данными существенно меняется.

Для работы с примером кода к этой статье я рекомендую установить Android SDK 1.5 или более поздней версии вместе с Eclipse. Подробнее о настройке этой среды можно прочесть на сайте Android Developers. Также полезно, но не обязательно, иметь активную учетную запись в Twitter, чтобы следить за примером. См. соответствующие ссылки в разделе Ресурсы.

Сначала кратко рассмотрим оба формата данных, начиная с XML. Если вы уже знакомы с XML и JSON, можете сразу перейти к разделу Возможности приложения: каналы Twitter и приступить к работе с ними на Android.

XML: старый друг

Избавление от тяжелого труда

Значение самоописательной природы XML становится очевидным, если вспомнить, что было до всеобщего принятия XML. Тогда для обмена данными требовалась трудоемкая разработка документов по описанию данных, которые часто составлялись и поддерживались вручную в текстовом процессоре или электронной таблице. Эти документы, так называемые спецификации интерфейса, описывали имена полей, их длину, разделители, иерархию и т.п. Пользователи делали это так, как считали нужным; ближе всего к стандарту был знакомый формат данных, разделенных запятыми (CSV). Но даже файлы CSV в значительной мере различались. Чтобы рассеять сомнения, попробуйте импортировать один такой файл в программу электронных таблиц и посмотрите, сколько возможно вариантов.

Практически каждый, кто в последние годы программировал для предприятий, Web или мобильных телефонов, сталкивался с XML. Он везде, куда ни глянь.

XML-документ имеет узнаваемую структуру: ряд элементов, которые могут содержать атрибуты и дочерние элементы. Каждый действительный документ XML начинается с декларации в первой строке: <?xml version="1.0" encoding="utf-8"?>. То, что следует за первой строкой, зависит от приложения. Красота XML – в его самоопределяемости.

XML-схемы

XML-документы говорят сами за себя, но они должны следовать определенным правилам и руководящим принципам. Здесь-то и появляется XML-схема. Это документ, который описывает структуру конкретного XML-файла. Такие структуры часто бывают очень пространными и сложными. (Пожалуй, худшим вкладом XML В ИТ стал взрывной рост объема данных, когда идея самоописательных структур данных вошла в моду, отчасти благодаря также значительному уменьшению стоимости дискового пространства в последнее десятилетие.)

Когда эти большие и сложные файлы стали нормой, программистам и аналитикам стало трудно овладеть искусством ручной работы с ними. Для решения этой проблемы появились XML-редакторы и инструменты валидации, которые помогали управлять файлами и связанными с ними задачами, такими как документирование и преобразование в традиционные форматы.

XML может использоваться не только для работы с обычными текстовыми данным и, но для хранения двоичных данных – с помощью специального набора тегов CDATA. Теги CDATA в XML-документе могут содержать любые данные, в том числе другой текст разметки, при условии, что этот текст не содержит самого тега CDATA.

API нередко используют эту возможность, применяя XML в качестве структуры для выполнения запросов типа запрос/ответ. Ответ часто содержит XML-структуру данных с тегом CDATA. Например, вызов API может запросить учетную запись клиента с фамилией Mott. Когда данные найдены, они упаковываются в XML-структуру и помещаются в элемент ответа, как в листинге 1.

Листинг 1. Упаковка данных в XML-структуру и их размещение в элементе ответа
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<request>
<query>
<lastname>Mott</lastname>
<maxhits>100</maxhits>
</query>
</request>

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<response>
<returncode>200</returncode>
<query>
<lastname>Mott</lastname>
<hits>1</hits>
</query>
<data>
<![CDATA[
<contact>
<firstname>Troy</firstname>
<lastname>Mott</lastname>
<age>not telling</age>
</contact>
]]>
</data>
</response>

XML в действии

Сегодня XML – это формат данных, ожидаемый по умолчанию. Хотя те же данные могут быть доступны и в других форматах, можно с полной уверенностью рассчитывать на наличие XML-структуры.

Системы Планирования ресурсов предприятия (ERP) интенсивно используют XML для решения задач импорта и экспорта данных. Новостные интернет-сайты часто предлагают каналы Really Simple Syndication (RSS) – XML-документы в заранее определенном формате, на обработку которого настроены программы чтения новостей. XML используют даже текстовые процессоры, такие как OpenOffice.org и Microsoft® Office.

Сегодня документы Microsoft Office – это PKZIP-совместимые файлы, содержащие несколько XML-документов. В первой строке каждый XML-файл содержит одну и ту же декларацию. Как вы видно из листинга 2, атрибуты могут быть довольно запутанными.

Листинг 2. Общая декларация в первой строке любого XML-файла.
 <?xml version="1.0" encoding="UTF-8" standalone="yes"?>
 <w:document xmlns:ve="http://schemas.openxmlformats.org/markup-compatibility/2006"
 xmlns:o="urn:schemas-microsoft-com:office:office"
 xmlns:r="http://schemas.openxmlformats.org/officeDocument/2006/relationships"
 xmlns:m="http://schemas.openxmlformats.org/officeDocument/2006/math"
 xmlns:v="urn:schemas-microsoft-com:vml"
 xmlns:wp="http://schemas.openxmlformats.org/drawingml/2006/wordprocessingDrawing"
 xmlns:w10="urn:schemas-microsoft-com:office:word"
 xmlns:w="http://schemas.openxmlformats.org/wordprocessingml/2006/main"
 xmlns:wne="http://schemas.microsoft.com/office/word/2006/wordml">
 <w:body><w:p w:rsidR="00B6337C" w:rsidRDefault="00663F0E"><w:r>
 <w:t xml:space="preserve">This is a sample </w:t></w:r><w:r
 w:rsidRPr="006906EA"><w:rPr><w:i/></w:rPr><w:t>Microsoft 
 Word document</w:t></w:r><w:r><w:t xml:space="preserve"> used
 to </w:t></w:r><w:r w:rsidRPr="006906EA"><w:rPr><w:b/>
 <w:u w:val="single"/></w:rPr><w:t>demonstrate</w:t></w:r>
 <w:r><w:t xml:space="preserve"> some XML topics.</w:t></w:r>
 </w:p><w:p w:rsidR="00B14B2A" w:rsidRDefault="00B14B2A"/><w:p 
 w:rsidR="00B14B2A"w:rsidRDefault="00B14B2A"><w:r><w:rPr>
 <w:noProof/></w:rPr><w:drawing><wp:inline distT="0" distB="0" 
 distL="0" distR="0"><wp:extent cx="3276600" cy="3838575"/><wp:effectExtent
 l="19050" t="0" r="0" b="0"/><wp:docPr id="1" name="Picture 0"
 descr="frankableson.jpg"/><wp:cNvGraphicFramePr><a:graphicFrameLocks
 xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"
 noChangeAspect="1"/></wp:cNvGraphicFramePr><a:graphic
 xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main"><a:graphicData
 uri="http://schemas.openxmlformats.org/drawingml/2006/picture"><pic:pic
 xmlns:pic="http://schemas.openxmlformats.org/drawingml/2006/picture">
 <pic:nvPicPr><pic:cNvPrid="0"name="frankableson.jpg"/><pic:cNvPicPr/>
 </pic:nvPicPr><pic:blipFill><a:blip r:embed="rId4"
 cstate="print"/><a:stretch><a:fillRect/></a:stretch>
 </pic:blipFill><pic:spPr><a:xfrm><a:off x="0" y="0"/>
 <a:ext cx="3276600" cy="3838575"/></a:xfrm><a:prstGeom
 prst="rect"><a:avLst/></a:prstGeom></pic:spPr></pic:pic>
 </a:graphicData></a:graphic></wp:inline></w:drawing>
 </w:r></w:p><w:p w:rsidR="00663F0E" w:rsidRDefault="00663F0E"/>
 <w:p w:rsidR="00CC16CE" w:rsidRDefault="00CC16CE"/><w:sectPr 
 w:rsidR="00CC16CE" w:rsidSect="00B6337C"><w:pgSz w:w="12240" w:h="15840"/>
 <w:pgMar w:top="1440" w:right="1440" w:bottom="1440" w:left="1440" w:header="720" 
 w:footer="720" w:gutter="0"/><w:cols w:space="720"/><w:docGrid
 w:linePitch="360"/></w:sectPr></w:body></w:document>

XML – самоописательный язык, но это не означает, что теги всегда должны быть наглядными. Этот пространный пример демонстрирует также использование нескольких пространств имен XML, что может делать XML-документы еще более сложными для понимания без специальных инструментов.

XML применяется везде, но для Android-программистов это часто плохой выбор, особенно если структура данных пала жертвой взрывного роста объема данных, которым часто сопровождаются XML-структуры. Платформа с ограниченными ресурсами, такая как Android, которая, как правило, работает через сотовую сеть передачи данных, не в состоянии хранить и анализировать большие объемы XML-данных. Однако если для конкретной задачи программирования требуется обмен как текстовыми, так и двоичными данными, XML может быть правильным выбором.

Теперь рассмотрим альтернативный формат обмена данными: JSON.


JSON: новый любимец Сети

Все больше и больше поставщиков интернет-API предлагают JSON в качестве одного из форматов данных. JSON сделал себе имя в сообществе Web-программистов Ajax (Asynchronous JavaScript и XML). Технология Ajax позволяет динамически обновлять Web-страницы путем обновления данных в отдельных карманах, а не всей страницы. Так как при этом передается меньше данных – и, что еще важнее, гораздо меньше данных анализируется и отображается в окне браузера – Ajax-приложения могут обеспечить пользователю гораздо лучший опыт, чем традиционные Web-приложения. Действительно, хорошо написанное Ajax-приложение способно соперничать по удобству работы для пользователя с приложениями для смарт- или толстых клиентов.

Когда Ajax-приложение обменивается данными с Web-сервером, оно часто запрашивает обновление тех или иных данных, но в идеале – без форматирования. Как правило, считается плохой практикой, когда Web-сервер передает отформатированный HTML-код. Вместо этого, хорошо написанное приложение должно отправлять данные в браузер и применять к нему файл каскадной таблицы стилей (CSS), чтобы создать визуальные эффекты, такие как цвет и начертание шрифта.

Предположим, что приложение должно запросить контактные данные нашего мифического г-на Mott. Приложение должно возвратить в браузер больше чем один элемент данных. Как же их упаковать? В примере из листинга 1 можно использовать простую структуру запрос/ответ в формате XML. Этого вполне достаточно, однако, требуется проанализировать каждый ответ сервера, сохранить данные в той или иной структуре (DOM), а затем обновить содержание Web-страницы.

Иначе, можно просто получить от сервера код JavaScript и работать непосредственно с ним. Вот пример ответа на запрос (http://<yourserver/app/searchcontact?Mott) от гипотетического приложения для человека по имени Mott. Это строковое представление объекта JavaScript – то есть строка JSON (здесь она разделена на две строки, чтобы соответствовать ширине страницы):

[{"firstname":"Troy","lastname":"Mott","age":"don't ask!"},{"firstname":"Apple seed",
   "lastname":"Mott's","age":"99"}]

В то время как XML известен своим многословием, JSON имеет репутацию трудночитаемого. Объекты JSON имеют формат пар ключ:значение. Элементы объекта разделены запятыми, и каждый объект заключен в фигурные скобки {}. Массив объектов заключается в квадратные скобки. Это общий подход к передаче набора строк из базы данных в массив объектов, при котором каждый элемент массива соответствует строке базы данных, а каждое свойство объекта представляет собой столбец данных.

В листинге 3 приведен пример использования такого объекта на странице HTML. Для простоты сообщения сервера не включены; вместо этого данные JSON предоставлены в виде строковой переменной с именем serverresponse.

Листинг 3. Использование объекта JSON на HTML-странице
<html>
<head>
<script language="JavaScript">
var serverresponse = "[{\"firstname\":\"Troy\",\"lastname\":\"Mott\",\"age\":\"don't
ask!\"},{\"firstname\":\"Apple seed\",\"lastname\":\"Mott's\",\"age\":\"99\"}]";
function updatepage()
{
    var contacts = eval(serverresponse );
    var i;
    var s = "Search Results:<br />";
    for (i=0;i<contacts.length;i++)
    {
        s = s + contacts[i].firstname + " " + contacts[i].lastname + "'s age is ... " 
+ contacts[i].age + "<br />";
    }
    document.getElementById("target").innerHTML = s;
}
</script>
</head>
<body>
<button onclick="updatepage();">Search for Mott</button><br />
<span id="target">&nbsp;</span>
</body>
</html>

Обратите внимание, что в этом примере используется функция JavaScript с именем eval(), чтобы превратить строку в массив JavaScript. Имеются библиотеки JSON для более быстрого и безопасного выполнения этого шага. Подход из листинга 3 – не лучший метод. Я привожу его здесь, чтобы показать, как можно использовать объект JSON в приложении Ajax: структура JSON принимается, анализируется и обрабатывается программой клиента.

Таким образом, JSON – это:

  • формат обмена данными;
  • средство кодирования объектов JavaScript в виде строк;
  • только текстовые и числовые значения. двоичные значения явно не допускается. JSON не имеет эквивалента CDATA;
  • более экономичный, чем XML, формат с точки зрения размера данных, но за счет читабельности;
  • все более распространенная опция у таких поставщиков API, как Twitter.

В листинге 3 клиент – это Web-браузер, работающий с клиентским сценарием. Возвращаясь к теме этой статьи, рассмотрим использование XML и JSON в приложении для Android.


Возможности применения: каналы Twitter

Twitter стал международной силой, поставляя новости обо всем от того, что люди едят на завтрак и как выступает школьная спортивная команда их ребенка, до таких серьезных тем, как новости с улиц, где происходят политические столкновения, или ход операции по пересадке органов.

Самый простой способ получить документы XML и JSON для использования с примером кода к этой статье – воспользоваться URL http://twitter.com/statuses/user_timeline/userid.format, где userid ваш идентификатор пользователя в Twitter, а format – XML или JSON.

Ссылку на эту страницу можно найти и непосредственно на своей странице Twitter, как показано на рисунке 1. На нем виден идентификатор пользователя Twitter.

Рисунок 1. Ссылка на страницу каналов на странице Twitter
Скриншот страницы fableson Twitter со ссылкой 'RSS fee of fableson's tweets' in lower right corner

Полные файлы каналов очень громоздки, так что следующие два листинга иллюстрируют только первую запись канала (только от моей учетной записи Twitter). Листинг 4 содержит фрагмент XML.

Листинг 4. Фрагмент XML
<?xml version="1.0" encoding="UTF-8"?>
<statuses type="array">
<status>
  <created_at>Thu Apr 29 05:25:29 +0000 2010</created_at>
  <id>13052369631</id>
  <text>Wrapping up new article on JSON for Android
 programmers...</text>
  <source><a href="http://www.linkedin.com/"rel="nofollow">
   LinkedIn</a></source>
  <truncated>false</truncated>
  <in_reply_to_status_id/>
  <in_reply_to_user_id/>
  <favorited>false</favorited>
  <in_reply_to_screen_name/>
  <user>
    <id>15221439</id>
    <name>fableson</name>
    <screen_name>fableson</screen_name>
    <location>Byram Township, NJ</location>
    <description/>

<profile_image_url>http://a3.twimg.com/profile_images/260492935
/bookcover_normal.jpg</profile_image_url>
    <url>http://msiservices.com</url>
    <protected>false</protected>
    <followers_count>52</followers_count>
    <profile_background_color>9ae4e8
    <profile_text_color>000000</profile_text_color>
    <profile_link_color>0000ff</profile_link_color>
    <profile_sidebar_fill_color>e0ff92
</profile_sidebar_fill_color>
    <profile_sidebar_border_color>87bc44
</profile_sidebar_border_color>
    <friends_count>10</friends_count>
    <created_at>Tue Jun 24 17:04:11 +0000 2008</created_at>
    <favourites_count>0</favourites_count>
    <utc_offset>-18000</utc_offset>
    <time_zone>Eastern Time (US & Canada)</time_zone>

   <profile_background_image_url>http://s.twimg.com/a/1272044617/
images/themes/theme1/bg.png</profile_background_image_url>

<profile_background_tile>false</profile_background_tile>
    <notifications>false</notifications>
    <geo_enabled>false</geo_enabled>

    <verified>false</verified>
    <following>false</following>
    <statuses_count>91</statuses_count>
    <lang>en</lang>
    <contributors_enabled>false</contributors_enabled>
  </user>
  <geo/>
  <coordinates/>
  <place/>
  <contributors/>
</status>
</statuses>

Листинг 5 демонстрирует те же данные, но на этот раз в формате JSON.

Листинг 5. Канал данных в формате JSON
[
{"in_reply_to_status_id":null,
"favorited":false,
"created_at":"Thu Apr 29 05:25:29 +0000 2010",
"in_reply_to_screen_name":null,
"geo":null,
"source":"<a href=\"http://www.linkedin.com/\" rel=\"nofollow\
          ">LinkedIn</a>",
"contributors":null,
"place":null,
"truncated":false,
"coordinates":null,
"user":
{
    "friends_count":10,
    "description":"",
    "lang":"en",
    "statuses_count":91,
    "time_zone":"Eastern Time (US & Canada)",
    "profile_link_color":"0000ff",
    "favourites_count":0,
    "created_at":"Tue Jun 24 17:04:11 +0000 2008",
    "contributors_enabled":false,
    "profile_sidebar_fill_color":"e0ff92",
    "following":null,
    "geo_enabled":false,
    "profile_background_image_url":"http://s.twimg.com/a/1272044617/images/themes
/theme1/bg.png",
    "profile_image_url":"http://a3.twimg.com/profile_images/260492935
/bookcover_normal.jpg",
    "notifications":null,
    "profile_sidebar_border_color":"87bc44",
    "url":"http://msiservices.com",
    "verified":false,
    "profile_background_tile":false,
    "screen_name":"fableson",
    "protected":false,
    "location":"Byram Township, NJ",
    "profile_background_color":"9ae4e8",
    "name":"fableson",
    "followers_count":52,
    "id":15221439,
    "utc_offset":-18000,
    "profile_text_color":"000000"
},
"in_reply_to_user_id":null,
"id":13052369631,
"text":"Wrapping up new article on JSON for Android programmers..."}
]

Обратите внимание, как много дополнительных данных, кроме простого обновления статуса, содержится в обоих листингах. Все, о чем нужно заботиться, – это дата/время сообщения и текст самого поста. Далее я покажу соответствующие части Android-приложения, которое анализирует эти данные. Весь проект приведен в разделе загрузок.


Приложение XMLvsJSON

Актуальные новости в реальном времени

Обратите внимание, что пример приложения не извлекает данные из Сети в режиме реального времени, хотя от приложения для чтения актуальных новостей этого можно было бы ожидать. Каналы данных берутся из папки необработанных ресурсов, так что приложение может сосредоточиться на аспектах анализа. В разделе Ресурсы есть ссылки на информацию о выполнении сетевых соединений с Android.

Android-приложение получилось простым. Оно содержит полные копии каналов данных XML и JSON и предоставляет пользователю возможность анализа любой из них. На рисунке 2 иллюстрируется структура файлов проекта в среде Eclipse. (См. текстовую версию рисунка 2.)

Рисунок 2. Структура файлов проекта Eclipse
Скриншот структуры файлов в Eclipse

На рисунке 3 показан пользовательский интерфейс приложения до выбора способа анализа.

Рисунок 3. Пользовательский интерфейс приложения до выбора способа анализа
Скриншот приложения's user interface prior to selecting a parsing option

Пользовательский интерфейс содержит две кнопки, Parse XML и Parse JSON file, за которыми следует текст по умолчанию. В листинге 6 приведен макет этого интерфейса, который находится в файле main.xml в папке res/layout проекта.

Листинг 6. Макет пользовательского интерфейса
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    >

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:gravity="center_horizontal">

<Button android:layout_width="wrap_content" android:layout_height="wrap_content"
 android:id="@+id/btnXML" android:text="Parse XML"></Button>
<Button android:layout_width="wrap_content" android:layout_height="wrap_content"
 android:id="@+id/btnJSON" android:text="Parse JSON file"></Button>
</LinearLayout>

<ScrollView xmlns:android="http://schemas.android.com/apk/res/android" 
android:id="@+id/ScrollView01" android:layout_width="fill_parent"
android:layout_height="wrap_content">

<TextView  
    android:layout_width="fill_parent" 
    android:layout_height="wrap_content" 
    android:text="default text" 
    android:layout_gravity="center_horizontal"
    android:id="@+id/txtData" 
    />
</ScrollView>

</LinearLayout>

Кнопки Parse XML и Parse JSON file определены над элементом ScrollView, который в свою очередь содержит элемент TextView. Идея здесь в том, чтобы пользователь мог прокручивать полученные данные на экране.

Обратите внимание на использование нескольких структур LinearLayout. Первая – это выравнивание по вертикали, и она содержит как LinearLayout с горизонтальной структурой, так и ScrollView. Внутренняя структура LinearLayout содержит два виджета Button. В листинге 7 этот макет расширен и связан с методом onCreate().

Листинг 7. Метод onCreate()
    Button btnXML;
    Button btnJSON;
    TextView tvData;
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
        tvData = (TextView) findViewById(R.id.txtData);
        btnXML = (Button) findViewById(R.id.btnXML);
        btnXML.setOnClickListener(new Button.OnClickListener()
        {
            public void onClick(View v)
            { 
                examineXMLFile();
            }
        });
        btnJSON = (Button) findViewById(R.id.btnJSON);
        btnJSON.setOnClickListener(new Button.OnClickListener()
        {
            public void onClick(View v)
            {
                examineJSONFile();
            }
        });

    }

Метод examineXMLFile() управляет анализом XML.


Анализ XML

SAX против DOM

Android поддерживает также парсер DOM, который занимает больше памяти, но несколько проще по сравнению с парсером SAX. Для таких приложений, как XMLvsJSON, которые имеют дело лишь с очень небольшой частью информационного канала, подход SAX, вероятно, – лучший инструмент.

Анализ XML-данных часто выполняется с помощью SAX-подобного парсера. При работе с таким парсером задается InputSource, который указывает на источник XML-данных, и создается обработчик, который получает определенные события при изменении документа. В листинге 8 показан метод examineXMLFile(), который решает следующие задачи:

  • настройка InputSource на XML-файл из необработанных ресурсов;
  • создание SAXParser, связанного с обработчиком twitterFeedHandler (см. листинг 9);
  • вызов анализатора и отображение результатов в виджете TextView, определенном в файле макета R.id.txtData и указанном в коде как tvData;
  • отображение любых ошибок, также в TextView.
Листинг 8. Метод examineXMLFIle()
void examineXMLFile()
    {
        try {
            InputSource is = new InputSource(getResources()
.openRawResource(R.raw.xmltwitter));
            // create the factory
            SAXParserFactory factory = SAXParserFactory.newInstance();
            // create a parser
            SAXParser parser = factory.newSAXParser();
            // create the reader (scanner)
            XMLReader xmlreader = parser.getXMLReader();
            // instantiate our handler
            twitterFeedHandler tfh = new twitterFeedHandler();

            // assign our handler
            xmlreader.setContentHandler(tfh);
            // perform the synchronous parse
            xmlreader.parse(is);
            // should be done... let's display our results
            tvData.setText(tfh.getResults());
        }
        catch (Exception e) {
            tvData.setText(e.getMessage());
        }
    }

Если examineXMLFile() выполняет настройку, то реальная работа по анализу с точки зрения приложения производится в обработчике, который реализован в файле twitterFeedHandler.Java. Этот класс, который реализует интерфейс DefaultHandler, приведен в листинге 9.

Листинг 9. Класс twitterFeedHandler
public class twitterFeedHandler extends DefaultHandler {  
    StringBuilder sb = null;
    String ret = "";
    boolean bStore = false;
    int howMany = 0;

    twitterFeedHandler() {
    }

    String getResults()
    {
        return "XML parsed data.\nThere are [" + howMany + "] status updates\n\n" + ret;
    }
    @Override

    public void startDocument() throws SAXException {
        // initialize "list"
    }

    @Override
    public void endDocument() throws SAXException {

    }

    @Override
    public void startElement(String namespaceURI, String localName, String qName, 
Attributes atts) throws SAXException {

        try {
            if (localName.equals("status")) {
                this.sb = new StringBuilder("");
                bStore = true;
            }
            if (localName.equals("user")) {
                bStore = false;
            }
            if (localName.equals("text")) {
                this.sb = new StringBuilder("");
            }
            if (localName.equals("created_at")) {
                this.sb = new StringBuilder("");
            }
        } catch (Exception ee) {

            Log.d("error in startElement", ee.getStackTrace().toString());
        }
    }

    @Override

    public void endElement(String namespaceURI, String localName, String qName)
throws SAXException {

        if (bStore) {
            if (localName.equals("created_at")) {

                ret += "Date: " + sb.toString() + "\n"; 
                sb = new StringBuilder("");
                return;

            }

            if (localName.equals("user")) {
                bStore = true;
            }

            if (localName.equals("text")) {

                ret += "Post: " + sb.toString() + "\n\n";
                sb = new StringBuilder("");
                return;

            }
        }
        if (localName.equals("status")) {
            howMany++;
            bStore = false;
        }
    }

    @Override

    public void characters(char ch[], int start, int length) {

        if (bStore) {
            String theString = new String(ch, start, length);

            this.sb.append(theString);
        }
    }

}

В листинге 9 есть некоторые примечательные моменты. Во-первых, нужно учесть, что парсер SAX – это парсер, основанный на событиях, что означает, что документ создается в момент обработки. События происходят, когда документ начинается или заканчивается, когда начинается или заканчивается тег и когда обнаруживаются данные. То есть нужно определить структуру данных, которая будет хранить данные, представляющие интерес, и отбрасывать все остальное.

Обратите внимание на StringBuilder и добавочные данные, которые используются потому, что конкретный элемент данных может быть обработан за несколько проходов чтения в InputSource. Никогда не рассчитывайте на то, что при любом вызове метода characters() предоставляются сразу все данные.

Это приложение собирает данные в просто отформатированную строку. Альтернативный пример может включать помещение этих записей в класс коллекции или базы данных, особенно, если большую часть манипуляций нужно проделывать после разбора.

Для этого класса обычно используется метод getResults(). Он собирает представление этой информации и передает его приложению. Он не входит в состав интерфейса DefaultHandler.

На рисунке 4 показаны обработанные данные XML. (См. текстовую версию рисунка 4.)

Рисунок 4. Анализируемые данные XML
Скриншот анализируемых данных XML с экрана мобильного телефона

Хотя разбор XML с помощью парсера SAX – нетривиальное решение с точки зрения создания, управления и навигации результирующей структуры, его основными преимуществами являются быстродействие и возможность значительно сократить объем оперативной памяти во время и после разбора.

Теперь рассмотрим подход Android к разбору данных JSON.


Анализ JSON

Анализ данных JSON в приложении начинается, когда пользователь выбирает кнопку JSON. При этом активизируется метод examineJSONFile(), приведенный в листинге 10. Никаких дополнительных классов обработчика не требуется, потому что весь разбор и управление документами осуществляется в прилагаемых к Android библиотеках, и весь JSON-код содержится в этом методе.

Листинг 10. Запуск метода examineJSONfile()
void examineJSONFile()  
    {
        try
        {
            String x = "";
            InputStream is = this.getResources().openRawResource(R.raw.jsontwitter);
            byte [] buffer = new byte[is.available()];
            while (is.read(buffer) != -1);
            String jsontext = new String(buffer);
            JSONArray entries = new JSONArray(jsontext);

            x = "JSON parsed.\nThere are [" + entries.length() + "]\n\n";

            int i;
            for (i=0;i<entries.length();i++)
            {
                JSONObject post = entries.getJSONObject(i);
                x += "------------\n";
                x += "Date:" + post.getString("created_at") + "\n";
                x += "Post:" + post.getString("text") + "\n\n";
            }
            tvData.setText(x);
        }
        catch (Exception je)
        {
            tvData.setText("Error w/file: " + je.getMessage());
        }
    }

Как и приведенная выше XML-программа, этот код считывает файл из необработанных ресурсов. Данные считываются в память в полном объеме, преобразуются в java.lang.String, а затем анализируются и записываются в JSONArray. Заметим, что строка может разбираться прямо в массиве, как в этом примере, или в JSONObject. Поскольку данные Twitter – это массив объектов, имеет смысл разобрать всю строку в массиве, а затем обращаться к объектам отдельно по порядку.

Поток для этого метода прост: как только данные проанализированы, код создает строковое представление, как это делается в обработчике для парсера XML. Здесь интересно то, что осуществляется управление данными; не нужно создавать дополнительные структуры памяти для хранения этих данных. Кроме того, приложение заранее "знает", сколько записей находится в JSONArray (В этом примере – 20).

Хотя разбор JSON гораздо проще с точки зрения программирования, это дается не даром. Добавляется память, в которую до начала обработки считывается весь поток данных и где затем хранятся все данные. Подход же SAX XML использует только те данные, который действительно представляют интерес. Это не важно, если памяти для разбора объекта JSON много; в этом случае данный подход может быть предпочтительным для многих приложений, особенно если не нужно работать с DOM.


Заключение

Эта статья знакомит с форматами обмена данными XML и JSON в контексте Android-приложений. По сравнению с подходом JSON, подход XML несколько быстрее и менее прожорлив на память – но за счет повышенной сложности. В части 2 я покажу некоторые способы объединения данных JSON, WebView-виджеты на основе WebKit, а также специальную логику динамического приложения для Android.


Загрузка

ОписаниеИмяРазмер
Пример исходного кодаxmlvsjosn.zip68 КБ

Ресурсы

Научиться

Получить продукты и технологии

Обсудить

Комментарии

developerWorks: Войти

Обязательные поля отмечены звездочкой (*).


Нужен IBM ID?
Забыли Ваш IBM ID?


Забыли Ваш пароль?
Изменить пароль

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Профиль создается, когда вы первый раз заходите в developerWorks. Информация в вашем профиле (имя, страна / регион, название компании) отображается для всех пользователей и будет сопровождать любой опубликованный вами контент пока вы специально не укажите скрыть название вашей компании. Вы можете обновить ваш IBM аккаунт в любое время.

Вся введенная информация защищена.

Выберите имя, которое будет отображаться на экране



При первом входе в developerWorks для Вас будет создан профиль и Вам нужно будет выбрать Отображаемое имя. Оно будет выводиться рядом с контентом, опубликованным Вами в developerWorks.

Отображаемое имя должно иметь длину от 3 символов до 31 символа. Ваше Имя в системе должно быть уникальным. В качестве имени по соображениям приватности нельзя использовать контактный e-mail.

Обязательные поля отмечены звездочкой (*).

(Отображаемое имя должно иметь длину от 3 символов до 31 символа.)

Нажимая Отправить, Вы принимаете Условия использования developerWorks.

 


Вся введенная информация защищена.


static.content.url=http://www.ibm.com/developerworks/js/artrating/
SITE_ID=40
Zone=XML
ArticleID=646762
ArticleTitle=Использование XML и JSON с Android: Часть 1. Преимущества JSON и XML для Android-приложений
publish-date=04132011