Pull to refresh

Разбор XML при помощи Simple Framework

Reading time5 min
Views18K


Здравствуйте, читатели Хабрахабр!

Данный пост навеян другим постом и комментарием уважаемого хабраюзера AnatolyB оттуда.

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

И, конечно же, тем, кто еще не знаком с этой прекрасной библиотекой, рекомендую скорее познакомиться, я же постараюсь в этом вам помочь.

Intro


Simple Framework — это библиотека, совместимая с виртуальной машиной Android, предназначенная для сериализации/десериализации объектов Java в xml и обратно.

Основным достоинством Simple является декларативный подход к описанию связей между классами с их содержимым и XML представлением. Т.е. достаточно задать соответствующие атрибуты полям класса и можно тут же их сериализовать в XML, а при желании и обратно. Никакого дополнительного мусора, вроде перечисления нод, делать не нужно, все очень просто и прозрачно. Всю работу с сопоставления полей классов, их перечислением, получением значений и т.п. берет на себя Simple, а помогает ей в этом reflection.

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

Первым делом качаем саму библиотеку отсюда. Находим jar файл и копируем его в папку lib внутри нашего проекта. Далее добавляем наш jar в Build Path через «Add JARs...», и в итоге получаем что-то наподобие этого:


Примеры использования


Теперь мы можем использовать Simple в нашем проекте. И первое что мы попытаемся сделать это преобразуем простой XML в class Java.

Пусть у нас есть следующий XML:
<Pet>
   <Name>Bobby</Name>
   <Age>8</Age>
   <NickName>Lucky</NickName>
</Pet>


Он представляет сущность «домашнее животное», у которой есть обязательные поля: имя и возраст, а также одно необязательное: кличка.

Для того, чтобы связать этот XML с каким-то классом нам нужно создать класс и добавить к нему специальные атрибуты, чтобы Simple смог понять чего и как мы хотим сделать. Для нашего примера класс будет выглядеть вот так:
@Root(name="Pet")
public class MyPet 
{
    @Element(name="Name")
    public String name;
	
    @Element(name="Age")
    public int age;
	
    @Element(required=false, name="NickName")
    public String nickName;
}


Где:
  • Root — указывает на root'ый элемент XML.
  • Element — внутренние поля «Pet».
  • required — говорит, что это поле может быть опциональным.
  • name — указывает на имя элемента во входном XML, если это имя и поле класса совпадают, то данный атрибут может быть опущен.
Если поля Pet задавались бы атрибутами, а не элементами, то входной XML выглядел бы так:
<Pet Name="Bobby" Age="8" NickName="Lucky"/>

А наш класс выглядел бы вот так:
@Root(name="Pet")
public class MyPet 
{
    @Attribute(name="Name")
    public String name;
	
    @Attribute(name="Age")
    public int age;
	
    @Attribute(required=false, name="NickName")
    public String nickName;
}


Сам код по десериализации выглядит так:
Reader reader = new StringReader(xml);
Persister serializer = new Persister();
try 
{
    MyPet pet = serializer.read(MyPet.class, reader, false);
    Log.v("SimpleTest", "Pet Name" + pet.name);
} 
catch (Exception e) 
{
    Log.e("SimpleTest", e.getMessage());
}

В приведенном выше коде мы отдали на вход Simple serializer два параметра: MyPet.class — указание на класс с описанием атрибутов для десериализации и reader — поток содержащий входную XML. Как видно код совсем не сложный и очень компактный.

Код для обратного преобразования так же достаточно простой:
Writer writer = new StringWriter();
Serializer serializer = new Persister();
try 
{
    MyPet pet = new MyPet();
    pet.name = "Bobby";
    pet.age = 8;
    pet.nickName = "Lucky";

    serializer.write(pet, writer);
    String xml = writer.toString();
} 
catch (Exception e) 
{
    Log.e("SimpleTest", e.getMessage());
}

Для соблюдения принципа инкапсуляции, поля класса можно обернуть в get'еры и set'еры и Simple будет работать с ними:
@Root(name="Pet")
public class MyPet 
{
    private String name;    
    private int age;
    private String nickName;
    
    @Attribute(name="Name")
    public void setName(String name) 
    {
        this.name = name;
    }
    
    @Attribute(name="Name")
    public String getName() 
    {
        return name;           
    }
    
    @Attribute(name="Age")
    public void setAge(int age) 
    {
        this.age = age;
    }
    
    @Attribute(name="Age")
    public int getAge() 
    {
        return age;           
    }
    
    @Attribute(required=false, name="NickName")
    public void setNickName(String nickName) 
    {
        this.nickName = nickName;
    }
    
    @Attribute(required=false, name="NickName")
    public String getNickName() 
    {
        return nickName;           
    }
}

Если элемент XML имеет свои атрибуты или вложенные элементы, то его можно объявить отдельным классом или их списком. Модифицируем наш пример, добавим сущность «питомник» (nursery), которая может содержать произвольное число объектов «домашнее животное» (Pet). Пример:
<Nursery>
    <Pet Name="Bobby" Age="8" NickName="Lucky"/>
    <Pet Name="Rex" Age="3"/>
    <Pet Name="Pumba" Age="1"/>
</Nursery>

Для этого примера единственное, что нам нужно, это добавить класс для «Nursery»:
@Root(name="Nursery")
public class MyNursery 
{
    @ElementList(inline=true, name="Pet")
    public List<MyPet> pets;
}

Как видно, все так же просто. Ключевое слово inline говорит о том, что элементы «Pet» содержаться сразу внутри MyNursery, без использования промежуточного родительского элемента.

Код для загрузки «Nursery» аналогичен тому, что мы делали для «Pet»:
Reader reader = new StringReader(xml);
Persister serializer = new Persister();
try 
{
    MyNursery nursery = serializer.read(MyNursery.class, reader, false);
    Log.v("SimpleTest", "Pets in nursery: " + nursery.pets.size());
} 
catch (Exception e) 
{
    Log.e("SimpleTest", e.getMessage());
}

Я думаю этих примеров достаточно для начала самостоятельного разбирательство с библиотекой Simple. Тем более, что большое количество примеров представлено на официальном сайте.

Заключение


Simple предлагает решения, наверно, для всех конструкций, которые только возможны в XML. Так же поддерживаются такие возможности языка Java как: наследование и интерфейсы.

При использовании Simple можно отметить следующие положительные и отрицательные стороны.

Положительные:
  1. Простота в использовании и понимании.
  2. Количество кода при таком подходе минимально.
  3. Поддержка платформы Android.
  4. Богатые возможности по поддержке различных конструкций XML.
  5. Возможность применять в не Android приложениях, например в отвязанных от устройств Unit-тестах.
  6. Лицензия Apache, т.е. можно свободно использовать в коммерческом софте.

Отрицательные:
  1. Синтаксис Simple атрибутов перегружает представление классов.
  2. Для работы Simple применяется механизм Reflection'а, а это затратные операции. Поэтому, если вы собираетесь применять данный Framework в продукте требовательном к производительности, то стоит задуматься над целесообразностью такого решения.

Полезные ссылки

  1. Официальный сайт.
  2. Прямая ссылка на документацию.
  3. Другая статья на тему.
Tags:
Hubs:
+23
Comments13

Articles