将 Json 转换为 Map[String, String]
Convert Json to a Map[String, String]
我输入了json喜欢
{"a": "x", "b": "y", "c": "z", .... }
我想将此 json 转换为类似 Map[String, String]
的 Map
所以基本上是键值对的映射。
我如何使用 circe 执行此操作?
请注意,我不知道 "a"、"b"、"c" 将出现在 Json 中。我所知道的是它们将永远是字符串,而不是任何其他数据类型。
我在这里查看了自定义解码器 https://circe.github.io/circe/codecs/custom-codecs.html,但它们只有在您知道标签名称时才有效。
我在 Jackson 中找到了执行此操作的示例。但不在圈子里
import com.fasterxml.jackson.module.scala.DefaultScalaModule
import com.fasterxml.jackson.databind.ObjectMapper
val data = """
{"a": "x", "b", "y", "c": "z"}
"""
val mapper = new ObjectMapper
mapper.registerModule(DefaultScalaModule)
mapper.readValue(data, classOf[Map[String, String]])
假设:
val rawJson: String = """{"a": "x", "b": "y", "c": "z"}"""
这个有效:
import io.circe.parser._
val result: Try[Map[String, String]] = parse(rawJson).toTry
.flatMap(json => Try(json.asObject.getOrElse(sys.error("Not a JSON Object"))))
.flatMap(jsonObject => Try(jsonObject.toMap.map{case (name, value) => name -> value.asString.getOrElse(sys.error(s"Field '$name' is not a JSON string"))}))
val map: Map[String, String] = result.get
println(map)
或使用 Decoder
:
import io.circe.Decoder
val decoder = Decoder.decodeMap(KeyDecoder.decodeKeyString, Decoder.decodeString)
val result = for {
json <- parse(rawJson).toTry
map <- decoder.decodeJson(json).toTry
} yield map
val map = result.get
println(map)
您可以测试以下无效输入,看看会抛出什么异常:
val rawJson: String = """xxx{"a": "x", "b": "y", "c": "z"}""" // invalid JSON
val rawJson: String = """[1,2,3]""" // not a JSON object
val rawJson: String = """{"a": 1, "b": "y", "c": "z"}""" // not all values are string
虽然其他答案中的解决方案有效,但它们比必要的要冗长得多。现成的 circe 提供了一个隐式的 Decoder[Map[String, String]]
实例,因此您可以编写以下内容:
scala> val doc = """{"a": "x", "b": "y", "c": "z"}"""
doc: String = {"a": "x", "b": "y", "c": "z"}
scala> io.circe.parser.decode[Map[String, String]](doc)
res0: Either[io.circe.Error,Map[String,String]] = Right(Map(a -> x, b -> y, c -> z))
Decoder[Map[String, String]]
实例在 Decoder
伴随对象中定义,因此它始终可用——您不需要任何导入、其他模块等。Circe 为大多数标准提供了这样的实例具有合理实例的库类型。例如,如果你想将 JSON 数组解码为 List[String]
,你不需要构建自己的 Decoder[List[String]]
——你可以只使用来自Decoder
伴生对象。
这不仅是解决此问题的一种更简洁的方法,而且是推荐的解决方法。手动构建显式解码器实例并将 Either
转换为 Try
以组成解析和解码操作既不必要又容易出错(如果您确实需要以 Try
或 Option
或其他什么,几乎可以肯定最好在最后这样做)。
我输入了json喜欢
{"a": "x", "b": "y", "c": "z", .... }
我想将此 json 转换为类似 Map[String, String]
的 Map所以基本上是键值对的映射。
我如何使用 circe 执行此操作?
请注意,我不知道 "a"、"b"、"c" 将出现在 Json 中。我所知道的是它们将永远是字符串,而不是任何其他数据类型。
我在这里查看了自定义解码器 https://circe.github.io/circe/codecs/custom-codecs.html,但它们只有在您知道标签名称时才有效。
我在 Jackson 中找到了执行此操作的示例。但不在圈子里
import com.fasterxml.jackson.module.scala.DefaultScalaModule
import com.fasterxml.jackson.databind.ObjectMapper
val data = """
{"a": "x", "b", "y", "c": "z"}
"""
val mapper = new ObjectMapper
mapper.registerModule(DefaultScalaModule)
mapper.readValue(data, classOf[Map[String, String]])
假设:
val rawJson: String = """{"a": "x", "b": "y", "c": "z"}"""
这个有效:
import io.circe.parser._
val result: Try[Map[String, String]] = parse(rawJson).toTry
.flatMap(json => Try(json.asObject.getOrElse(sys.error("Not a JSON Object"))))
.flatMap(jsonObject => Try(jsonObject.toMap.map{case (name, value) => name -> value.asString.getOrElse(sys.error(s"Field '$name' is not a JSON string"))}))
val map: Map[String, String] = result.get
println(map)
或使用 Decoder
:
import io.circe.Decoder
val decoder = Decoder.decodeMap(KeyDecoder.decodeKeyString, Decoder.decodeString)
val result = for {
json <- parse(rawJson).toTry
map <- decoder.decodeJson(json).toTry
} yield map
val map = result.get
println(map)
您可以测试以下无效输入,看看会抛出什么异常:
val rawJson: String = """xxx{"a": "x", "b": "y", "c": "z"}""" // invalid JSON
val rawJson: String = """[1,2,3]""" // not a JSON object
val rawJson: String = """{"a": 1, "b": "y", "c": "z"}""" // not all values are string
虽然其他答案中的解决方案有效,但它们比必要的要冗长得多。现成的 circe 提供了一个隐式的 Decoder[Map[String, String]]
实例,因此您可以编写以下内容:
scala> val doc = """{"a": "x", "b": "y", "c": "z"}"""
doc: String = {"a": "x", "b": "y", "c": "z"}
scala> io.circe.parser.decode[Map[String, String]](doc)
res0: Either[io.circe.Error,Map[String,String]] = Right(Map(a -> x, b -> y, c -> z))
Decoder[Map[String, String]]
实例在 Decoder
伴随对象中定义,因此它始终可用——您不需要任何导入、其他模块等。Circe 为大多数标准提供了这样的实例具有合理实例的库类型。例如,如果你想将 JSON 数组解码为 List[String]
,你不需要构建自己的 Decoder[List[String]]
——你可以只使用来自Decoder
伴生对象。
这不仅是解决此问题的一种更简洁的方法,而且是推荐的解决方法。手动构建显式解码器实例并将 Either
转换为 Try
以组成解析和解码操作既不必要又容易出错(如果您确实需要以 Try
或 Option
或其他什么,几乎可以肯定最好在最后这样做)。