JAXB unmarshalling ? Sax reader ? What about… nothing.

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
}

Leave a Reply

Your email address will not be published. Required fields are marked *

*

This site uses Akismet to reduce spam. Learn how your comment data is processed.