Работа с XML в Kotlin: библиотеки, парсинг и создание документов

Онлайн-тренажер Python для начинающих

Изучайте Python легко и без перегрузки теорией. Решайте практические задачи с автоматической проверкой, получайте подсказки на русском языке и пишите код прямо в браузере — без необходимости что-либо устанавливать.

Начать курс

Работа с XML в Kotlin: библиотеки, парсинг и создание документов

XML (eXtensible Markup Language) остаётся востребованным форматом для хранения и передачи структурированных данных, особенно в legacy-системах, конфигурационных файлах и веб-сервисах. Kotlin, будучи полностью совместимым с Java, предоставляет доступ ко всем классическим Java-библиотекам для работы с XML, а также имеет нативные решения. В этой статье мы разберём основные подходы: парсинг, создание и сериализацию XML-документов на Kotlin.

1. Встроенные средства JDK: DOM, SAX, StAX

Благодаря полной интероперабельности с Java, в Kotlin можно напрямую использовать стандартные API:

  • DOM (Document Object Model) — загружает весь документ в память, удобен для изменений.
  • SAX (Simple API for XML) — событийно-ориентированный парсер, минимальное потребление памяти.
  • StAX (Streaming API for XML) — потоковый парсер с курсорным или событийным подходом.

Пример парсинга XML с помощью DOM в Kotlin:

import javax.xml.parsers.DocumentBuilderFactory
import org.w3c.dom.Element

fun parseXmlWithDom(xmlString: String) {
    val factory = DocumentBuilderFactory.newInstance()
    val builder = factory.newDocumentBuilder()
    val document = builder.parse(xmlString.byteInputStream())
    val root = document.documentElement

    val items = root.getElementsByTagName("item")
    for (i in 0 until items.length) {
        val item = items.item(i) as Element
        val name = item.getElementsByTagName("name").item(0).textContent
        val price = item.getElementsByTagName("price").item(0).textContent
        println("Item: $name, Price: $price")
    }
}

2. Библиотека Simple XML (org.simpleframework.xml)

Simple XML — популярная библиотека для сериализации/десериализации объектов в XML. Она использует аннотации и не требует конфигурационных файлов. Отлично подходит для REST API с XML-ответами.

Подключение (Gradle):

implementation("org.simpleframework:simple-xml:2.7.1")

Пример модели и десериализации:

import org.simpleframework.xml.*
import org.simpleframework.xml.core.Persister

@Root(name = "catalog")
data class Catalog(
    @field:ElementList(inline = true)
    var books: List<Book> = emptyList()
)

@Root(name = "book")
data class Book(
    @field:Element(name = "title")
    var title: String = "",
    @field:Element(name = "author")
    var author: String = "",
    @field:Attribute(name = "id")
    var id: Int = 0
)

fun deserializeXml(xml: String): Catalog {
    val serializer = Persister()
    return serializer.read(Catalog::class.java, xml)
}

3. kotlinx.serialization с XML форматом

Для мультиплатформенных проектов (KMP) удобно использовать kotlinx.serialization с кастомным форматом XML. Существуют сторонние адаптеры, например kotlinx-serialization-xml (от сообщества).

Пример с библиотекой nl.adaptivity.xmlutil (поддерживает JVM, JS, Native):

import nl.adaptivity.xmlutil.serialization.XML
import kotlinx.serialization.*

@Serializable
data class Person(
    val name: String,
    @XmlSerialName("age")
    val years: Int
)

fun main() {
    val xml = XML {
        indent = 4
        xmlDeclMode = XmlDeclMode.Auto
    }
    val person = Person("Alice", 30)
    val result = xml.encodeToString(Person.serializer(), person)
    println(result)
    // <Person>
    //     <name>Alice</name>
    //     <age>30</age>
    // </Person>
}

4. XPath и XSLT в Kotlin

Для выборки данных по сложным критериям используйте XPath. В Kotlin это делается через стандартные Java-классы javax.xml.xpath.

Пример поиска всех элементов price с значением больше 100:

import javax.xml.parsers.DocumentBuilderFactory
import javax.xml.xpath.XPathFactory

fun queryWithXPath(xml: String) {
    val builder = DocumentBuilderFactory.newInstance().newDocumentBuilder()
    val doc = builder.parse(xml.byteInputStream())
    val xpath = XPathFactory.newInstance().newXPath()
    val expression = "//item[price > 100]/name/text()"
    val names = xpath.evaluate(expression, doc, javax.xml.xpath.XPathConstants.NODES_LIST)
    for (i in 0 until names.length) {
        println(names.item(i).nodeValue)
    }
}

Рекомендаций