Я пытаюсь разобрать строку JSON для класса case в Scala (поэтому я могу выполнять обработку данных фильтрации и т. Д.). После некоторого исследования я собираюсь с spray-json, так как есть несколько примеров по ссылке. К сожалению, ссылка не показывает, как разбирать JSON с вложенными полями с массивами.Parse Complex JSON в SCALA using spray-json
Я тестирую свой код на ноутбуке Scala с кодом ниже, и он работает.
// Dependencies
io.spray spray-json_2.10 1.3.2
import spray.json._
import DefaultJsonProtocol._ // if you don't supply your own Protocol (see below)
// simple source
val source = """{
"EventId": "29ca61f3-b8b6-41e7-8236-802fa232e7cf",
"Timestamp": "2016-03-09T20:14:07.5535193Z",
"StartTime": "2016-03-09T02:51:04.397",
"EndTime": "2016-03-09T02:51:04.397",
"ActiveStates": "{\"No Motion\":1,\"Motion Detected\":1,\"Face Detected\":1}",
"Created": "2016-03-09T02:51:04.397",
"Modified": "2016-03-09T02:51:04.397"
}"""
// simple case class
case class claX( EventId: String,
Timestamp: String,
StartTime: String,
EndTime: String,
ActiveStates: String,
Created: String,
Modified: String)
object MyJsonProtocol extends DefaultJsonProtocol {
implicit val claXFormat = jsonFormat7(claX)
}
import MyJsonProtocol._
import spray.json._
val json = source.parseJson // parse string to json
val cx0 = json.convertTo[claX] // convert to class claX
Моя проблема в том, когда строка JSON имеет вложенные массив в данных, который имеет вложенный класс «продукта» в нем. Это пример JSON:
{
"EventId": "29ca61f3-b8b6-41e7-8236-802fa232e7cf",
"Timestamp": "2016-03-09T20:14:07.5535193Z",
"StartTime": "2016-03-09T02:51:04.397",
"EndTime": "2016-03-09T02:51:04.397",
"ActiveStates": "{\"No Motion\":1,\"Motion Detected\":1,\"Face Detected\":1}",
"Created": "2016-03-09T02:51:04.397",
"Modified": "2016-03-09T02:51:04.397",
"Data": {
"AgeRange": {
"Name": "30 - 35"
},
"Company": {
"Id": "f3ad1744-0ead-458a-9416-852c43ccde24"
},
"CompanyType": {
"Name": "Retailer"
},
"ConnectorType": {
"Name": "Camera Capturing"
},
"Content": {
"Ids": [
"0c0f0a9a-fece-4b3e-abb4-0f508d357220"
]
},
"Customer": {
"LoyaltyId": 0
},
"DeviceRegistries": [
{
"Id": "f19f5daa-e9b9-43d0-91a7-51da4fdd0e31",
"DeviceName": "Company 3 Cooler",
"DeviceType": "CCU"
}
],
"Emotion": {
"Name": "Happy"
},
"Gender": {
"Name": "Male"
},
"Products": [
{
"Name": "Molson Canadian",
"ProductCategory": "Beverage",
"InventoryTrackingNumberType": "SKU",
"InventoryTrackingNumber": "438654935776",
"ProductPrice": {
"RetailPrice": 2.1,
"RetailPriceSymbol": "?",
"PromotionPrice": 1.8,
"PromotionPriceSymbol": "?"
}
},
{
"Name": "Coors Original",
"ProductCategory": "Beverage",
"InventoryTrackingNumberType": "SKU",
"InventoryTrackingNumber": "438654935775",
"ProductPrice": {
"RetailPrice": 1.1,
"RetailPriceSymbol": "?",
"PromotionPrice": 0.8,
"PromotionPriceSymbol": "?"
}
},
{
"Name": "Coors Light",
"ProductCategory": "Beverage",
"InventoryTrackingNumberType": "SKU",
"InventoryTrackingNumber": "438654935778",
"ProductPrice": {
"RetailPrice": 6.1,
"RetailPriceSymbol": "?",
"PromotionPrice": 5.8,
"PromotionPriceSymbol": "?"
}
},
{
"Name": "Blue Moon",
"ProductCategory": "Beverage",
"InventoryTrackingNumberType": "SKU",
"InventoryTrackingNumber": "438654935777",
"ProductPrice": {
"RetailPrice": 4.1,
"RetailPriceSymbol": "?",
"PromotionPrice": 3.8,
"PromotionPriceSymbol": "?"
}
}
],
"Race": {
"Name": "Latin"
},
"Region": {
"Name": "Region 01"
},
"SensorRegistry": {
"Name": "Company 3 Camera 01"
},
"SensorType": {
"Name": "Proximity"
},
"SfuRegistries": {
"Ids": [
"7effea8c-56dd-4905-bbc3-2158d14cd7cc",
"24a7253d-174a-44f0-8145-483cc0f45adb",
"bc970c8e-7e41-4889-859b-55c6a3f8ba5d",
"46e599f5-8082-499f-b5d0-9d611409a652"
]
},
"Shelves": {
"Ids": [
"ea442504-7d64-4c01-bdde-1eb46e53b81c",
"d6fe9c78-e21b-4a57-b620-99a7d94d46f9"
]
},
"State": {
"Name": "Face Detected"
},
"StockLevel": {
"OnHand": 0
},
"Store": {
"Id": "268c852d-86b8-4b7c-b865-2f29a3e2307e"
},
"Unit": {
"Id": "52c58781-b2bf-46ea-81ad-b9d9fbacb471"
},
"UnitType": {
"Name": "5-Shelf Cooler"
}
},
"id": "54bfd971-0fec-4e0e-87cc-851a697705e9"
}
Я сделал еще два класса регистра для управления «продукта» и «Цены»
case class ProductPrice(RetailPrice: Double,
RetailPriceSymbol: Double,
PromotionPrice: Double,
PromotionPriceSymbol: Double)
case class Product(Name: String,
ProductCategory: String,
InventoryTrackingNumberType: String,
InventoryTrackingNumber: String,
ProductPrice: ProductPrice)
То, что я не знаю, как вы совмещаете . это так, что узел данных в формате JSON обрабатывается должным образом в claXBig (где все из строки JSON правильно разобранного Это где я подножки:
case class claX2( EventId: String,
Timestamp: String,
StartTime: String,
EndTime: String,
ActiveStates: String,
Created: String,
Modified: String,
Data: Map[String, Any]) // <- how do I parse this and the nested products
object MyJsonProtocol2 extends DefaultJsonProtocol {
implicit val claXFormat2 = jsonFormat8(claX2)
}
Я также пытаюсь л ДОА больший JSON (сбор этих «событий») с использованием коды, описанной here
Поэтому я добавил новый класс случай ниже, чтобы обработать массив «мероприятие или claX2
case class claX2Collection(clax2s: Array[claX2])
extends IndexedSeq[claX2] {
def apply(index: Int) = clax2s(index) //<- not sure what this mean
def length = clax2s.length // or whether index is doing anything
}
я предполагаю claX2Collection является правильным его компиляция. Но ниже код, безусловно, неправильно, но необходимо, чтобы загрузить коллекцию событий из массива JSON
implicit object claX2JsonFormat extends RootJsonFormat[claX2]{
def write(f: claX2) = {
val buf = scala.collection.mutable.ArrayBuffer(
"events" -> JsString("claX2"), // <- error
"Timestamp" -> JsObject(f.Timestamp), // error
"StartTime" -> JsObject(f.StartTime), // error
"EndTime" -> JsObject(f.EndTime), // error
"ActiveStates" -> JsObject(f.ActiveStates), // error
"Created" -> JsObject(f.Created), // errors
"Modified" -> JsObject(f.Modified), // errors
"Data" -> JsObject(f.Data) // errors
)
}
def read(value:JsValue) = {
val jso = value.asJsObject
// not sure what to do here but
// assuming I have to pick out
val EventId = jso.fields.get("EventId")
Timestamp = jso.fields.get("Timestamp")
StartTime = jso.fields.get("StartTime")
EndTime = jso.fields.get("EndTime")
ActiveStates = jso.fields.get("ActiveStates")
Created = jso.fields.get("Created")
Modified = jso.fields.get("Modified")
Data = jso.fields.get("Data")
claX2(EventId,Timestamp,StartTime,EndTime,ActiveStates,Created,
Modified,Data)
}
}
Когда, зафиксированной он должен быть в состоянии прочитать этот JSON:
{
"type": "EventCollection",
"events": [
{
"EventId": "29ca61f3-b8b6-41e7-8236-802fa232e7cf",
"Timestamp": "2016-03-09T20:14:07.5535193Z",
"StartTime": "2016-03-09T02:51:04.397",
"EndTime": "2016-03-09T02:51:04.397",
"ActiveStates": "{\"No Motion\":1,\"Motion Detected\":1,\"Face Detected\":1}",
"Created": "2016-03-09T02:51:04.397",
"Modified": "2016-03-09T02:51:04.397",
"Data": {
"AgeRange": {
"Name": "30 - 35"
},
"Company": {
"Id": "f3ad1744-0ead-458a-9416-852c43ccde24"
},
"CompanyType": {
"Name": "Retailer"
},
"ConnectorType": {
"Name": "Camera Capturing"
},
"Content": {
"Ids": [
"0c0f0a9a-fece-4b3e-abb4-0f508d357220"
]
},
"Customer": {
"LoyaltyId": 0
},
"DeviceRegistries": [
{
"Id": "f19f5daa-e9b9-43d0-91a7-51da4fdd0e31",
"DeviceName": "Company 3 Cooler",
"DeviceType": "CCU"
}
],
"Emotion": {
"Name": "Happy"
},
"Gender": {
"Name": "Male"
},
"Products": [
{
"Name": "Molson Canadian",
"ProductCategory": "Beverage",
"InventoryTrackingNumberType": "SKU",
"InventoryTrackingNumber": "438654935776",
"ProductPrice": {
"RetailPrice": 2.1,
"RetailPriceSymbol": "?",
"PromotionPrice": 1.8,
"PromotionPriceSymbol": "?"
}
},
{
"Name": "Coors Original",
"ProductCategory": "Beverage",
"InventoryTrackingNumberType": "SKU",
"InventoryTrackingNumber": "438654935775",
"ProductPrice": {
"RetailPrice": 1.1,
"RetailPriceSymbol": "?",
"PromotionPrice": 0.8,
"PromotionPriceSymbol": "?"
}
},
{
"Name": "Coors Light",
"ProductCategory": "Beverage",
"InventoryTrackingNumberType": "SKU",
"InventoryTrackingNumber": "438654935778",
"ProductPrice": {
"RetailPrice": 6.1,
"RetailPriceSymbol": "?",
"PromotionPrice": 5.8,
"PromotionPriceSymbol": "?"
}
},
{
"Name": "Blue Moon",
"ProductCategory": "Beverage",
"InventoryTrackingNumberType": "SKU",
"InventoryTrackingNumber": "438654935777",
"ProductPrice": {
"RetailPrice": 4.1,
"RetailPriceSymbol": "?",
"PromotionPrice": 3.8,
"PromotionPriceSymbol": "?"
}
}
],
"Race": {
"Name": "Latin"
},
"Region": {
"Name": "Region 01"
},
"SensorRegistry": {
"Name": "Company 3 Camera 01"
},
"SensorType": {
"Name": "Proximity"
},
"SfuRegistries": {
"Ids": [
"7effea8c-56dd-4905-bbc3-2158d14cd7cc",
"24a7253d-174a-44f0-8145-483cc0f45adb",
"bc970c8e-7e41-4889-859b-55c6a3f8ba5d",
"46e599f5-8082-499f-b5d0-9d611409a652"
]
},
"Shelves": {
"Ids": [
"ea442504-7d64-4c01-bdde-1eb46e53b81c",
"d6fe9c78-e21b-4a57-b620-99a7d94d46f9"
]
},
"State": {
"Name": "Face Detected"
},
"StockLevel": {
"OnHand": 0
},
"Store": {
"Id": "268c852d-86b8-4b7c-b865-2f29a3e2307e"
},
"Unit": {
"Id": "52c58781-b2bf-46ea-81ad-b9d9fbacb471"
},
"UnitType": {
"Name": "5-Shelf Cooler"
}
},
"id": "54bfd971-0fec-4e0e-87cc-851a697705e9"
},
{
"EventId": "29ca61f3-b8b6-41e7-8236-802fa232e7cf",
"Timestamp": "2016-03-09T20:14:07.5535193Z",
"StartTime": "2016-03-09T02:51:04.397",
"EndTime": "2016-03-09T02:51:04.397",
"ActiveStates": "{\"No Motion\":1,\"Motion Detected\":1,\"Face Detected\":1}",
"Created": "2016-03-09T02:51:04.397",
"Modified": "2016-03-09T02:51:04.397",
"Data": {
"AgeRange": {
"Name": "30 - 35"
},
"Company": {
"Id": "f3ad1744-0ead-458a-9416-852c43ccde24"
},
"CompanyType": {
"Name": "Retailer"
},
"ConnectorType": {
"Name": "Camera Capturing"
},
"Content": {
"Ids": [
"0c0f0a9a-fece-4b3e-abb4-0f508d357220"
]
},
"Customer": {
"LoyaltyId": 0
},
"DeviceRegistries": [
{
"Id": "f19f5daa-e9b9-43d0-91a7-51da4fdd0e31",
"DeviceName": "Company 3 Cooler",
"DeviceType": "CCU"
}
],
"Emotion": {
"Name": "Happy"
},
"Gender": {
"Name": "Male"
},
"Products": [
{
"Name": "Molson Canadian",
"ProductCategory": "Beverage",
"InventoryTrackingNumberType": "SKU",
"InventoryTrackingNumber": "438654935776",
"ProductPrice": {
"RetailPrice": 2.1,
"RetailPriceSymbol": "?",
"PromotionPrice": 1.8,
"PromotionPriceSymbol": "?"
}
},
{
"Name": "Coors Original",
"ProductCategory": "Beverage",
"InventoryTrackingNumberType": "SKU",
"InventoryTrackingNumber": "438654935775",
"ProductPrice": {
"RetailPrice": 1.1,
"RetailPriceSymbol": "?",
"PromotionPrice": 0.8,
"PromotionPriceSymbol": "?"
}
},
{
"Name": "Coors Light",
"ProductCategory": "Beverage",
"InventoryTrackingNumberType": "SKU",
"InventoryTrackingNumber": "438654935778",
"ProductPrice": {
"RetailPrice": 6.1,
"RetailPriceSymbol": "?",
"PromotionPrice": 5.8,
"PromotionPriceSymbol": "?"
}
},
{
"Name": "Blue Moon",
"ProductCategory": "Beverage",
"InventoryTrackingNumberType": "SKU",
"InventoryTrackingNumber": "438654935777",
"ProductPrice": {
"RetailPrice": 4.1,
"RetailPriceSymbol": "?",
"PromotionPrice": 3.8,
"PromotionPriceSymbol": "?"
}
}
],
"Race": {
"Name": "Latin"
},
"Region": {
"Name": "Region 01"
},
"SensorRegistry": {
"Name": "Company 3 Camera 01"
},
"SensorType": {
"Name": "Proximity"
},
"SfuRegistries": {
"Ids": [
"7effea8c-56dd-4905-bbc3-2158d14cd7cc",
"24a7253d-174a-44f0-8145-483cc0f45adb",
"bc970c8e-7e41-4889-859b-55c6a3f8ba5d",
"46e599f5-8082-499f-b5d0-9d611409a652"
]
},
"Shelves": {
"Ids": [
"ea442504-7d64-4c01-bdde-1eb46e53b81c",
"d6fe9c78-e21b-4a57-b620-99a7d94d46f9"
]
},
"State": {
"Name": "Face Detected"
},
"StockLevel": {
"OnHand": 0
},
"Store": {
"Id": "268c852d-86b8-4b7c-b865-2f29a3e2307e"
},
"Unit": {
"Id": "52c58781-b2bf-46ea-81ad-b9d9fbacb471"
},
"UnitType": {
"Name": "5-Shelf Cooler"
}
},
"id": "54bfd971-0fec-4e0e-87cc-851a697705e9"
}
]
}
Никогда не использовал спрей-джсон, обычно я играю с игрой-json. Если вы готовы попробовать, посмотрите http://pedrorijo.com/blog/scala-json/ http://pedrorijo.com/blog/scala-json-part2/ – pedrorijo91
Самое быстрое решение - сменить карту [ String, Any] в JsObject, затем создайте для него следующий класс case. –
@ pedrorijo91 спасибо за обе ссылки, прочитав их и добавлю в панель инструментов. –