Làm thế nào để phân tích cú pháp JSON trong Kotlin?


121

Tôi đang nhận một chuỗi đối tượng JSON khá sâu từ một dịch vụ mà tôi phải phân tích cú pháp thành một đối tượng JSON và sau đó ánh xạ nó tới các lớp.

Làm cách nào để chuyển đổi chuỗi JSON thành đối tượng trong Kotlin?

Sau đó, ánh xạ tới các lớp tương ứng, tôi đã sử dụng StdDeserializer từ Jackson. Vấn đề nảy sinh tại thời điểm đối tượng có các thuộc tính cũng phải được giải hóa thành các lớp. Tôi đã không thể tải được trình ánh xạ đối tượng, ít nhất là tôi không biết làm thế nào, bên trong một bộ khử không khí khác.

Cảm ơn trước sự giúp đỡ nào. Tốt hơn là, về nguyên bản, tôi đang cố gắng giảm số lượng phụ thuộc tôi cần, vì vậy nếu câu trả lời chỉ dành cho thao tác JSON và phân tích cú pháp thì là đủ.


2
Tôi chưa phát triển bằng Java. Đó không phải là lỗi mà tôi đang gặp phải. Tôi chỉ không biết làm thế nào để thực hiện phân tích cú pháp hiệu quả trong Kotlin. Tất cả các tìm kiếm luôn dẫn đến một khuôn khổ. Java có org.json.simple. Tin tưởng vào các tính năng tự động hoàn thành của IDE, Kotlin thì không.
AJ_1310,

Gói org.json.simple không có nguồn gốc từ Java. Tôi đoán đó là thư viện này: github.com/fangyidong/json-simple . Bạn cũng có thể sử dụng nó với Kotlin nếu muốn (mặc dù thư viện klaxon mà Jason Bourne đề xuất có thể là lựa chọn tốt hơn cho Kotlin).
marstran

Hãy xem github.com/square/moshi . Có một bài viết trên blog về nó tại medium.com/square-corner-blog/...
James Moore

Câu trả lời:


72

Bạn có thể sử dụng thư viện này https://github.com/cbeust/klaxon

Klaxon là một thư viện nhẹ để phân tích cú pháp JSON trong Kotlin.


86
Tác giả ở đây, vui lòng gửi email cho tôi nếu bạn có câu hỏi / đề xuất.
Cedric Beust

Tôi phải nhập thư viện java nào để có được Trình phân tích cú pháp chính xác? Tôi đã thử org.json. *, Nhưng tôi phải thiếu một cái gì đó trong cài đặt Gradle của mình. Tôi nghĩ rằng tài liệu Klaxon giả định quá nhiều (giống như người dùng biết các thư viện Java).
Makis

@CedricBạn đã thử làm việc với đối tượng lớp với sqlite chưa? bất kỳ thực hành được đề nghị ở đây?
Raju yourPepe

104

Không có nghi ngờ gì rằng tương lai của phân tích cú pháp trong Kotlin sẽ là với kotlinx.serialization. Nó là một phần của các thư viện Kotlin. Nó vẫn đang ở thời điểm viết trong giai đoạn ấp trứng.

https://github.com/Kotlin/kotlinx.serialization

import kotlinx.serialization.*
import kotlinx.serialization.json.JSON

@Serializable
data class MyModel(val a: Int, @Optional val b: String = "42")

fun main(args: Array<String>) {

    // serializing objects
    val jsonData = JSON.stringify(MyModel.serializer(), MyModel(42))
    println(jsonData) // {"a": 42, "b": "42"}

    // serializing lists
    val jsonList = JSON.stringify(MyModel.serializer().list, listOf(MyModel(42)))
    println(jsonList) // [{"a": 42, "b": "42"}]

    // parsing data back
    val obj = JSON.parse(MyModel.serializer(), """{"a":42}""")
    println(obj) // MyModel(a=42, b="42")
}

3
Vấn đề tôi gặp phải là bạn khó có thể sử dụng nó với thuốc generic. Ít nhất là tôi đã không tìm ra cách làm như vậy. Và tôi chắc chắn không muốn sử dụng sự phản chiếu.
natronite

3
KotlinX Serialization vẫn đang trong giai đoạn thử nghiệm, vì vậy họ giới thiệu những thay đổi đột phá trong các bản phát hành mới. Ngoài ra, nó không an toàn cho chuỗi, vì vậy JSON của bạn có thể bị hỏng nếu một số chuỗi cố gắng sử dụng một phiên bản duy nhất của Json(nó phổ biến). Hơn nữa, có một số vấn đề Github mở với nhãn lỗi. Vì vậy, tôi sẽ nói rằng nó vẫn có rủi ro khi sử dụng trong sản xuất (trừ khi bạn sẵn sàng dành thời gian để khắc phục các sự cố tiềm ẩn và không có kế hoạch cập nhật nó thường xuyên). Dự án thực sự thú vị, đặc biệt đối với các dự án Kotlin Multiplatform, nhưng nó vẫn chưa ổn định.
Javad Sadeqzadeh

Dường như đã có một sự thay đổi đột
ngột

Điều này cũng yêu cầu phụ thuộc bổ sung, vì vậy hãy truy cập liên kết để được hướng dẫn
xjcl

34

Không có thư viện bên ngoài (trên Android)

Để phân tích cú pháp này:

val jsonString = """
    {
       "type":"Foo",
       "data":[
          {
             "id":1,
             "title":"Hello"
          },
          {
             "id":2,
             "title":"World"
          }
       ]
    }        
"""

Sử dụng các lớp sau:

import org.json.JSONObject

class Response(json: String) : JSONObject(json) {
    val type: String? = this.optString("type")
    val data = this.optJSONArray("data")
            ?.let { 0.until(it.length()).map { i -> it.optJSONObject(i) } } // returns an array of JSONObject
            ?.map { Foo(it.toString()) } // transforms each JSONObject of the array into Foo
}

class Foo(json: String) : JSONObject(json) {
    val id = this.optInt("id")
    val title: String? = this.optString("title")
}

Sử dụng:

val foos = Response(jsonString)

2
Vì vậy, nếu điều này không yêu cầu bất kỳ thư viện bên ngoài nào, điều đó có nghĩa là org.json.JSONObject là một phần của thư viện chuẩn phải không?
still_dreaming_1

@ still_dreaming_1 vâng, đúng như vậy, "Đã thêm vào API cấp 1", cf. developer.android.com/reference/org/json/JSONObject.html
frouo

Tôi đoán đó là một thứ Android? Tôi đã tìm kiếm nó trong thư viện chuẩn Kotlin hoặc Java cho JVM.
still_dreaming_1

Ồ, hoàn toàn có thể, tôi xin lỗi vì tôi đã quên đề cập điều đó trong câu trả lời! Có thể bạn có thể sử dụng JsonObjectnếu JVM của bạn đang chạy trong Java7 ( docs.oracle.com/javaee/7/api/javax/json/JsonObject.html )?
frouo

Ồ, tôi không tìm thấy cái đó trước đây, cảm ơn! Có một số lớp liên quan khác như JsonReader. Có vẻ như chúng là một phần của Java EE, nhưng không phải là Java SE. Tôi sẽ xem xét có thể chuyển sang Java EE.
still_dreaming_1

26

Bạn có thể sử dụng Gson.

Thí dụ

Bước 1

Thêm biên dịch

compile 'com.google.code.gson:gson:2.8.2'

Bước 2

Chuyển đổi json thành Kotlin Bean(sử dụng JsonToKotlinClass )

Như thế này

Json dữ liệu

{
"timestamp": "2018-02-13 15:45:45",
"code": "OK",
"message": "user info",
"path": "/user/info",
"data": {
    "userId": 8,
    "avatar": "/uploads/image/20180115/1516009286213053126.jpeg",
    "nickname": "",
    "gender": 0,
    "birthday": 1525968000000,
    "age": 0,
    "province": "",
    "city": "",
    "district": "",
    "workStatus": "Student",
    "userType": 0
},
"errorDetail": null
}

Kotlin Bean

class MineUserEntity {

    data class MineUserInfo(
        val timestamp: String,
        val code: String,
        val message: String,
        val path: String,
        val data: Data,
        val errorDetail: Any
    )

    data class Data(
        val userId: Int,
        val avatar: String,
        val nickname: String,
        val gender: Int,
        val birthday: Long,
        val age: Int,
        val province: String,
        val city: String,
        val district: String,
        val workStatus: String,
        val userType: Int
    )
}

Bước 3

Sử dụng Gson

var gson = Gson()
var mMineUserEntity = gson?.fromJson(response, MineUserEntity.MineUserInfo::class.java)

này mang lại cho tôi java.lang.IllegalStateException: Dự kiến một chuỗi nhưng BEGIN_OBJECT tại dòng 1 cột 700 đường
Srishti Roy

Bạn nên kiểm tra dữ liệu của bạn trở lại đầu tiên @ SrishtiRoy.
KeLiuyue

nó hoạt động, nhưng nếu phản hồi json của tôi giống như "danh mục": ["Được đề xuất"], thì?
Srishti Roy

@SrishtiRoy phản hồi là dữ liệu JSON bất hợp pháp. Legal JSON dữ liệu được bắt đầu với {hoặc[
KeLiuyue

1
Vấn đề với Gson là nó bỏ qua tính vô hiệu. Có valthể dễ dàng có một thuộc tính nullnếu nó bị thiếu trong JSON. Ngoài ra, các giá trị mặc định hoàn toàn không được sử dụng.
user3738870

21

Không chắc đây có phải là thứ bạn cần hay không nhưng đây là cách tôi đã làm.

Sử dụng import org.json.JSONObject:

    val jsonObj = JSONObject(json.substring(json.indexOf("{"), json.lastIndexOf("}") + 1))
    val foodJson = jsonObj.getJSONArray("Foods")
    for (i in 0..foodJson!!.length() - 1) {
        val categories = FoodCategoryObject()
        val name = foodJson.getJSONObject(i).getString("FoodName")
        categories.name = name
    }

Đây là một mẫu của json:

{"Thực phẩm": [{"FoodName": "Táo", "Trọng lượng": "110"}]}


8
sự phụ thuộc là gì?
Luís Soares

Tôi đã sử dụng org.json. Đây là liên kết: mvnrepository.com/artifact/org.json/json/20180813
markB

Phương thức này yêu cầu lớp đó phải có hàm tạo mặc định mà không có bất kỳ tham số nào. Điều gì nếu lớp dữ liệu có params trong constructor như dưới đây: data class SomeClass(val param1: Int, val param2: Int).
leimenghao

@leimenghao Bạn có thể thực hiện việc này trong một dòng: val Category = SomeClass (param1 = foodJson.getJSONObject (i) .getString ("FoodName"), param2 = foodJson.getJSONObject (i) .getInt ("Trọng lượng"))
markB

Hoạt động thực sự tốt. Chỉ để nói, bạn có thể sử dụng for (i in 0 until foodJson!!.length()) {thay thế for (i in 0..foodJson!!.length() - 1) {. Nó cũng làm như vậy, và nó khá trực quan hơn
Arnyminer Z

12

Cá nhân tôi sử dụng mô-đun Jackson cho Kotlin mà bạn có thể tìm thấy ở đây: jackson-module-kotlin .

implementation "com.fasterxml.jackson.module:jackson-module-kotlin:$version"

Ví dụ, đây là mã để phân tích cú pháp JSON của kỹ năng Path of Exile khá nặng (84k dòng khi được định dạng):

Mã Kotlin:

package util

import com.fasterxml.jackson.databind.DeserializationFeature
import com.fasterxml.jackson.module.kotlin.*
import java.io.File

data class SkillTreeData( val characterData: Map<String, CharacterData>, val groups: Map<String, Group>, val root: Root,
                          val nodes: List<Node>, val extraImages: Map<String, ExtraImage>, val min_x: Double,
                          val min_y: Double, val max_x: Double, val max_y: Double,
                          val assets: Map<String, Map<String, String>>, val constants: Constants, val imageRoot: String,
                          val skillSprites: SkillSprites, val imageZoomLevels: List<Int> )


data class CharacterData( val base_str: Int, val base_dex: Int, val base_int: Int )

data class Group( val x: Double, val y: Double, val oo: Map<String, Boolean>?, val n: List<Int> )

data class Root( val g: Int, val o: Int, val oidx: Int, val sa: Int, val da: Int, val ia: Int, val out: List<Int> )

data class Node( val id: Int, val icon: String, val ks: Boolean, val not: Boolean, val dn: String, val m: Boolean,
                 val isJewelSocket: Boolean, val isMultipleChoice: Boolean, val isMultipleChoiceOption: Boolean,
                 val passivePointsGranted: Int, val flavourText: List<String>?, val ascendancyName: String?,
                 val isAscendancyStart: Boolean?, val reminderText: List<String>?, val spc: List<Int>, val sd: List<String>,
                 val g: Int, val o: Int, val oidx: Int, val sa: Int, val da: Int, val ia: Int, val out: List<Int> )

data class ExtraImage( val x: Double, val y: Double, val image: String )

data class Constants( val classes: Map<String, Int>, val characterAttributes: Map<String, Int>,
                      val PSSCentreInnerRadius: Int )

data class SubSpriteCoords( val x: Int, val y: Int, val w: Int, val h: Int )

data class Sprite( val filename: String, val coords: Map<String, SubSpriteCoords> )

data class SkillSprites( val normalActive: List<Sprite>, val notableActive: List<Sprite>,
                         val keystoneActive: List<Sprite>, val normalInactive: List<Sprite>,
                         val notableInactive: List<Sprite>, val keystoneInactive: List<Sprite>,
                         val mastery: List<Sprite> )

private fun convert( jsonFile: File ) {
    val mapper = jacksonObjectMapper()
    mapper.configure( DeserializationFeature.ACCEPT_EMPTY_ARRAY_AS_NULL_OBJECT, true )

    val skillTreeData = mapper.readValue<SkillTreeData>( jsonFile )
    println("Conversion finished !")
}

fun main( args : Array<String> ) {
    val jsonFile: File = File( """rawSkilltree.json""" )
    convert( jsonFile )

JSON (không định dạng): http://filebin.ca/3B3reNQf3KXJ/rawSkilltree.json

Với mô tả của bạn, tôi tin rằng nó phù hợp với nhu cầu của bạn.


1
Khác nhau từ Klaxon (nó có một lỗi khi tôi đã cố gắng), Jackson thực sự hoạt động :)
redsk

Ngoài ra, bạn có thể sử dụng plugin lớp dữ liệu JSON to Kotlin trong intellij để tạo các lớp dữ liệu cho bạn.
Brooks DuBois

7

Để chuyển đổi JSON sang Kotlin, hãy sử dụng http://www.json2kotlin.com/

Ngoài ra, bạn có thể sử dụng plugin Android Studio. File> Settings, chọn Pluginsở cây bên trái, nhấn "Browse repositories ...", tìm kiếm " JsonToKotlinClass ", chọn nó và nhấp vào nút màu xanh lá cây "Install".

cắm vào

Sau khi khởi động lại AS, bạn có thể sử dụng nó. Bạn có thể tạo một lớp với File > New > JSON To Kotlin Class (JsonToKotlinClass). Một cách khác là nhấn Alt + K.

nhập mô tả hình ảnh ở đây

Sau đó, bạn sẽ thấy một hộp thoại để dán JSON.

Vào năm 2018, tôi đã phải thêm package com.my.package_namevào đầu một lớp học.


4

Đầu tiên.

Bạn có thể sử dụng plugin chuyển đổi lớp dữ liệu JSON sang Kotlin trong Android Studio để ánh xạ JSON tới các lớp POJO (lớp dữ liệu kotlin). Plugin này sẽ chú thích lớp dữ liệu Kotlin của bạn theo JSON.

Sau đó, bạn có thể sử dụng công cụ chuyển đổi GSON để chuyển đổi JSON sang Kotlin.

Làm theo hướng dẫn hoàn chỉnh này: Hướng dẫn phân tích cú pháp Kotlin Android JSON

Nếu bạn muốn phân tích cú pháp json theo cách thủ công.

val **sampleJson** = """
  [
  {
   "userId": 1,
   "id": 1,
   "title": "sunt aut facere repellat provident occaecati excepturi optio 
    reprehenderit",
    "body": "quia et suscipit\nsuscipit recusandae consequuntur expedita"
   }]
   """

Mã để phân tích cú pháp phía trên Mảng JSON và đối tượng của nó ở chỉ mục 0.

var jsonArray = JSONArray(sampleJson)
for (jsonIndex in 0..(jsonArray.length() - 1)) {
Log.d("JSON", jsonArray.getJSONObject(jsonIndex).getString("title"))
}

1

http://www.jsonschema2pojo.org/ Xin chào, bạn có thể sử dụng trang web này để chuyển đổi json sang pojo.
điều khiển + Alt + shift + k

Sau đó, bạn có thể chuyển đổi thủ công lớp mô hình đó thành lớp mô hình kotlin. với sự trợ giúp của phím tắt trên.


1
Nó sẽ chuyển đổi sang Java.
CoolMind

0

Hơi muộn nhưng sao cũng được.

Nếu bạn thích phân tích cú pháp JSON thành JavaScript như các cấu trúc sử dụng ngữ nghĩa Kotlin, tôi khuyên bạn nên dùng JSONKraken , mà tôi là tác giả.

Các đề xuất và ý kiến ​​về vấn đề này được đánh giá cao!


-4

Tải xuống nguồn deme từ đây ( Json phân tích cú pháp trong android kotlin )

Thêm phần phụ thuộc này:

compile 'com.squareup.okhttp3:okhttp:3.8.1'

Gọi hàm api:

 fun run(url: String) {
    dialog.show()
    val request = Request.Builder()
            .url(url)
            .build()

    client.newCall(request).enqueue(object : Callback {
        override fun onFailure(call: Call, e: IOException) {
            dialog.dismiss()

        }

        override fun onResponse(call: Call, response: Response) {
            var str_response = response.body()!!.string()
            val json_contact:JSONObject = JSONObject(str_response)

            var jsonarray_contacts:JSONArray= json_contact.getJSONArray("contacts")

            var i:Int = 0
            var size:Int = jsonarray_contacts.length()

            al_details= ArrayList();

            for (i in 0.. size-1) {
                var json_objectdetail:JSONObject=jsonarray_contacts.getJSONObject(i)


                var model:Model= Model();
                model.id=json_objectdetail.getString("id")
                model.name=json_objectdetail.getString("name")
                model.email=json_objectdetail.getString("email")
                model.address=json_objectdetail.getString("address")
                model.gender=json_objectdetail.getString("gender")

                al_details.add(model)


            }

            runOnUiThread {
                //stuff that updates ui
                val obj_adapter : CustomAdapter
                obj_adapter = CustomAdapter(applicationContext,al_details)
                lv_details.adapter=obj_adapter
            }

            dialog.dismiss()

        }

    })
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.