Я пытаюсь обработать следующий JSON, полученный от API.
{"product":"midprice",
"prices":[
["APPLE","217.88"],
["GOOGLE","1156.05"],
["FACEBOOK","160.58"]
]}
Я могу получить базовое отображение, работая с:
require "json"
message = "{\"product\":\"midprice\",\"prices\":[[\"APPLE\",\"217.88\"],[\"GOOGLE\",\"1156.05\"],[\"FACEBOOK\",\"160.58\"]]}"
class Midprice
JSON.mapping(
product: String,
prices: Array(Array(String)),
)
end
midprice = Midprice.from_json(message)
p midprice.product # Outputs the String
p midprice.prices # Outputs
Кристалл 0.26.1 Код: https://play.crystal-lang.org/#/r/515o
Но в идеале я бы хотел, чтобы цены были хешем с названием акции в качестве ключа и ценой в качестве значения. Можно ли это сделать с помощью JSON.mapping?
JSON.mapping
будет удален в пользу JSON::Serializable
и аннотаций. Вы можете использовать это как:
class Midprice
include JSON::Serializable
getter product : String
@[JSON::Field(converter: StockConverter.new)]
getter prices : Hash(String, String)
end
Вам необходимо использовать converter
, чтобы преобразовать prices
в нужный вам формат.
В этом случае входом является Array(Array(String))
, а выходом - Hash(String, String)
другого типа. Вам необходимо реализовать собственный метод from_json
для вашего конвертера.
class StockConverter
def initialize
@prices = Hash(String, String).new
end
def from_json(pull : JSON::PullParser)
pull.read_array do
pull.read_array do
stock = pull.read_string
price = pull.read_string
@prices[stock] = price
end
end
@prices
end
end
Вот полный рабочий код: https://play.crystal-lang.org/#/r/51d9
Но на самом деле преобразователь может быть просто модулем со статическим методом. Нет никакой пользы от наличия специального экземпляра для этого. Это просто стоит ненужного выделения кучи. play.crystal-lang.org/#/r/51dw
Для справки: вы также можете использовать конвертер с
JSON.mapping
. Но все же переход наJSON::Serializable
- хорошая идея.