Here is a very tiny and naive xml parser made in kotlin.
One function, one input (string), one output (map).
Simple, and lightweight (no library).
private fun xmlToMap(body: String): Map, Any> {
val OPENING_TAG = Regex("^< ([^ >/]+)[^>]*>")
val OPENING_CLOSING_TAG = Regex("^< ([^ >/]+)[^>]*/>")
val CLOSING_TAG = Regex("^]+)>")
val ATTRS = Regex("([a-zA-Z][a-zA-Z-0-9]*)=\"([^\"]*)\"")
val root = mutableMapOf, Any>()
val deque = ArrayDeque(listOf(root))
val attrSetFunc = {text: String, node: MutableMap, Any> ->
ATTRS.findAll(text).forEach { node[it.groups[1]!!.value] = it.groups[2]!!.value } }
var substring = body
var currentNode = root
while(substring.isNotEmpty()){
when{
OPENING_CLOSING_TAG.containsMatchIn(substring) -> {
val groups = OPENING_CLOSING_TAG.find(substring)!!.groups
val localName = groups[1]!!.value
val attrs = mutableMapOf, Any>()
attrSetFunc(groups[0]!!.value, attrs)
currentNode[localName] = attrs
substring = substring.substring(groups[0]!!.range.endInclusive+1)
}
CLOSING_TAG.containsMatchIn(substring) -> {
val groups = CLOSING_TAG.find(substring)!!.groups
currentNode = deque.pop()
substring = substring.substring(groups[0]!!.range.endInclusive+1)
}
OPENING_TAG.containsMatchIn(substring) -> {
val groups = OPENING_TAG.find(substring)!!.groups
attrSetFunc(groups[0]!!.value, currentNode)
val localName = groups[1]!!.value
deque.push(currentNode)
currentNode[localName] = mutableMapOf, Any>()
currentNode = currentNode[localName] as MutableMap, Any>
substring = substring.substring(groups[0]!!.range.endInclusive+1)
}
else -> {
val data = substring.substring(0 until substring.indexOf('< '))
currentNode["CDATA"] = data
substring = substring.substring(substring.indexOf('< '))
}
}
}
return root
}