如何使用 Argonaut 解码结构不良 JSON 其中键名有意义
How to use Argonaut to decode poorly structured JSON where key name is meaningful
你好,如果 JSON 有一个键和一个值,那么 the documentation 中的 Decode Person 示例就很棒,你可以使用键名来提取它的值,但是如果up key 随意但有意义。
for Fxample one open cryptocurrency api 可以给出硬币的历史价格并且 JSON 返回的结构根据我要的硬币的基础货币和各种引用我希望它定价的货币.. 例如,假设我想要 'AUD' 和 'XRP' 中特定日期 'DOGE' 的价格,返回的 JSON 看起来像
{"DOGE":{"AUD":0.008835,"XRP":0.004988}}
我无法导航到 base 并获取它的值,然后获取价格并获取它们,因为 JSON 不是那样构造的,我需要寻找 'DOGE' 作为键,然后在返回的对象知道将有一个 'AUD' 键和 'XRP' 键。当然,根据我的查询,每个结果都会有所不同。
当我基于它们创建搜索时,我当然知道这些键,但是我如何使用 Argonaut 来解析这个 JSON?我能以某种方式创建一个解码来关闭我的键名吗?
感谢任何帮助或指导,谢谢。
由于您不知道 属性 名称会提前发生什么,因此您无法创建编解码器并将原始 JSON 直接解码为 Scala class.
您想将原始 JSON 解析为通用 argonaut.Json
对象,然后您可以进行模式匹配或使用 fold
检查内容。例如:
val rawJson: String = ...
val parsed: Either[String, argonaut.Json] = argonaut.Parse.parse(rawJson)
您可以通过检查 source code.
查看 argonaut 的 Json
对象上可用的方法
根据 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)])
你好,如果 JSON 有一个键和一个值,那么 the documentation 中的 Decode Person 示例就很棒,你可以使用键名来提取它的值,但是如果up key 随意但有意义。
for Fxample one open cryptocurrency api 可以给出硬币的历史价格并且 JSON 返回的结构根据我要的硬币的基础货币和各种引用我希望它定价的货币.. 例如,假设我想要 'AUD' 和 'XRP' 中特定日期 'DOGE' 的价格,返回的 JSON 看起来像
{"DOGE":{"AUD":0.008835,"XRP":0.004988}}
我无法导航到 base 并获取它的值,然后获取价格并获取它们,因为 JSON 不是那样构造的,我需要寻找 'DOGE' 作为键,然后在返回的对象知道将有一个 'AUD' 键和 'XRP' 键。当然,根据我的查询,每个结果都会有所不同。
当我基于它们创建搜索时,我当然知道这些键,但是我如何使用 Argonaut 来解析这个 JSON?我能以某种方式创建一个解码来关闭我的键名吗?
感谢任何帮助或指导,谢谢。
由于您不知道 属性 名称会提前发生什么,因此您无法创建编解码器并将原始 JSON 直接解码为 Scala class.
您想将原始 JSON 解析为通用 argonaut.Json
对象,然后您可以进行模式匹配或使用 fold
检查内容。例如:
val rawJson: String = ...
val parsed: Either[String, argonaut.Json] = argonaut.Parse.parse(rawJson)
您可以通过检查 source code.
查看 argonaut 的Json
对象上可用的方法
根据 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)])