Android Serialization Kotlin Samples

Android Kotlin serialization examples including JSON serialization, deserialization, and XML parsing

Key Facts

Category
Kotlin
Items
3
Format Families
json, xml, text

Sample Overview

Android Kotlin serialization examples including JSON serialization, deserialization, and XML parsing This sample set belongs to Kotlin and can be used to test related workflows inside Elysia Tools.

💻 JSON Serialization kotlin

🟡 intermediate ⭐⭐⭐

Convert objects to JSON strings using Gson and other libraries

⏱️ 25 min 🏷️ kotlin, android, json, serialization
Prerequisites: Intermediate Kotlin, Gson library
// Android Kotlin JSON Serialization Examples
// Using Gson library and kotlinx.serialization

import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.reflect.TypeToken
import java.lang.reflect.Type
import java.util.Date

// Data classes for serialization
data class User(
    val id: Int,
    val username: String,
    val email: String,
    val age: Int? = null,
    val isActive: Boolean = true,
    val createdAt: Date? = null
)

data class Product(
    val productId: String,
    val name: String,
    val price: Double,
    val tags: List<String>,
    val inStock: Boolean
)

data class Order(
    val orderId: Int,
    val user: User,
    val products: List<Product>,
    val totalAmount: Double,
    val orderDate: String
)

// 1. Basic JSON Serialization with Gson
class BasicJsonSerializer {

    private val gson: Gson = Gson()

    // Serialize simple object
    fun serializeObject(obj: Any): String {
        val json = gson.toJson(obj)
        println("Serialized: $json")
        return json
    }

    // Serialize with pretty printing
    fun serializeObjectPretty(obj: Any): String {
        val prettyGson = GsonBuilder()
            .setPrettyPrinting()
            .create()

        val json = prettyGson.toJson(obj)
        println("Serialized (pretty):\n$json")
        return json
    }

    // Serialize null values explicitly
    fun serializeWithNulls(obj: Any): String {
        val gsonWithNulls = GsonBuilder()
            .serializeNulls()
            .create()

        return gsonWithNulls.toJson(obj)
    }

    // Serialize date in custom format
    fun serializeWithDateFormat(obj: Any, dateFormat: String): String {
        val gsonWithDateFormat = GsonBuilder()
            .setDateFormat(dateFormat)
            .create()

        return gsonWithDateFormat.toJson(obj)
    }

    // Serialize with custom field naming
    fun serializeWithFieldNaming(obj: Any): String {
        val gsonWithLowercase = GsonBuilder()
            .setFieldNamingPolicy(
                com.google.gson.FieldNamingPolicy.LOWER_CASE_WITH_UNDERSCORES
            )
            .create()

        return gsonWithLowercase.toJson(obj)
    }
}

// 2. Advanced JSON Serialization
class AdvancedJsonSerializer {

    // Serialize with exclusion strategy
    fun serializeWithExclusion(obj: Any): String {
        val gson = GsonBuilder()
            .setExclusionStrategies(object : com.google.gson.ExclusionStrategy {
                override fun shouldSkipField(field: com.google.gson.FieldAttributes): Boolean {
                    // Skip fields with specific annotation
                    return field.getAnnotation(SkipSerialization::class.java) != null
                }

                override fun shouldSkipClass(clazz: Class<*>): Boolean {
                    return false
                }
            })
            .create()

        return gson.toJson(obj)
    }

    // Serialize with custom serializer
    fun serializeWithCustomSerializer(obj: Any): String {
        val gson = GsonBuilder()
            .registerTypeAdapter(Date::class.java, DateSerializer())
            .create()

        return gson.toJson(obj)
    }

    // Serialize to file
    fun serializeToFile(obj: Any, filePath: String): Boolean {
        return try {
            val gson = Gson()
            val json = gson.toJson(obj)

            java.io.FileWriter(filePath).use { writer ->
                writer.write(json)
            }

            println("Serialized to file: $filePath")
            true
        } catch (e: Exception) {
            println("Error serializing to file: ${e.message}")
            false
        }
    }

    // Serialize with versioning
    fun serializeWithVersion(obj: Any, version: Double): String {
        val gson = GsonBuilder()
            .setVersion(version)
            .create()

        return gson.toJson(obj)
    }
}

// 3. Collection Serialization
class CollectionSerializer {

    private val gson: Gson = Gson()

    // Serialize list
    fun <T> serializeList(list: List<T>): String {
        return gson.toJson(list)
    }

    // Serialize map
    fun <K, V> serializeMap(map: Map<K, V>): String {
        return gson.toJson(map)
    }

    // Serialize set
    fun <T> serializeSet(set: Set<T>): String {
        return gson.toJson(set)
    }

    // Serialize nested collections
    fun serializeNested(data: Map<String, List<Any>>): String {
        return gson.toJson(data)
    }

    // Serialize array
    fun <T> serializeArray(array: Array<T>): String {
        return gson.toJson(array)
    }
}

// 4. Streaming JSON Serialization
class StreamingJsonSerializer {

    // Serialize using JsonWriter (for large datasets)
    fun serializeUsingJsonWriter(data: List<User>, filePath: String): Boolean {
        return try {
            java.io.FileWriter(filePath).use { writer ->
                val jsonWriter = com.google.gson.stream.JsonWriter(writer)

                jsonWriter.beginArray()
                for (user in data) {
                    jsonWriter.beginObject()

                    jsonWriter.name("id").value(user.id.toLong())
                    jsonWriter.name("username").value(user.username)
                    jsonWriter.name("email").value(user.email)
                    user.age?.let { jsonWriter.name("age").value(it.toLong()) }
                    jsonWriter.name("isActive").value(user.isActive)

                    jsonWriter.endObject()
                }
                jsonWriter.endArray()

                jsonWriter.close()
            }

            println("Streamed ${data.size} items to $filePath")
            true
        } catch (e: Exception) {
            println("Error streaming JSON: ${e.message}")
            false
        }
    }

    // Serialize with buffering
    fun serializeWithBuffer(data: List<Any>, bufferSize: Int): List<String> {
        val chunks = mutableListOf<String>()
        val gson = Gson()

        data.chunked(bufferSize).forEach { chunk ->
            chunks.add(gson.toJson(chunk))
        }

        return chunks
    }
}

// 5. Kotlinx Serialization (Alternative)
// Note: Requires kotlinx-serialization plugin
object KotlinxSerializer {

    // Example using kotlinx.serialization (if plugin is enabled)
    // @Serializable
    // data class UserKotlinx(
    //     val id: Int,
    //     val username: String,
    //     val email: String
    // )

    // fun serializeKotlinx(obj: Any): String {
    //     return Json.encodeToString(obj)
    // }
}

// 6. Custom Date Serializer
class DateSerializer : com.google.gson.JsonSerializer<Date> {
    override fun serialize(
                    src: Date,
                    typeOfSrc: Type,
                    context: com.google.gson.JsonSerializationContext
    ): com.google.gson.JsonElement {
        val formatter = java.text.SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS'Z'")
        return com.google.gson.JsonPrimitive(formatter.format(src))
    }
}

// Annotation for skipping fields
@Target(AnnotationTarget.FIELD)
@Retention(AnnotationRetention.RUNTIME)
annotation class SkipSerialization

// Main demonstration
fun demonstrateJsonSerialization() {
    println("=== Android Kotlin JSON Serialization Examples ===\n")

    // 1. Basic serialization
    println("--- 1. Basic Serialization ---")
    val basicSerializer = BasicJsonSerializer()

    val user = User(
        id = 1,
        username = "alice",
        email = "[email protected]",
        age = 25,
        isActive = true,
        createdAt = Date()
    )

    val json1 = basicSerializer.serializeObject(user)
    println("Simple: $json1")

    // 2. Pretty printing
    println("\n--- 2. Pretty Printing ---")
    val json2 = basicSerializer.serializeObjectPretty(user)

    // 3. Serialization with nulls
    println("\n--- 3. Serialize with Nulls ---")
    val userWithNulls = User(
        id = 2,
        username = "bob",
        email = "[email protected]",
        age = null,
        isActive = true
    )

    val json3 = basicSerializer.serializeWithNulls(userWithNulls)
    println("With nulls: $json3")

    // 4. Date formatting
    println("\n--- 4. Date Formatting ---")
    val json4 = basicSerializer.serializeWithDateFormat(
        user,
        "yyyy-MM-dd HH:mm:ss"
    )
    println("Custom date format: $json4")

    // 5. Complex object
    println("\n--- 5. Complex Object Serialization ---")
    val order = Order(
        orderId = 1001,
        user = user,
        products = listOf(
            Product("P001", "Laptop", 999.99, listOf("Electronics", "Computers"), true),
            Product("P002", "Mouse", 29.99, listOf("Electronics", "Accessories"), true)
        ),
        totalAmount = 1029.98,
        orderDate = "2025-12-27"
    )

    val json5 = basicSerializer.serializeObjectPretty(order)
    println("Order:\n$json5")

    // 6. Collections
    println("\n--- 6. Collection Serialization ---")
    val collectionSerializer = CollectionSerializer()

    val users = listOf(
        User(1, "alice", "[email protected]", 25),
        User(2, "bob", "[email protected]", 30),
        User(3, "charlie", "[email protected]", 28)
    )

    val usersJson = collectionSerializer.serializeList(users)
    println("Users list: $usersJson")

    val userMap = mapOf(
        "user1" to users[0],
        "user2" to users[1],
        "user3" to users[2]
    )

    val mapJson = collectionSerializer.serializeMap(userMap)
    println("Users map: $mapJson")

    // 7. Field naming policy
    println("\n--- 7. Field Naming Policy ---")
    val json6 = basicSerializer.serializeWithFieldNaming(user)
    println("Lowercase with underscores: $json6")

    // 8. Versioning
    println("\n--- 8. Versioning ---")
    val advancedSerializer = AdvancedJsonSerializer()
    val json7 = advancedSerializer.serializeWithVersion(user, 1.0)
    println("Version 1.0: $json7")

    println("\n=== All JSON Serialization Examples Completed ===")
}

💻 JSON Deserialization kotlin

🟡 intermediate ⭐⭐⭐⭐

Parse JSON strings and convert them to objects using Gson

⏱️ 30 min 🏷️ kotlin, android, json, parsing
Prerequisites: Intermediate Kotlin, Gson library
// Android Kotlin JSON Deserialization Examples
// Using Gson library for parsing JSON

import com.google.gson.Gson
import com.google.gson.GsonBuilder
import com.google.gson.reflect.TypeToken
import com.google.gson.JsonSyntaxException
import java.lang.reflect.Type

// Data classes for deserialization
data class User(
    val id: Int,
    val username: String,
    val email: String,
    val age: Int? = null,
    val isActive: Boolean = true,
    val createdAt: String? = null
)

data class Product(
    val productId: String,
    val name: String,
    val price: Double,
    val tags: List<String>,
    val inStock: Boolean
)

data class ApiResponse<T>(
    val success: Boolean,
    val data: T?,
    val message: String?,
    val errorCode: Int?
)

// 1. Basic JSON Deserialization
class BasicJsonDeserializer {

    private val gson: Gson = Gson()

    // Deserialize to simple object
    fun <T> deserializeObject(json: String, classOfT: Class<T>): T? {
        return try {
            val obj = gson.fromJson(json, classOfT)
            println("Deserialized: $obj")
            obj
        } catch (e: JsonSyntaxException) {
            println("Error deserializing: ${e.message}")
            null
        }
    }

    // Deserialize with pretty JSON handling
    fun <T> deserializePretty(json: String, classOfT: Class<T>): T? {
        return try {
            gson.fromJson(json, classOfT)
        } catch (e: Exception) {
            println("Error: ${e.message}")
            null
        }
    }

    // Deserialize with default values
    fun deserializeWithDefaults(json: String): User? {
        return try {
            gson.fromJson(json, User::class.java)
        } catch (e: Exception) {
            println("Error: ${e.message}")
            null
        }
    }
}

// 2. Collection Deserialization
class CollectionDeserializer {

    private val gson: Gson = Gson()

    // Deserialize JSON array to list
    fun <T> deserializeList(json: String, classOfT: Class<T>): List<T> {
        val listType = TypeToken.getParameterized(List::class.java, classOfT).type
        return try {
            gson.fromJson(json, listType) ?: emptyList()
        } catch (e: Exception) {
            println("Error deserializing list: ${e.message}")
            emptyList()
        }
    }

    // Deserialize JSON object to map
    fun deserializeMap(json: String): Map<String, Any> {
        val mapType = object : TypeToken<Map<String, Any>>() {}.type
        return try {
            gson.fromJson(json, mapType) ?: emptyMap()
        } catch (e: Exception) {
            println("Error deserializing map: ${e.message}")
            emptyMap()
        }
    }

    // Deserialize to set
    fun <T> deserializeSet(json: String, classOfT: Class<T>): Set<T> {
        val setType = TypeToken.getParameterized(Set::class.java, classOfT).type
        return try {
            gson.fromJson(json, setType) ?: emptySet()
        } catch (e: Exception) {
            println("Error deserializing set: ${e.message}")
            emptySet()
        }
    }

    // Deserialize nested collections
    fun deserializeNestedList(json: String): List<List<String>> {
        val nestedType = object : TypeToken<List<List<String>>>() {}.type
        return try {
            gson.fromJson(json, nestedType) ?: emptyList()
        } catch (e: Exception) {
            println("Error deserializing nested list: ${e.message}")
            emptyList()
        }
    }
}

// 3. Advanced Deserialization
class AdvancedJsonDeserializer {

    private val gson: Gson = Gson()

    // Deserialize from file
    fun <T> deserializeFromFile(filePath: String, classOfT: Class<T>): T? {
        return try {
            val file = java.io.File(filePath)
            val json = file.readText()

            gson.fromJson(json, classOfT)
        } catch (e: Exception) {
            println("Error reading from file: ${e.message}")
            null
        }
    }

    // Deserialize with custom date format
    fun deserializeWithDateFormat(json: String, dateFormat: String): User? {
        val gsonWithDateFormat = GsonBuilder()
            .setDateFormat(dateFormat)
            .create()

        return try {
            gsonWithDateFormat.fromJson(json, User::class.java)
        } catch (e: Exception) {
            println("Error with custom date format: ${e.message}")
            null
        }
    }

    // Deserialize with lenient mode
    fun deserializeLenient(json: String): User? {
        val lenientGson = GsonBuilder()
            .setLenient()
            .create()

        return try {
            lenientGson.fromJson(json, User::class.java)
        } catch (e: Exception) {
            println("Error in lenient mode: ${e.message}")
            null
        }
    }

    // Deserialize generic type
    fun <T> deserializeGeneric(json: String, type: Type): T? {
        return try {
            gson.fromJson(json, type)
        } catch (e: Exception) {
            println("Error deserializing generic: ${e.message}")
            null
        }
    }

    // Deserialize ApiResponse wrapper
    fun <T> deserializeApiResponse(json: String, dataType: Type): ApiResponse<T>? {
        val apiResponseType = TypeToken.getParameterized(
            ApiResponse::class.java,
            dataType
        ).type

        return try {
            gson.fromJson(json, apiResponseType)
        } catch (e: Exception) {
            println("Error deserializing API response: ${e.message}")
            null
        }
    }
}

// 4. Safe Deserialization with Validation
class SafeJsonDeserializer {

    private val gson: Gson = Gson()

    // Deserialize with validation
    fun <T> deserializeWithValidation(
                    json: String,
                    classOfT: Class<T>,
                    validator: (T) -> Boolean
    ): T? {
        return try {
            val obj = gson.fromJson(json, classOfT)

            if (validator(obj)) {
                obj
            } else {
                println("Validation failed")
                null
            }
        } catch (e: Exception) {
            println("Error: ${e.message}")
            null
        }
    }

    // Deserialize with fallback
    fun <T> deserializeWithFallback(
                    json: String,
                    classOfT: Class<T>,
                    fallback: T
    ): T {
        return try {
            gson.fromJson(json, classOfT) ?: fallback
        } catch (e: Exception) {
            println("Error, using fallback: ${e.message}")
            fallback
        }
    }

    // Deserialize nullable fields
    fun deserializeNullable(json: String): User? {
        return try {
            gson.fromJson(json, User::class.java)
        } catch (e: Exception) {
            println("Error with nullable: ${e.message}")
            null
        }
    }
}

// 5. Streaming JSON Deserialization
class StreamingJsonDeserializer {

    // Parse large JSON files using JsonReader
    fun parseLargeJson(filePath: String): List<User> {
        val users = mutableListOf<User>()

        try {
            java.io.FileReader(filePath).use { reader ->
                val jsonReader = com.google.gson.stream.JsonReader(reader)

                jsonReader.beginArray()

                while (jsonReader.hasNext()) {
                    jsonReader.beginObject()

                    var id = 0
                    var username = ""
                    var email = ""
                    var age: Int? = null
                    var isActive = true

                    while (jsonReader.hasNext()) {
                        when (jsonReader.nextName()) {
                            "id" -> id = jsonReader.nextInt()
                            "username" -> username = jsonReader.nextString()
                            "email" -> email = jsonReader.nextString()
                            "age" -> age = jsonReader.nextInt()
                            "isActive" -> isActive = jsonReader.nextBoolean()
                        }
                    }

                    jsonReader.endObject()

                    users.add(User(id, username, email, age, isActive))
                }

                jsonReader.endArray()
                jsonReader.close()
            }
        } catch (e: Exception) {
            println("Error streaming JSON: ${e.message}")
        }

        return users
    }

    // Parse specific fields only
    fun parseSpecificFields(json: String, fields: Set<String>): Map<String, String> {
        val result = mutableMapOf<String, String>()

        try {
            java.io.StringReader(json).use { reader ->
                val jsonReader = com.google.gson.stream.JsonReader(reader)

                jsonReader.beginObject()

                while (jsonReader.hasNext()) {
                    val name = jsonReader.nextName()
                    if (name in fields) {
                        result[name] = jsonReader.nextString()
                    } else {
                        jsonReader.skipValue()
                    }
                }

                jsonReader.endObject()
                jsonReader.close()
            }
        } catch (e: Exception) {
            println("Error parsing fields: ${e.message}")
        }

        return result
    }
}

// 6. JSON Path Query (Simple)
class JsonPathQuery {

    private val gson: Gson = Gson()

    // Get nested value
    fun getNestedValue(json: String, path: String): String? {
        return try {
            val jsonObj = gson.fromJson(json, com.google.gson.JsonObject::class.java)
            val parts = path.split(".")

            var current: com.google.gson.JsonElement = jsonObj

            for (part in parts) {
                if (current.isJsonObject) {
                    current = current.asJsonObject.get(part)
                }
            }

            current.asString
        } catch (e: Exception) {
            println("Error getting nested value: ${e.message}")
            null
        }
    }

    // Check if field exists
    fun hasField(json: String, fieldName: String): Boolean {
        return try {
            val jsonObj = gson.fromJson(json, com.google.gson.JsonObject::class.java)
            jsonObj.has(fieldName)
        } catch (e: Exception) {
            false
        }
    }

    // Extract all values of a field from array
    fun extractFieldFromArray(json: String, fieldName: String): List<String> {
        val values = mutableListOf<String>()

        try {
            val jsonArray = gson.fromJson(json, com.google.gson.JsonArray::class.java)

            for (element in jsonArray) {
                val obj = element.asJsonObject
                if (obj.has(fieldName)) {
                    values.add(obj.get(fieldName).asString)
                }
            }
        } catch (e: Exception) {
            println("Error extracting field: ${e.message}")
        }

        return values
    }
}

// Main demonstration
fun demonstrateJsonDeserialization() {
    println("=== Android Kotlin JSON Deserialization Examples ===\n")

    // 1. Basic deserialization
    println("--- 1. Basic Deserialization ---")
    val basicDeserializer = BasicJsonDeserializer()

    val userJson = """{"id":1,"username":"alice","email":"[email protected]","age":25,"isActive":true}"""
    val user = basicDeserializer.deserializeObject(userJson, User::class.java)
    println("Deserialized user: $user")

    // 2. Pretty JSON
    println("\n--- 2. Pretty JSON ---")
    val prettyJson = """
        {
            "id": 2,
            "username": "bob",
            "email": "[email protected]",
            "age": 30,
            "isActive": true
        }
    """.trimIndent()

    val user2 = basicDeserializer.deserializePretty(prettyJson, User::class.java)
    println("Deserialized from pretty: $user2")

    // 3. Collection deserialization
    println("\n--- 3. Collection Deserialization ---")
    val collectionDeserializer = CollectionDeserializer()

    val usersJson = """[
        {"id":1,"username":"alice","email":"[email protected]"},
        {"id":2,"username":"bob","email":"[email protected]"},
        {"id":3,"username":"charlie","email":"[email protected]"}
    ]"""

    val users = collectionDeserializer.deserializeList(usersJson, User::class.java)
    println("Deserialized ${users.size} users:")
    users.forEach { println("  - ${it.username}") }

    // 4. Map deserialization
    val mapJson = """{"name":"Product","price":29.99,"inStock":true}"""
    val map = collectionDeserializer.deserializeMap(mapJson)
    println("\nDeserialized map: $map")

    // 5. Generic deserialization
    println("\n--- 5. Generic Type Deserialization ---")
    val advancedDeserializer = AdvancedJsonDeserializer()

    val apiResponseJson = """
        {
            "success": true,
            "data": {"id":1,"username":"alice","email":"[email protected]"},
            "message": "User found",
            "errorCode": null
        }
    """.trimIndent()

    val userType = object : TypeToken<User>() {}.type
    val response = advancedDeserializer.deserializeApiResponse<User>(apiResponseJson, userType)
    println("API Response: success=${response?.success}, data=${response?.data}")

    // 6. Safe deserialization
    println("\n--- 6. Safe Deserialization ---")
    val safeDeserializer = SafeJsonDeserializer()

    val validatedUser = safeDeserializer.deserializeWithValidation(
        userJson,
        User::class.java
    ) { user -> user.email.contains("@") }

    println("Validated user: $validatedUser")

    val fallbackUser = safeDeserializer.deserializeWithFallback(
        "{invalid json}",
        User::class.java,
        User(0, "fallback", "[email protected]")
    )
    println("Fallback user: $fallbackUser")

    // 7. JSON path
    println("\n--- 7. JSON Path Query ---")
    val pathQuery = JsonPathQuery()

    val complexJson = """
        {
            "user": {
                "id": 1,
                "profile": {
                    "username": "alice",
                    "email": "[email protected]"
                }
            }
        }
    """.trimIndent()

    val email = pathQuery.getNestedValue(complexJson, "user.profile.email")
    println("Extracted email: $email")

    val hasField = pathQuery.hasField(complexJson, "user")
    println("Has 'user' field: $hasField")

    println("\n=== All JSON Deserialization Examples Completed ===")
}

💻 XML Parsing kotlin

🟡 intermediate ⭐⭐⭐⭐

Parse XML documents using XmlPullParser and DOM parser

⏱️ 30 min 🏷️ kotlin, android, xml, parsing
Prerequisites: Intermediate Kotlin, XML basics
// Android Kotlin XML Parsing Examples
// Using XmlPullParser and DOM parser

import org.xmlpull.v1.XmlPullParser
import org.xmlpull.v1.XmlPullParserFactory
import org.w3c.dom.Document
import org.w3c.dom.Element
import org.w3c.dom.Node
import org.w3c.dom.NodeList
import javax.xml.parsers.DocumentBuilderFactory
import java.io.StringReader

// Data classes for XML
data class Book(
    val id: Int,
    val title: String,
    val author: String,
    val price: Double,
    val genre: String?
)

data class User(
    val id: Int,
    val username: String,
    val email: String,
    val address: Address?
)

data class Address(
    val street: String,
    val city: String,
    val country: String
)

// 1. Basic XML Parsing with XmlPullParser
class BasicXmlParser {

    // Parse simple XML document
    fun parseSimpleXml(xml: String): List<Book> {
        val books = mutableListOf<Book>()
        val factory = XmlPullParserFactory.newInstance()
        val parser = factory.newPullParser()

        parser.setInput(StringReader(xml))

        var eventType = parser.eventType
        var currentId = 0
        var currentTitle = ""
        var currentAuthor = ""
        var currentPrice = 0.0
        var currentGenre: String? = null

        while (eventType != XmlPullParser.END_DOCUMENT) {
            when (eventType) {
                XmlPullParser.START_TAG -> {
                    when (parser.name) {
                        "book" -> {
                            currentId = parser.getAttributeValue(null, "id").toInt()
                        }
                        "title" -> {
                            currentTitle = parser.nextText()
                        }
                        "author" -> {
                            currentAuthor = parser.nextText()
                        }
                        "price" -> {
                            currentPrice = parser.nextText().toDouble()
                        }
                        "genre" -> {
                            currentGenre = parser.nextText()
                        }
                    }
                }
                XmlPullParser.END_TAG -> {
                    if (parser.name == "book") {
                        books.add(Book(currentId, currentTitle, currentAuthor, currentPrice, currentGenre))
                    }
                }
            }
            eventType = parser.next()
        }

        return books
    }

    // Parse XML with nested elements
    fun parseNestedXml(xml: String): List<User> {
        val users = mutableListOf<User>()
        val factory = XmlPullParserFactory.newInstance()
        val parser = factory.newPullParser()

        parser.setInput(StringReader(xml))

        var eventType = parser.eventType
        var currentId = 0
        var currentUsername = ""
        var currentEmail = ""
        var currentStreet = ""
        var currentCity = ""
        var currentCountry = ""
        var inAddress = false

        while (eventType != XmlPullParser.END_DOCUMENT) {
            when (eventType) {
                XmlPullParser.START_TAG -> {
                    when (parser.name) {
                        "user" -> {
                            currentId = parser.getAttributeValue(null, "id").toInt()
                        }
                        "username" -> currentUsername = parser.nextText()
                        "email" -> currentEmail = parser.nextText()
                        "address" -> inAddress = true
                        "street" -> if (inAddress) currentStreet = parser.nextText()
                        "city" -> if (inAddress) currentCity = parser.nextText()
                        "country" -> if (inAddress) currentCountry = parser.nextText()
                    }
                }
                XmlPullParser.END_TAG -> {
                    if (parser.name == "user") {
                        val address = if (currentStreet.isNotEmpty()) {
                            Address(currentStreet, currentCity, currentCountry)
                        } else null

                        users.add(User(currentId, currentUsername, currentEmail, address))

                        // Reset
                        currentStreet = ""
                        currentCity = ""
                        currentCountry = ""
                        inAddress = false
                    }
                }
            }
            eventType = parser.next()
        }

        return users
    }
}

// 2. DOM Parser
class DomXmlParser {

    // Parse XML using DOM
    fun parseWithDom(xml: String): List<Book> {
        val books = mutableListOf<Book>()

        try {
            val factory = DocumentBuilderFactory.newInstance()
            val builder = factory.newDocumentBuilder()
            val document = builder.parse(
                javax.xml.parsers.InputSource(StringReader(xml))
            )

            val bookNodes = document.getElementsByTagName("book")

            for (i in 0 until bookNodes.length) {
                val bookElement = bookNodes.item(i) as Element

                val id = bookElement.getAttribute("id").toInt()
                val title = getTextContent(bookElement, "title")
                val author = getTextContent(bookElement, "author")
                val price = getTextContent(bookElement, "price").toDouble()

                val genreNode = bookElement.getElementsByTagName("genre").item(0)
                val genre = if (genreNode != null) genreNode.textContent else null

                books.add(Book(id, title, author, price, genre))
            }

        } catch (e: Exception) {
            println("Error parsing with DOM: ${e.message}")
        }

        return books
    }

    // Get text content of child element
    private fun getTextContent(parent: Element, tagName: String): String {
        val nodes = parent.getElementsByTagName(tagName)
        return if (nodes.length > 0) {
            nodes.item(0).textContent
        } else {
            ""
        }
    }

    // Parse with attributes
    fun parseAttributes(xml: String): Map<String, Map<String, String>> {
        val result = mutableMapOf<String, Map<String, String>>()

        try {
            val factory = DocumentBuilderFactory.newInstance()
            val builder = factory.newDocumentBuilder()
            val document = builder.parse(
                javax.xml.parsers.InputSource(StringReader(xml))
            )

            val elements = document.documentElement.childNodes

            for (i in 0 until elements.length) {
                val node = elements.item(i)
                if (node.nodeType == Node.ELEMENT_NODE) {
                    val element = node as Element
                    val attrs = mutableMapOf<String, String>()

                    for (j in 0 until element.attributes.length) {
                        val attr = element.attributes.item(j)
                        attrs[attr.nodeName] = attr.nodeValue
                    }

                    result[element.tagName] = attrs
                }
            }

        } catch (e: Exception) {
            println("Error parsing attributes: ${e.message}")
        }

        return result
    }
}

// 3. XML to Object Mapper
class XmlObjectMapper {

    // Parse XML to generic map
    fun xmlToMap(xml: String): Map<String, Any> {
        val result = mutableMapOf<String, Any>()
        val factory = XmlPullParserFactory.newInstance()
        val parser = factory.newPullParser()

        parser.setInput(StringReader(xml))

        var eventType = parser.eventType
        var currentKey = ""
        val stack = mutableListOf<String>()

        while (eventType != XmlPullParser.END_DOCUMENT) {
            when (eventType) {
                XmlPullParser.START_TAG -> {
                    currentKey = parser.name
                    stack.add(currentKey)
                }
                XmlPullParser.TEXT -> {
                    val text = parser.text.trim()
                    if (text.isNotEmpty() && stack.size > 0) {
                        result[stack.joinToString(".")] = text
                    }
                }
                XmlPullParser.END_TAG -> {
                    if (stack.isNotEmpty()) {
                        stack.removeAt(stack.size - 1)
                    }
                }
            }
            eventType = parser.next()
        }

        return result
    }

    // Extract specific elements
    fun extractElements(xml: String, elementName: String): List<String> {
        val elements = mutableListOf<String>()
        val factory = XmlPullParserFactory.newInstance()
        val parser = factory.newPullParser()

        parser.setInput(StringReader(xml))

        var eventType = parser.eventType

        while (eventType != XmlPullParser.END_DOCUMENT) {
            if (eventType == XmlPullParser.START_TAG && parser.name == elementName) {
                elements.add(parser.nextText())
            }
            eventType = parser.next()
        }

        return elements
    }

    // Extract attributes
    fun extractAttributes(xml: String, elementName: String): List<Map<String, String>> {
        val attributesList = mutableListOf<Map<String, String>>()
        val factory = XmlPullParserFactory.newInstance()
        val parser = factory.newPullParser()

        parser.setInput(StringReader(xml))

        var eventType = parser.eventType

        while (eventType != XmlPullParser.END_DOCUMENT) {
            if (eventType == XmlPullParser.START_TAG && parser.name == elementName) {
                val attrs = mutableMapOf<String, String>()

                for (i in 0 until parser.attributeCount) {
                    attrs[parser.getAttributeName(i)] = parser.getAttributeValue(i)
                }

                attributesList.add(attrs)
            }
            eventType = parser.next()
        }

        return attributesList
    }
}

// 4. XML Validation and Utilities
class XmlUtilities {

    // Validate XML format
    fun isValidXml(xml: String): Boolean {
        return try {
            val factory = XmlPullParserFactory.newInstance()
            val parser = factory.newPullParser()
            parser.setInput(StringReader(xml))

            var eventType = parser.eventType
            while (eventType != XmlPullParser.END_DOCUMENT) {
                eventType = parser.next()
            }

            true
        } catch (e: Exception) {
            println("Invalid XML: ${e.message}")
            false
        }
    }

    // Format XML (pretty print)
    fun formatXml(xml: String): String {
        try {
            val factory = DocumentBuilderFactory.newInstance()
            val builder = factory.newDocumentBuilder()
            val document = builder.parse(
                javax.xml.parsers.InputSource(StringReader(xml))
            )

            // Use transformer for pretty printing
            val transformer = javax.xml.transform.TransformerFactory.newInstance().newTransformer()
            transformer.setOutputProperty(javax.xml.transform.OutputKeys.INDENT, "yes")
            transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "2")

            val writer = java.io.StringWriter()
            transformer.transform(
                javax.xml.transform.dom.DOMSource(document),
                javax.xml.transform.stream.StreamResult(writer)
            )

            return writer.toString()
        } catch (e: Exception) {
            println("Error formatting XML: ${e.message}")
            return xml
        }
    }

    // Count elements
    fun countElements(xml: String, elementName: String): Int {
        val factory = XmlPullParserFactory.newInstance()
        val parser = factory.newPullParser()

        parser.setInput(StringReader(xml))

        var count = 0
        var eventType = parser.eventType

        while (eventType != XmlPullParser.END_DOCUMENT) {
            if (eventType == XmlPullParser.START_TAG && parser.name == elementName) {
                count++
            }
            eventType = parser.next()
        }

        return count
    }
}

// Main demonstration
fun demonstrateXmlParsing() {
    println("=== Android Kotlin XML Parsing Examples ===\n")

    // 1. Basic XML parsing
    println("--- 1. Basic XML Parsing ---")
    val basicParser = BasicXmlParser()

    val booksXml = """
        <catalog>
            <book id="1">
                <title>The Great Gatsby</title>
                <author>F. Scott Fitzgerald</author>
                <price>12.99</price>
                <genre>Fiction</genre>
            </book>
            <book id="2">
                <title>To Kill a Mockingbird</title>
                <author>Harper Lee</author>
                <price>14.99</price>
                <genre>Southern Gothic</genre>
            </book>
            <book id="3">
                <title>1984</title>
                <author>George Orwell</author>
                <price>11.99</price>
            </book>
        </catalog>
    """.trimIndent()

    val books = basicParser.parseSimpleXml(booksXml)
    println("Parsed ${books.size} books:")
    books.forEach { book ->
        println("  - ${book.title} by ${book.author} ($${book.price})")
    }

    // 2. Nested XML parsing
    println("\n--- 2. Nested XML Parsing ---")
    val usersXml = """
        <users>
            <user id="1">
                <username>alice</username>
                <email>[email protected]</email>
                <address>
                    <street>123 Main St</street>
                    <city>NYC</city>
                    <country>USA</country>
                </address>
            </user>
            <user id="2">
                <username>bob</username>
                <email>[email protected]</email>
            </user>
        </users>
    """.trimIndent()

    val users = basicParser.parseNestedXml(usersXml)
    println("Parsed ${users.size} users:")
    users.forEach { user ->
        println("  - ${user.username} (${user.email})")
        user.address?.let {
            println("    Address: ${it.street}, ${it.city}")
        }
    }

    // 3. DOM parsing
    println("\n--- 3. DOM Parsing ---")
    val domParser = DomXmlParser()
    val booksFromDom = domParser.parseWithDom(booksXml)
    println("Parsed via DOM: ${booksFromDom.size} books")

    // 4. XML to map
    println("\n--- 4. XML to Map ---")
    val mapper = XmlObjectMapper()
    val simpleXml = """
        <config>
            <app_name>MyApp</app_name>
            <version>1.0.0</version>
            <debug>true</debug>
        </config>
    """.trimIndent()

    val configMap = mapper.xmlToMap(simpleXml)
    println("Config map:")
    configMap.forEach { (key, value) ->
        println("  $key: $value")
    }

    // 5. Extract elements
    println("\n--- 5. Extract Elements ---")
    val titles = mapper.extractElements(booksXml, "title")
    println("Book titles: $titles")

    // 6. Extract attributes
    val bookAttrs = mapper.extractAttributes(booksXml, "book")
    println("\nBook attributes:")
    bookAttrs.forEach { attrs ->
        println("  Book ${attrs["id"]}")
    }

    // 7. Validation
    println("\n--- 6. Validation ---")
    val utilities = XmlUtilities()

    val isValid = utilities.isValidXml(booksXml)
    println("Is valid XML: $isValid")

    val elementCount = utilities.countElements(booksXml, "book")
    println("Book count: $elementCount")

    // 8. Format XML
    println("\n--- 7. Format XML ---")
    val unformattedXml = "<catalog><book id="1"><title>Test</title></book></catalog>"
    val formattedXml = utilities.formatXml(unformattedXml)
    println("Formatted XML:\n$formattedXml")

    println("\n=== All XML Parsing Examples Completed ===")
}