Reputation: 435
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
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
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