Read and parse XML with Kotlin

13.05.2018

Read and parse XML with Kotlin

How do I read an XML or html file with Kotlin and examine its content? Here are some snippets of code how to read an XML or Html file with Kotlin and then examine the XML elements, their attributes and values. The following XML file is used as a sample file (items.xml):

			<ItemSet>
	           <Item type="T1" count="1">Value1</Item>
	           <Item type="T1" count="2">Value2</Item>
	           <Item type="T2" count="1">Value3</Item>
	           <Item type="T2" count="1">Value4</Item>
	        </ItemSet>
					

Read XML File

The following snippet reads the Xml file into a Document:


	fun readXml(): Document {
	    val xmlFile = File("./input/items.xml")

	    val dbFactory = DocumentBuilderFactory.newInstance()
	    val dBuilder = dbFactory.newDocumentBuilder()
	    val xmlInput = InputSource(StringReader(xmlFile.readText()))
	    val doc = dBuilder.parse(xmlInput)

	    return doc
	}

getElementValuesByAttributeNameAndAttributeValue

The following code snippet shows how to read the value of the XML element based on an attribute and its attribute value.

	/**
	 * Create a list with all values where the attribute name is 'attributeName' and its value is 'attributeValue'
	 *
	 *  Example:
	 *  Value1
	 *  Value 'Value1' is in the list if attributeName is 'type' and attributeValue is 'T1'.
	 *
	 */
	fun getElementValuesByAttributeNameAndAttributeValue(doc: Document, attributeValue: String, attributeName: String): List<String> {
	    val xpFactory = XPathFactory.newInstance()
	    val xPath = xpFactory.newXPath()

	    //Value1
	    val xpath = "/ItemSet/Item[contains(@$attributeName, '$attributeValue')]"

	    val itemsTypeT1 = xPath.evaluate(xpath, doc, XPathConstants.NODESET) as NodeList

	    val itemList: MutableList<String> = ArrayList()
	    for (i in 0..itemsTypeT1.length - 1) {
	        itemList.add(itemsTypeT1.item(i).textContent)
	    }

	    return ArrayList(itemList)
	}

An xPath is created that stores all Item elements from the Document in a NodeList. At the same time, in the xPath, the attributeName (type) is used to filter all item elements that have the value as the value in the attributeValue attribute T1. If the function is called with the following parameters: getElementValuesByAttributeNameAndAttributeValue(doc, "T1", "type")

After the xPath has been evaluated with evaluate, the values are read out in order and written to a new list. [Value1, Value2]

getAttributeValuesByAttributeNameAndAttributeValue

The following snippet shows how to filter the attribute values based on the attribute name and attribute value.

	/**
	 *
	 * Create a list with all attribute values where the 'attributeName', 'attributeValue' and 'attributeValueName' match.
	 *
	 *  *  Value1
	 *  Value '1' is in the list if attributeName is 'type' and attributeValue is 'T1' and 'attributeValueName' is 'count'.
	 *
	 */
	fun getAttributeValuesByAttributeNameAndAttributeValue(doc: Document, attributeValue: String, attributeName: String, attributeValueName: String): List<String> {

	    val xpFactory = XPathFactory.newInstance()
	    val xPath = xpFactory.newXPath()

	    //Value1
	    val xpath = "/ItemSet/Item[contains(@$attributeName, '$attributeValue')]"

	    val itemsTypeT1 = xPath.evaluate(xpath, doc, XPathConstants.NODESET) as NodeList

	    val itemList: MutableList<String> = ArrayList()
	    for (i in 0..itemsTypeT1.length - 1) {

	        val attributeValue = itemsTypeT1.item(i).attributes.getNamedItem(attributeValueName)
	        val value = attributeValue.nodeValue

	        itemList.add(attributeValue.nodeValue)
	    }

	    return ArrayList(itemList)
	}

An xPath is created that stores all Item elements from the Document in a NodeList. At the same time, in the xPath, the attributeName (type) is used to filter all item elements that have the value as the value in the attributeValue attribute T1. If the function is called with the following parameters: getAttributeValuesByAttributeNameAndAttributeValue(doc, "T1", "type", "count")

After the xPath has been evaluated with evaluate, the values are read out in order and written to a new list. The result should be [1, 2].

examineElementAttributes

The following code snippet shows how to extract all attributes of an Xml element.

	/**
 *
 * Create a list with all attributes of the element mithh the name 'elementName.
 *
 * Only the first elelemt of the doc is examined!
 *
 */
fun examineElementAttributes(doc: Document, elementName: String): List<String> {

    val xpFactory = XPathFactory.newInstance()
    val xPath = xpFactory.newXPath()

    val xpath = "/ItemSet/$elementName"

    val elementNodeList = xPath.evaluate(xpath, doc, XPathConstants.NODESET) as NodeList

    val firstElement = elementNodeList.item(0)

    val attributeList: MutableList<String> = ArrayList()
    for (i in 0..firstElement.attributes.length - 1) {
        val attribute = firstElement.attributes.item(i);

        attributeList.add(attribute.nodeName)
        println(attribute)
    }

    return ArrayList(attributeList)
}

The xPath selects all elements by its name elementName. After the xpath is evaluated the first element in the NodeList is examinded. All attributes are stored in a new List. The result should be [count, type] if the function is called with the following parameters: examineElementAttributes(doc, "Item").

Please do not forget: This is not a perfect Kotlin code. These are code snippets that show how to work with Kotlin and Xml.