Consider the following from the Scala interpreter:
scala> JSON.parseFull("""{"name":"jack","greeting":"hello world"}""")
res6: Option[Any] = Some(Map(name -> jack, greeting -> hello world))
Why is the Map returned in Some() thing? And how do I work with it?
I want to put the values in an xml template:
<test>
<name>name goes here</name>
<greeting>greeting goes here</greeting>
</test>
What is the Scala way of getting my map out of Some(thing) and getting those values in the xml?
You have two separate problems.
Any
.Option
and aMap
.Let's suppose we have the data:
and suppose that we want to return the appropriate XML if there is something to return, but not otherwise. Then we can use
collect
to gather those parts that we know how to deal with:(note how we've taken each entry in the map apart to make sure it maps a string to a string--we wouldn't know how to proceed otherwise. We get:
Okay, that's better! Now if you know which fields you want in your XML, you can ask for them:
which in this (successful) case produces
and in an unsuccessful case would produce
None
.If you instead want to wrap whatever you happen to find in your map in the form
<key>value</key>
, it's a bit more work because Scala doesn't have a good abstraction for tags:which again produces
(You can use
get
to get the contents of anOption
, but it will throw an exception if theOption
is empty (i.e.None
).)parseFull
returns anOption
because the string may not be valid JSON (in which case it will returnNone
instead ofSome
).The usual way to get the value out of a
Some
is to pattern match against it like this:If you're certain the input will always be valid and so you don't need to handle the case of invalid input, you can use the
get
method on theOption
, which will throw an exception when called onNone
.You should probably use something like this:
Where:
The
collect
method onOption[A]
takes aPartialFunction[A, B]
and is a combination offilter
(by a predicate) andmap
(by a function). That is:Are both equivalent. When you have an optional value, you should use
map
,flatMap
,filter
,collect
etc to transform the option in your program, avoiding extracting the option's contents either via a pattern-match or via theget
method. You should never, ever useOption.get
- it is the canonical sign that you are doing it wrong. Pattern-matching should be avoided because it represents a fork in your program and hence adds to cyclomatic complexity - the only time you might wish to do this might be for performanceActually you have the issue that the result of the
parseJSON
method is anOption[Any]
(the reason is that it is anOption
, presumably, is that the parsing may not succeed andOption
is a more graceful way of handlingnull
than, well,null
).But the issue with my code above is that the
case x: Map[String, String]
cannot be checked at runtime due to type erasure (i.e. scala can check that the option contains aMap
but not that theMap
's type parameters are bothString
. The code will get you an unchecked warning.An
Option
is returned becauseparseFull
has different possible return values depending on the input, or it may fail to parse the input at all (givingNone
). So, aside from an optionalMap
which associates keys with values, an optionalList
can be returned as well if the JSON string denoted an array.Example:
You might need pattern matching in order to achieve what you want, like so:
Now, if you want to generate XML output, you can use the above to iterate over the key/value pairs: