XML - вельми популярний формат для обміну інформацією, хоча поступово здає свої позиції більш швидкому та економному формату JSON. Тим не менш, XML як і раніше використовується багатьма веб-сервісами, які надають котирування валют, прогноз погоди, осередки землетрусів і т. п.

Якщо ви скажете, що не знаєте, як виглядає XML-файл, то програмісти розсміються вам в обличчя. Розмітка вашого екрану, ресурси та інші файли вашої програми складаються з XML-файлів. Загальний принцип вам зрозумілий - безліч тегів в кутових дужках, які певним чином структуровані.

Читати такі файли людині не дуже приємно, в очах починає рябіти і хочеться спати. Тому необхідно використовувати спеціальні інструменти для обробки тексту - парсери, які перетворять XML-файл в легкий для читання текст.

Бібліотеки Android мають кілька наборів класів для роботи з XML-документами з довільною структурою і змістом, щоб заплутати програміста і позбавити його сну. Підтримуються технології SAX (Simple API for XML), pam Parser, Limited DOM Level 2 core support (об'єктна модель документів) та ін. Знаючі люди кажуть, що найкраще використовувати парсер XML Pull Parser - самий швидкий і легкий. Навіщо ж тоді напхали в систему інші парсери? На жаль, у нас немає відповіді. Насправді у кожної програми є свої плюси і мінуси і можливо для вашого випадку підійде якийсь певний парсер.

Pam Parser

Розглянемо парсер XML Pull Parser. Парсер дозволяє розбирати XML-документи за один прохід. Після проходу парсер представляє елементи документа у вигляді послідовності подій і тегів. На даний момент саме його рекомендує використовувати Google в Android-додатках.

Подивимося на документ очима парсера. Він бачить такі елементи документа:

START_DOCUMENT – початок документа;
START_TAG – початок тега;
TEXT – вміст елемента;
END_TAG – кінець тега;
END_DOCUMENT – кінець документа.

Кожний документ починається з події START_DOCUMENT і закінчується подією END_DOCUMENT. Позиція всередині документа представлена у вигляді поточного події, яке можна визначити, викликавши метод getEventType().

Для послідовного переходу по тегам потрібно викликати метод next(), який переміщує нас по ланцюжку подій, що збіглися, (іноді вкладених) START_TAG і END_TAG. Можна витягти ім'я будь-якого тега за допомогою методу getName() і отримати текст між кожним набором тегів за допомогою методу getNextText().

Щоб упакувати статичний XML-документ разом з вашим додатком, помістіть його в каталог res/xml/. Ви отримаєте можливість звертатися в коді програми до цього документа (операції читання і запису). Розглянемо завантаження XML-документа довільної структури ресурсів в код програми.

Створимо приклад програми, здатний читати список імен котів і їх домашніх телефонів, визначених у XML-файлі.

В каталозі res створити підкаталог xml, у якому буде розташовуватися наш ХМL-файл. У цьому файлі ми напишемо список котів і телефонів, і збережемо його під ім'ям contacts.xml.

<contacts>
<contact 
first_name="Кіт" 
last_name="Рижик"
phone="4516585"/>
<contact 
first_name="Кіт"
last_name="Барсик"
phone="4558963"/>
<contact 
first_name="Кішка"
last_name="Мурка"
phone="6254147"/>
<contact 
first_name="Кіт"
last_name="Бегемот"
phone="06666660"/>
</contacts>

Додамо в розмітку компонент ListView:

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity">
<ListView
android:id="@+id/listView"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"/>
</RelativeLayout>

Завантажити файл contacts.xml можна наступним чином:

XmlPullParser parser = getResources().getXml(R. xml.contacts);

Метод getXml() повертає XmlPullParser, який може прочитати завантажений документ XML в циклі while:

// продовжуємо, поки не досягнемо кінця документа
while (parser.getEventType()!= XmlPullParser.END_DOCUMENT) {
if (parser.getEventType() == XmlPullParser.START_TAG && parser.getName().equals("contact")) {
list.add(parser.getAttributeValue(0) + " " + parser.getAttributeValue(1) + "\n" + parser.getAttributeValue(2));
}
parser.next();
}

Як це відбувається? Запускаємо цикл while з умовою, що він буде працювати поки не досягне кінця документа, тобто закриваючого корінного тега (END_DOCUMENT).

Далі парсер починає переміщатися по тегам. Ми говоримо йому, що якщо (if) зустрінеш тег contact, то передай йому привіт та додай в масив текст з першого атрибута. І з другого атрибута. І з третього атрибута. Після чого даємо копняка парсеру з допомогою методу next(), щоб він ішов шукати далі.

У елемента contact ми визначили три атрибута first_name, last_name та phone, які завантажуються в список. Перші два атрибута поділяємо пробілом, а третій атрибут (номер телефону) виводимо на новому рядку.

Повністю код виглядає наступним чином:

import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;
import org.xmlpull.v1.XmlPullParser;
import java.util.ArrayList;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R. layout.activity_main);
ListView listView = (ListView) findViewById(R. id.listView);
ArrayList<String> list = new ArrayList<>();
try {
XmlPullParser parser = getResources().getXml(R. xml.contacts);
while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
if (parser.getEventType() == XmlPullParser.START_TAG && parser.getName().equals("contact")) {
 list.add(parser.getAttributeValue(0) + " " + parser.getAttributeValue(1) + "\n" + parser.getAttributeValue(2));
}
parser.next();
}
} catch (Throwable t) {
Toast.makeText(this, "Помилка при завантаженні XML-документа:" + t.toString(), Toast.LENGTH_LONG)
.show();
}
ArrayAdapter<String> adapter = new ArrayAdapter<>(this, android.R.layout.simple_list_item_1, list);
listView.setAdapter(adapter);
} }

Для закріплення матеріалу змінимо структуру документа. Нехай він буде виглядати наступним чином:

<?xml version="1.0" encoding="utf-8"?>
<data>
<contact>
<firstname>Кіт</firstname>
<lastname>Рижик</lastname>
<phone
home="4516585"
work="1111" />
</contact>
<contact>
<firstname>Кіт</firstname>
<lastname>Барсик</lastname>
<phone
home="4516586"
work="222" />
</contact>
<contact>
<firstname>Кішка</firstname>
<lastname>Мурка</lastname>
<phone
home="4516587"
work="3333" />
</contact>
</data>

А тепер напишемо код, який буде відслідковувати всі теги при розборі документа і виводити результат в лог.

@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R. layout.activity_main);
try {
XmlPullParser parser = getResources().getXml(R. xml.contacts);
while (parser.getEventType() != XmlPullParser.END_DOCUMENT) {
final String TAG = "ЛогКот";
String tmp = "";
switch (parser.getEventType()) {
case XmlPullParser.START_DOCUMENT:
Log.d(TAG, "Початок документа");
break;
// початок тега
case XmlPullParser.START_TAG:
Log.d(TAG, "START_TAG: ім'я тега =" + parser.getName() + ", рівень = " + parser.getDepth() + ", число атрибутів = " + parser.getAttributeCount());
tmp = "";
for (int i = 0; i < parser.getAttributeCount(); i++) {
tmp = tmp + parser.getAttributeName(i) + " = " + parser.getAttributeValue(i) + ", ";
}
if (!TextUtils.isEmpty(tmp))
Log.d(TAG, "Атрибути:" + tmp);
break;
// кінець тега
case XmlPullParser.END_TAG:
Log.d(TAG, "END_TAG: ім'я тега =" + parser.getName());
break;
// вміст тега
case XmlPullParser.TEXT:
Log.d(TAG, "текст =" + parser.getText());
break;
default:
break;
}
parser.next();
}
} catch (Throwable t) {
Toast.makeText(this, "Помилка при завантаженні XML-документа:" + t.toString(), Toast.LENGTH_LONG).show();
} }

Принцип той самий. Тільки на цей раз результат ми не виводимо в списку, а просто виводимо в лог. Для зручності поєднав картинку документа і лог на одному екрані, щоб наочно показати роботу парсера.

 

 

 

 

Якщо ви будете брати документ не з ресурсів, а з файлу з зовнішнього накопичувача, то отримання програми для обробки документа буде іншим:

//XmlPullParser parser = getResources().getXml(R. xml.contacts);
// з файлу на SD-карти
XmlPullParserFactory factory = XmlPullParserFactory.newInstance();
//factory.setNamespaceAware(true); // якщо використовується простір імен
XmlPullParser parser = factory.newPullParser();
File file = new File(Environment.getExternalStorageDirectory()+ "/sd-contacts.xml");
FileInputStream fis = new FileInputStream(file);
parser.setInput(new InputStreamReader(fis));

Це найпростіший приклад використання програми для читання документа з ресурсів. У реальних додатках вам доведеться отримувати інформацію з файлу, який знаходиться у інтернеті.

Вікторія Пряжнікова


2016-06-05 • Просмотров [ 41 ]