LoginSignup
10
10

More than 5 years have passed since last update.

keyが完全に不定なjsonをなんとかGsonでパースする

Posted at

前提

Androidにおけるjsonのパーサーライブラリの鉄板といえばGsonですが(個人調べ)、このライブラリはKotlinでも問題なく(個人調べ)利用することができます。

User.kt
data class User(
        val userId: String,
        val username: String
)
MainClass.kt
val user = Gson().fromJson(json, User::class.java)

keyが完全に不定なjson

mediumは投稿関連のAPIしか提供されていませんが、各URLにformat=jsonのクエリを入れることでjsonが返ってくるようになるので、これをGsonでパースすることができます。

サンプルURL: https://medium.com/japan?format=json

top.json
])}while(1);</x>{"success":true,"payload":{"collection":{"id":"ee897b6da065","name":"Medium Japan","slug":"japan","tags":["PUBLICATIONS","JAPANESE","MEDIUM JAPAN","日本語"],"creatorId":"cd5018cebde7","description":"Medium 公式の日本語専用パブリケーションです。","shortDescription":"Medium 公式の日本語専用パブリケーションです。","image":{"imageId":"1*etUthOXG-BrZm25K7wEcgA.png","filter":"","backgroundSize":"","originalWidth":500,"originalHeight":500,"strategy":"resample","height":0,"width":0},"metadata":{"followerCount":4101,"activeAt":1487168607377},"virtuals":{"permissions":{"canPublish":false,"canPublishAll":false,"canRepublish":false,"canRemove":false,"canManageAll":false,"canSubmit":false,"canEditPosts":false,"canAddWriters":false,"canViewStats":false,"canSendNewsletter":false,"canViewLockedPosts":false,"canViewCloaked":false,"canEditOwnPosts":false,"canBeAssignedAuthor":false},"isSubscribed":false,"isNewsletterSubscribed":false,"memberOfMembershipPlanId":""},"logo":{"imageId":"1*etUthOXG-BrZm25K7wEcgA.png","filter":"","backgroundSize":"","originalWidth":500,"originalHeight":500,"strategy":"resample","height":0,"width":0},"twitterUsername":"MediumJapan","facebookPageName":"MediumJapan","sections":[{"type":2,"collectionHeaderMetadata":{"title":"Medium Japan","description":"Medium の公式日本語パブリケーションへようこ
// 省略

ちなみに先頭にXSS対策で付いている(と思われる) ])}while(1);</x>{ を削除した上でパースする必要があります。

ただし、このjsonはUser情報やPost情報のリストが配列ではなく、各IDをkeyとしたオブジェクトで登録されています。これだと @SerializedName(alternate = {}) でもパースは事実上不可能です。

top.json
{
   "payload":{
      "references":{
         "User":{
            "1106b2cd94a5":{
               "userId":"1106b2cd94a5",
               "username":"rayyama"
            },
            "c78a7314d9a5":{
               "userId":"c78a7314d9a5",
               "username":"SayakaNogawa",
            },
            "6673db351714":{
               "userId":"6673db351714",
               "username":"mach"
            }
         }
      }
   }
}

※ 必要な部分を抜粋

Mapとしてjsonをパースする

ということでどうすれば取れるかを考えたのですが、keyの値は不定でも文字列型であることは一定しているので、Mapとして取得できるみたいです。

User.kt
data class Payload(
        val references: References
)

data class References(
        @SerializedName("User") val users: Map<*, User>
)

data class User(
        val userId: String,
        val username: String
)
MainClass.kt
val users = Gson().fromJson(json, Payload::class.java)

// 各ユーザーのuserIdを出力
for ((_, user) in users.payload.references.users) {
    Log.d(TAG, user.userId)
}

今回はKotlinでやってみましたが、おそらくjavaも同じ要領で Map<String, User> でいけるんじゃないかと思います。
ご指摘等あれば編集リクエストまたはコメントにてお願いします。

10
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
10