使用scala提取嵌套的JSON元素

时间:2016-08-07 08:40:07

标签: json scala nested json4s

我在Scala中有以下代码。我的目标是在不知道密钥的数量和深度的情况下提取密钥的值。

    import org.json4s.jackson.JsonMethods._
    import org.json4s.{DefaultFormats, JField, JObject, JString, JValue}

    object jsonLift {

        implicit val formats = DefaultFormats

        val js = parse(
            """
    {
      "url": "imap.yahoo.com",
        "credentials": {
        "username": "myusername",
        "password": "mypassword"
         },
        "some key":{
            "other key": {
                "username": "hello"
            }
        }
    }
            """)


            def getElem(elem: String, json:JValue) = for {
                    JObject(child) <- json
                    JField(elem, JString(value)) <- child       // this does not return the expected result
    //              JField("username", JString(value)) <- child // this returns the expected result
                } yield  value


        def main(args: Array[String]) {

            val result = getElem("username", js)
            println(result)

        }
    }

上述代码的结果是List(imap.yahoo.com, myusername, mypassword, hello),这不是我所期待的。我的预期结果是List(myusername, hello)

但是,如果我直接在方法elem内部使用我感兴趣的键(作为字符串)更改变量getElem(例如:&#34;用户名&#34;)我得到了预期的结果:List(myusername, hello)这是键的所有值&#34;用户名&#34;。

如何通过调用方法getElem并将JSON键的名称作为参数来获取预期的值列表?例如:getElem("JSON key", json)

谢谢!

2 个答案:

答案 0 :(得分:3)

def getElem(elem: String, json:JValue) = for { JObject(child) <- json JField(`elem`, JString(value)) <- child } yield value 更改为

elem

如果没有RHS上type JField = (String, JValue)周围的反引号,您就会将elem的第一个元素绑定到新名称elem并隐藏方法参数import CoreLocation public class SwiftLocation: NSObject, CLLocationManagerDelegate { private let locationManager = CLLocationManager() private var latestCoord: CLLocationCoordinate2D init(ignore:String) { locationManager.requestAlwaysAuthorization() locationManager.desiredAccuracy = kCLLocationAccuracyBest locationManager.distanceFilter = kCLDistanceFilterNone locationManager.startUpdatingLocation() latestCoord = locationManager.location!.coordinate super.init() locationManager.delegate = self } private func locationManager(manager: CLLocationManager, didUpdateToLocation newLocation: CLLocation, fromLocation oldLocation: CLLocation) { latestCoord = manager.location!.coordinate } public func getLatest() -> CLLocationCoordinate2D { return latestCoord } }

答案 1 :(得分:1)

所以,这里的问题是当你使用时:

JField(elem, JString(value)) <- child 

在您的理解范围内,这个elem的新定义会影响您传递到elem方法的getElem

我猜你的意图是,如果传递到elem的{​​{1}}值与getElem的名称相同,那么这将匹配。但这不是它的工作原理,而是将符号elem绑定到键名。

您可以通过对上面一行的小改动来达到您想要的效果,如下所示:

JField

仅当JField(key, JString(value)) <- child if key == elem 的名称与value匹配时才会将值绑定到JField