2016-01-15 8 views
2

Это мой первый опыт использования аргонавтов и только небольшое знание линз (достаточно пройти). Я потратил некоторое время, пытаясь разобраться в проблеме, но ничего не получаю.Извлечение значений из массива JSON объектов JSON с использованием объективов Argonaut

Я пытаюсь создать объектив, чтобы получить JsonArray (из строк) от какого-то JSON. Я могу дойти до объекта, у которого есть массив, но не уверен, что делать дальше.

JSON выглядит следующим образом:

json example

И мой объектив до сих пор это:

val hashtagsView = twitterEntitiesView >=> jsonObjectPL("hashtags") >=> jArrayPL 

Я не уверен, что jArrayPL правильно либо. Я хотел бы просто получить текст из массива.

Чтобы обернуть, может ли кто-нибудь помочь мне узнать, как построить объектив, который смотрит в хэштеги, а затем для каждого элемента массива заглянуть в текст, наконец получив значения как JsonArray.

Update:

С некоторой помощью от Travis я следующий код составителя:

import argonaut._, Argonaut._ 
import monocle.std.list._, monocle.function.Each.each, monocle.function.Index.index 
import scalaz._, Scalaz._ 

val \/-(json) = Parse.parse(rawJSON) 
val lens = jObjectPrism 
      .composeOptional(index("hashtags")) 
      .composePrism(jArrayPrism) 
      .composeTraversal(each[List[Json], Json]) 
      .composePrism(jObjectPrism) 
      .composeOptional(index("text")) 
      .composePrism(jStringPrism) 

println(lens.getAll(json)) 

К сожалению, я получаю сообщение об ошибке выполнения: scalaz.Scalaz$.ToEitherOps(Ljava/lang/Object;)Lscalaz/syntax/EitherOps;, начиная с линии val \/-(json) = Parse.parse(rawJSON)

Спасибо заранее!

ответ

3

Готовы ли вы использовать линзы Monocle, которые предлагают аргонавт вместо линз Scalaz? Если да, то работа с обходов намного лучше:

import argonaut._, Argonaut._ 
import monocle.function.{ each, index }, monocle.std.list._ 
import scalaz._, Scalaz._ 

val doc = """{ 
    "hashtags": [ 
    { "indices": [0, 3], "text": "foo" }, 
    { "indices": [3, 6], "text": "bar" } 
    ] 
}""" 

val \/-(json) = Parse.parse(doc) 

val lens = jObjectPrism 
    .composeOptional(index("hashtags")) 
    .composePrism(jArrayPrism) 
    .composeTraversal(each[List[Json], Json]) 
    .composePrism(jObjectPrism) 
    .composeOptional(index("text")) 
    .composePrism(jStringPrism) 

И потом:

scala> lens.getAll(json) 
res0: List[argonaut.Argonaut.JsonString] = List(foo, bar) 

scala> lens.modify(_ + " (new)")(json).spaces2 
res1: String = 
{ 
    "hashtags" : [ 
    { 
     "indices" : [ 
     0, 
     3 
     ], 
     "text" : "foo (new)" 
    }, 
    { 
     "indices" : [ 
     3, 
     6 
     ], 
     "text" : "bar (new)" 
    } 
    ] 
} 

И так далее. Вы можете сделать что-то подобное с объективами Scalaz, но это потребует больше работы.

+0

Спасибо за ответ @Travis. Могу ли я уточнить, является ли это псевдокодом или он должен быть запущен? Причина, по которой я спрашиваю, заключается в том, что я не могу заставить ее работать сам. Ниже приведена ошибка, с которой я возвращаюсь: http://pastebin.com/UbdXjd3F Я использую версию Monocle 1.2.0, версию Scalaz 7.0.6 и версию Argonaut 6.0.4. Надеюсь, нет проблемы с зависимостью. – FintanH

+0

@FintahH Это реальная сессия REPL, но с Argonaut 6.1, в которой используется другая версия Monocle со слегка отличающейся компоновкой пакетов. На данный момент я не на компьютере, но могу дать правильный импорт для версии 6.0.4 позже. –

+0

@ FintanH О, извините, я ошибся - линзы Monocle вообще не были доступны в 6.0.4. –

0

Ну, если вы хотите только извлечь поля:

import argonaut._, Argonaut._ 
import scalaz._, Scalaz._ 

val doc = """{ 
    "hashtags": [ 
    { "indices": [0, 3], "text": "foo" }, 
    { "indices": [3, 6], "text": "bar" } 
    ] 
}""" 

val \/-(json) = Parse.parse(doc) 
val lense = jObjectPL 
val hashtags = (lense >=> jsonObjectPL("hashtags") >=> jArrayPL).get(json) 

hashtags.get.foreach(i => (lense >=> jsonObjectPL("indices")).get(i).get.println) 
hashtags.get.foreach(i => (lense >=> jsonObjectPL("text")).get(i).get.println) 

..or лучше

val ind = ((v:Json) =>(lense >=> jsonObjectPL("indices")).get(v).get) 
val text = ((v:Json) =>(lense >=> jsonObjectPL("text")).get(v).get) 

hashtags.get.foreach(i => (ind(i), text(i)).println)