Reputation: 35
I have a Map[String,List[String]]
type data and want to save as a xml
file in Scala. If I choose to use scala.xml.XML.save
method, I need to convert map to node.
But I didn't find a way to do it. And it seems there is no method in map or node library could do it.
Upvotes: 0
Views: 255
Reputation: 4063
You can try also next library : https://github.com/mthaler/xmlconfect - the idea similar to other codec libraries (e.g. circe, Play Json etc.) - it build codec based on types via implicit's. In your case it would look like next:
import scala.xml.PrettyPrinter
import com.mthaler.xmlconfect._
import com.mthaler.xmlconfect.ProductFormatInstances._
import com.mthaler.xmlconfect.BasicTextFormats._
import com.mthaler.xmlconfect.CollectionFormats._
object XmlFormat {
type RawData = Map[String, List[String]]
case class TypedDataElement(item: String)
object TypedDataElement {
implicit val format: XmlElemFormat[TypedDataElement] = xmlFormat1(TypedDataElement.apply)
}
case class TypedDataNode(key: String, item: List[TypedDataElement])
object TypedDataNode {
implicit val format: XmlElemFormat[TypedDataNode] = xmlFormat2(TypedDataNode.apply)
}
case class AllTypedData(data: List[TypedDataNode]) {
def toRawData: RawData = {
data.map(item => item.key -> item.item.map(_.item)).toMap
}
}
object AllTypedData {
implicit val format: XmlElemFormat[AllTypedData] = xmlFormat1(AllTypedData.apply)
def fromRaw(raw: RawData): AllTypedData = {
val all = raw.toList.map {
case (key, values) => TypedDataNode(key, values.map(TypedDataElement.apply))
}
AllTypedData(all)
}
}
def main(args: Array[String]): Unit = {
val rawData: RawData = Map("node" -> List("value1", "value2"))
val typedData = AllTypedData.fromRaw(rawData)
val printer = new PrettyPrinter(80, 4)
println(printer.formatNodes(typedData.toNode))
}
}
Case classes was introduced in order to provide key names.
The result output in this particular case would be:
<AllTypedData>
<TypedDataNode>
node
<TypedDataElement>value1</TypedDataElement>
<TypedDataElement>value2</TypedDataElement>
</TypedDataNode>
</AllTypedData>
Upvotes: 0
Reputation: 796
You have to create the converter manually since xml can be pretty different one another, this is an example you can use.
import scala.xml.{Node, NodeSeq}
val a:Map[String, List[String]] = Map("animal" -> List("cat", "dog", "bird"), "fruit" -> List("banana", "apple"))
def convertToXML(parametersToCreateXML: Map[String,List[String]]): NodeSeq = {
def generateTitleToData(keyValue: (String, List[String])): Node = {
<member>
<name>{keyValue._1}</name>
<values>
{keyValue._2.map(x =>generateData(x))}
</values>
</member>
}
def generateData(value: String): Node = {
<value>
<string>{value}</string>
</value>
}
parametersToCreateXML.map(x => generateTitleToData(x)).toSeq
}
convertToXML(a)
res0: scala.xml.NodeSeq =
NodeSeq(<member>
<name>animal</name>
<values>
<value>
<string>cat</string>
</value><value>
<string>dog</string>
</value><value>
<string>bird</string>
</value>
</values>
</member>, <member>
<name>fruit</name>
<values>
<value>
<string>banana</string>
</value><value>
<string>apple</string>
</value>
</values>
</member>)
as you can see, the conversion from Seq[Node]
to NodeSeq
is done implicitly.
Upvotes: 1