如果JSON有一个键和值,并且您可以使用键名来提取其值,那么the documentation中的Decode Person示例很棒,但是如果构成键的字符串是任意的,那么有意义。
对于Fxample,一个开放的加密货币api可以给出硬币的历史价格,并且返回的JSON的结构是不同的,这取决于我要求的硬币的基础货币以及我想要它的各种报价货币。例如,假设我想要特定日期的价格“DOGE'在' AUD'和' XRP'返回的JSON看起来像
{"DOGE":{"AUD":0.008835,"XRP":0.004988}}
我无法导航到基础并获得其价值然后价格并获得它们,因为JSON没有被这样结构化,我需要寻找“DOGE”'作为一个密钥,然后在对象中,知道会有一个' AUD'密钥和' XRP'键。当然,根据我的查询,每个结果都会有所不同。
当然我知道这些键,因为我基于它们创建搜索但是如何使用Argonaut来解析这个JSON?我可以以某种方式创建一个关闭我的密钥名称的解码吗?
感谢任何帮助或指导,谢谢。
答案 0 :(得分:1)
由于您不知道属性名称将提前知道什么,因此您无法创建编解码器并将原始JSON直接解码为Scala类。
您希望将原始JSON解析为通用argonaut.Json
对象,然后您可以模式匹配或使用fold
来检查内容。例如:
val rawJson: String = ...
val parsed: Either[String, argonaut.Json] = argonaut.Parse.parse(rawJson)
您可以通过检查source code来查看argonaut Json
对象上可用的方法。
答案 1 :(得分:1)
根据Fried Brice的回答,我确实沿着解析路线向下映射了生成的Either以生成我的数据类型,请参阅下面的代码片段,建议,改进欢迎。
def parseHistoricPriceJSON(rawJson: String, fromcurrency: Currency, toCurrencies: List[Currency]): Either[String, PricedAsset] = {
import argonaut._, Argonaut._
import monocle.macros.syntax.lens._
val parsed: Either[String, Json] = Parse.parse(rawJson)
val myTocurrs = Currency("XRP") :: toCurrencies
parsed.right.map(outer => {
val cursor = outer.cursor
val ps = for {
toC <- myTocurrs
prices <- cursor.downField(fromcurrency.sym)
price <- prices.downField(toC.sym)
thep <- price.focus.number
} yield (toC, thep.toDouble.get)
PricedAsset(fromcurrency, ps)
})
}
case class Currency(sym: String) extends AnyVal {
def show = sym
}
case class PricedAsset(base:Currency, quotePrices: List[(Currency,Double)])