Андрей Ващенко

Парсинг XML в объекты Room

При работе на одном из проектов возникло несколько проблем.
Сервер - 1С система; Интерфейс обмена - SOAP.
Андрей Ващенко
Android-разработчик
Первая проблема: в целом SOAP это тот же XML, но с некоторыми надстройками. Эти надстройки потребовалось убрать, чтобы работать с чистым XML.
<!-- до очистки -->

<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/">
    <soap:Body>
        <m:Response xmlns:m="tp.mobile">
            <m:return xmlns:xs="http://www.w3.org/2001/XMLSchema"
					xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
                <m:name>Название объекта</m:name>
                <m:error>Кол-во ошибок</m:error>
                <m:objects_qty>Кол-во объектов в ответе</m:objects_qty>
                <m:information version="3"
						is_deleted="false"
						hide="false">
                    <m:id>object_id</m:id>
					
                    <!-- остальные поля объекта -->
					
                </m:information>
				
                <!-- остальные объекты information -->
				
            </m:return>
        </m:Response>
    </soap:Body>
</soap:Envelope>

<!-- после очистки -->

<return>
	<name>Название объекта</name>
	<error>Кол-во ошибок</error>
	<objects_qty>Кол-во объектов в ответе</objects_qty>
	<information version="3" is_deleted="false" hide="false">
		<id>object_id</id>
		
		<!-- остальные поля объекта -->
		
	</information>
	
	<!-- остальные объекты information -->
</return>
Вторая проблема - тяжелые объекты. Помимо примитивных данных (строки, числа, даты, булевые значения и т. п.) приходили огромные картинки в формате base64. Вообще парсинг чего-либо - это сама по себе тяжелая задача для мобильного процессора. А с увеличением количества данных растет количество используемой оперативной памяти и увеличивается время выполнения операции. Если приходил очень большой объект, то приложение падало из-за OutOfMemoryError, а если не падало, то заметно долго выполняло операцию.

Третья проблема - в удобстве использования моделей данных. Приложение должно было хранить данные оффлайн. Для хранения использовали базу данных SQLite. В качестве обертки над SQLite - библиотеку Room. Работа с базой происходит в основном через модели. А т. к. парсер XML тоже работает с моделями, возникла идея не плодить по две модели на объект, а объединить эти модели в одну.
Решение проблемы
Для работы с XML использовали библиотеку SimpleXML. У SimpleXML есть DOM-парсер (ручной) и Pull-парсер (автоматизированный).

Преимущество Pull в том, что на вход он принимает xml и модель данных, которую необходимо получить. На выходе получается готовый объект. Недостаток Pull в том, что пока парсер будет искать требуемое поле в XML, он несколько раз пройдется по тем полям, которые он уже использовал. Это существенно замедляет производительность.

Преимущество DOM-парсера перекрывает недостаток Pull: движение по XML полностью контролируется разработчиком, и парсер не проходит несколько раз по уже использованным полям, но поля в модель приходится присваивать вручную. Этот парсер работает быстрее в несколько раз.

Далее будут изображены примерные алгоритмы обоих парсеров. Пожалуйста, не нужно воспринимать их как обучающее пособие. Главное - передать принцип. На практике под отдельную задачу придется писать свой код.
Алгоритм работы pull-парсера
Алгоритм работы DOM-парсера
Как можно заметить из алгоритмов, в DOM-парсере присутствует лишний вложенный цикл в отличие от Pull-парсера. Именно он замедляет процесс парсинга. Но, как я уже говорил, DOM-парсер быстрее настраивается, поэтому если объекты небольшие, то его можно использовать.

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

Для наглядности в приложении я посчитал разницу между временем начала парсинга и временем получения готовых объектов, тем самым получил время парсинга в миллисекундах для обоих парсеров. Результат приведен на скриншотах.
Главный экран приложения с выбором типа парсера
Время обработки данных через Pull-парсер
Время обработки данных через DOM-парсер
Для уменьшения количества моделей в 2 раза и для удобства разработки я объединил модели XML и Room. На рисунках ниже показаны модели отдельно и объединенная модель.

Преимущество объединенной модели не только в меньшем количестве классов. Самое главное преимущество в том, что не нужно конвертировать XML-модель в Room, чтобы сохранить объект в БД. То, что пришло с парсера, можно сразу же вставить в БД. А если возникнет потребность получить XML из объекта, то с объединенной моделью это можно сделать быстро и легко.


Room-модель объекта User
XML-модель объекта User
Объединенная модель объекта User
Вывод
В результате я получил большой опыт работы с библиотеками SimpleXML и Room. Проверил на практике два типа парсинга XML, изучил их преимущества и недостатки. Также я проверил идею с объединением моделей, она отлично себя показала. В любом случае, это отличный опыт. Если однажды мне придется работать с подобными проектами, то на парсер я потрачу гораздо меньше времени.
Спасибо за внимание!
BytePace © Все права защищены