david419
david419

Reputation: 435

Converting xml to Object/Map in Scala

I am trying to write a module that will convert XML to object/map. The xml can be anything so we cannot predefine a model class like we do for XStream/SAX Parser(I tried both). Is there any way to write a generic module that will convert any given XML to a Map or Object?

Upvotes: 2

Views: 672

Answers (2)

Gilgamesh
Gilgamesh

Reputation: 21

This works:

val emptyMap = Map.empty[String,List[String]]

def xml2map(xml: String): Map[String,List[String]] = add2map(XML.loadString(xml), "", emptyMap)

private def add2map(node: Node, xPath: String, oldMap: Map[String,List[String]]): Map[String,List[String]] = {

  val elems = node.child.filter(_.isInstanceOf[Elem])
  val xCurr = xPath + "/" + node.label

  val currElems = elems.filter(_.child.count(_.isInstanceOf[Elem]) == 0)
  val nextElems = elems.diff(currElems)

  val currMap = currElems.foldLeft(oldMap)((map, elem) => map + {
    val key = xCurr + "/" + elem.label

    val oldValue = map.getOrElse(key, List.empty[String])
    val newValue = oldValue ::: List(elem.text)

    key -> newValue
  })

  nextElems.foldLeft(currMap)((map, elem) => map ++ add2map(elem, xCurr, emptyMap))
}

For the XML below

<Student>
<StudentID>123456</StudentID>
<AdmissDate>2018-09-03</AdmissDate>
<Timetable>
    <CurrentTerm>
        <StartDt>2018-09-03</StartDt>
        <EndDt>2018-12-31</EndDt>
        <Subject>Maths</Subject>
        <Subject>Physics</Subject>
        <Subject>History</Subject>
    </CurrentTerm>
</Timetable>

it returns a Map[String,List[String]] that looks like (after .toString()):

Map(
  /Student/Timetable/CurrentTerm/EndDt -> List(2018-12-31),
  /Student/Timetable/CurrentTerm/StartDt -> List(2018-09-03),
  /Student/Timetable/CurrentTerm/Subject -> List(Maths, Physics, History),
  /Student/AdmissDate -> List(2018-09-03),
  /Student/StudentID -> List(123456)
)

Upvotes: 0

Alexander Kondaurov
Alexander Kondaurov

Reputation: 4123

This question is interesting to me also. I tried to convert any xml object to Map[String, String].

<offer>
<model>superModel</model>
<vendor>superVendor</vendor>
<params>
<param1>p1</param1>
<param2>p2</param2>
</params>
</offer>

Result Map[String, String]:

Map(
"model" -> "superModel"
"vendor" -> "superVendor",
"params.param1" -> "p1",
"params.param2" -> "p2"
)

Upvotes: 1

Related Questions