Xml in Kotlin

Kotlin offers support for XML processing through third-party libraries. One popular library is kotlinx.serialization, which we’ll use in this example.

First, add the necessary dependencies to your project:

implementation("org.jetbrains.kotlinx:kotlinx-serialization-core:1.3.2")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-xml:1.3.2")

Now, let’s look at the code:

import kotlinx.serialization.*
import kotlinx.serialization.xml.*
import java.io.StringWriter

@Serializable
@SerialName("plant")
data class Plant(
    @SerialName("id")
    @XmlAttribute
    val id: Int,
    val name: String,
    val origin: List<String>
) {
    override fun toString(): String {
        return "Plant id=$id, name=$name, origin=$origin"
    }
}

fun main() {
    val coffee = Plant(27, "Coffee", listOf("Ethiopia", "Brazil"))

    // Emit XML representing our plant
    val format = Xml { indentString = "  " }
    val xmlString = format.encodeToString(Plant.serializer(), coffee)
    println(xmlString)

    // To add a generic XML header to the output, append it explicitly
    println("<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n$xmlString")

    // Use decodeFromString to parse a string of XML into a data structure
    val p = format.decodeFromString(Plant.serializer(), xmlString)
    println(p)

    val tomato = Plant(81, "Tomato", listOf("Mexico", "California"))

    // The @SerialName annotation can be used to nest elements
    @Serializable
    @SerialName("nesting")
    data class Nesting(
        @SerialName("parent")
        val plants: List<Plant>
    )

    val nesting = Nesting(listOf(coffee, tomato))

    val nestingXml = format.encodeToString(Nesting.serializer(), nesting)
    println(nestingXml)
}

This Kotlin code demonstrates XML serialization and deserialization using the kotlinx.serialization library. Here’s a breakdown of what’s happening:

  1. We define a Plant data class with XML-specific annotations.

  2. In the main function, we create a Plant instance for coffee.

  3. We use Xml.encodeToString() to serialize the Plant object to XML.

  4. We demonstrate how to add an XML header manually.

  5. We use Xml.decodeFromString() to deserialize the XML string back into a Plant object.

  6. We create another Plant instance for tomato.

  7. We define a Nesting class to demonstrate nested XML structures.

  8. Finally, we serialize the Nesting object, which contains both plants.

When you run this program, it will output:

<plant id="27">
  <name>Coffee</name>
  <origin>Ethiopia</origin>
  <origin>Brazil</origin>
</plant>

<?xml version="1.0" encoding="UTF-8"?>
<plant id="27">
  <name>Coffee</name>
  <origin>Ethiopia</origin>
  <origin>Brazil</origin>
</plant>

Plant id=27, name=Coffee, origin=[Ethiopia, Brazil]

<nesting>
  <parent>
    <plant id="27">
      <name>Coffee</name>
      <origin>Ethiopia</origin>
      <origin>Brazil</origin>
    </plant>
    <plant id="81">
      <name>Tomato</name>
      <origin>Mexico</origin>
      <origin>California</origin>
    </plant>
  </parent>
</nesting>

This example demonstrates how to work with XML in Kotlin, including serialization, deserialization, and handling nested structures.