Одним из распространенных форматов хранения и передачи данных является xml. Рассмотрим, как с ним работать в приложении на Android.
Приложение может получать данные в формате xml различными способами - из ресурсов, из сети и т.д. В данном случае рассмотрим ситуацию, когда файл xml хранится в ресурсах.
Возьмем стандартный проект Android по умолчанию и в папке res создадим каталог xml. Для этого нажмем на каталог res правой кнопкой мыши и в контекстном меню выберем New -> Android Resource Directory:
В появившемся окне в качестве типа ресурсов укажем xml:
В этот каталог добавим новый файл, который назовем users.xml и который будет иметь следующее содержимое:
<?xml version="1.0" encoding="utf-8"?> <users> <user> <name>Tom</name> <age>36</age> </user> <user> <name>Alice</name> <age>32</age> </user> <user> <name>Bob</name> <age>28</age> </user> </users>
Это обычный файл xml, который хранит набор элементов user. Каждый элемент характеризуется наличием двух подэлементов - name и age. Условно говоря, каждый элемент описывает пользователя, у которого есть имя и возраст.
В папку, где находится основной класс MainActivity, добавим новый класс, который назовем User:
package com.example.xmlapp; public class User { private String name; private String age; public String getName(){ return name; } public String getAge(){ return age; } public void setName(String name){ this.name = name; } public void setAge(String age){ this.age = age; } public String toString(){ return "User: " + name + " - " + age; } }
Этот класс описывает товар, информация о котором будет извлекаться из xml-файла.
И в ту же папку добавим новый класс UserResourceParser:
Определим для класса UserResourceParser следующий код:
package com.example.xmlapp; import org.xmlpull.v1.XmlPullParser; import java.util.ArrayList; public class UserResourceParser { private ArrayList<User> users; public UserResourceParser(){ users = new ArrayList<>(); } public ArrayList<User> getUsers(){ return users; } public boolean parse(XmlPullParser xpp){ boolean status = true; User currentUser = null; boolean inEntry = false; String textValue = ""; try{ int eventType = xpp.getEventType(); while(eventType != XmlPullParser.END_DOCUMENT){ String tagName = xpp.getName(); switch (eventType){ case XmlPullParser.START_TAG: if("user".equalsIgnoreCase(tagName)){ inEntry = true; currentUser = new User(); } break; case XmlPullParser.TEXT: textValue = xpp.getText(); break; case XmlPullParser.END_TAG: if(inEntry){ if("user".equalsIgnoreCase(tagName)){ users.add(currentUser); inEntry = false; } else if("name".equalsIgnoreCase(tagName)){ currentUser.setName(textValue); } else if("age".equalsIgnoreCase(tagName)){ currentUser.setAge(textValue); } } break; default: } eventType = xpp.next(); } } catch (Exception e){ status = false; e.printStackTrace(); } return status; } }
Данный класс выполняет функции парсинга xml. Распарсенные данные будут храниться в переменной users. Непосредственно сам парсинг осуществляется
с помощью функции parse
. Основную работу выполняет передаваемый в качестве параметра объект XmlPullParser. Этот
класс позволяет пробежаться по всему документу xml и получить его содержимое.
Когда данный объект проходит по документу xml, при обнаружении определенного тега он генерирует некоторое событие. Есть четыре события, которые описываются следующими константами:
START_TAG
: открывающий тег элемента
TEXT
: прочитан текст элемента
END_TAG
: закрывающий тег элемента
END_DOCUMENT
: конец документа
С помощью метода getEventType()
можно получить первое событие и потом последовательно считывать документ, пока не дойдем до его конца.
Когда будет достигнут конец документа, то событие будет представлять константу END_DOCUMENT
:
int eventType = xpp.getEventType(); while(eventType != XmlPullParser.END_DOCUMENT){ //...................... eventType = xpp.next(); }
Для перехода к следующему событию применяется метод next()
.
При чтении документа с помощью метода getName()
можно получить название считываемого элемента.
String tagName = xpp.getName();
И в зависимости от названия тега и события мы можем выполнить определенные действия. Например, если это открывающий тег элемента user, то создаем новый объект User и устанавливаем, что мы находимся внутри элемента user:
case XmlPullParser.START_TAG: if("user".equalsIgnoreCase(tagName)){ inEntry = true; currentUser = new User(); } break;
Если событие TEXT
, то считано содержимое элемента, которое мы можем прочитать с помощью метода getText()
:
case XmlPullParser.TEXT: textValue = xpp.getText(); break;
Если закрывающий тег, то все зависит от того, какой элемент прочитан. Если прочитан элемент user, то добавляем объект User в коллекцию ArrayList и сбрываем переменную inEntry, указывая, что мы вышли из элемента user:
case XmlPullParser.END_TAG: if(inEntry){ if("user".equalsIgnoreCase(tagName)){ users.add(currentUser); inEntry = false;
Если прочитаны элементы name и age, то передаем их значения переменным name и age объекта User:
else if("name".equalsIgnoreCase(tagName)){ currentUser.setName(textValue); } else if("age".equalsIgnoreCase(tagName)){ currentUser.setAge(textValue); }
Теперь изменим класс MainActivity, который будет загружать ресурс xml:
package com.example.xmlapp; import androidx.appcompat.app.AppCompatActivity; import android.os.Bundle; import android.util.Log; import org.xmlpull.v1.XmlPullParser; public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); XmlPullParser xpp = getResources().getXml(R.xml.users); UserResourceParser parser = new UserResourceParser(); if(parser.parse(xpp)) { for(User prod: parser.getUsers()){ Log.d("XML", prod.toString()); } } } }
Вначале получаем ресурс xml с помощью метода getXml(), в который передается название ресурса. Данный метод возвращает объект XmlPullParser, который затем используется для парсинга. Для простоты просто выводим данные в окне Logcat: