質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.50%
JSON

JSON(JavaScript Object Notation)は軽量なデータ記述言語の1つである。構文はJavaScriptをベースとしていますが、JavaScriptに限定されたものではなく、様々なソフトウェアやプログラミング言語間におけるデータの受け渡しが行えるように設計されています。

VB.NET

Microsoft Visual Basic .NETのことで、Microsoft Visual Basic(VB6)の後継。 .NET環境向けのプログラムを開発することができます。 現在のVB.NETでは、.NET Frameworkを利用して開発を行うことが可能です。

Q&A

解決済

1回答

17946閲覧

入れ子になったjsonをVB.NETでパースする方法をご教示ください

bananaman

総合スコア7

JSON

JSON(JavaScript Object Notation)は軽量なデータ記述言語の1つである。構文はJavaScriptをベースとしていますが、JavaScriptに限定されたものではなく、様々なソフトウェアやプログラミング言語間におけるデータの受け渡しが行えるように設計されています。

VB.NET

Microsoft Visual Basic .NETのことで、Microsoft Visual Basic(VB6)の後継。 .NET環境向けのプログラムを開発することができます。 現在のVB.NETでは、.NET Frameworkを利用して開発を行うことが可能です。

0グッド

2クリップ

投稿2018/04/06 12:27

VS2017環境のVB.NETで、以下のようなjsonをパースしようとしましたが、エラーで困っています。
以下のようなjsonなのですが、contentのmenusが配列構造になっており、このgradeとmarkの値を取得する方法がわかりません。

//////////// json ///////////////
{
"response": {
"id": "xxxxxx",
"content": {
"menus": [
{
"grade": "A",
"mark": "1"
},
{
"grade": "B",
"mark": "2"
},
{
"grade": "C",
"mark": "3"
},
{
"grade": "D",
"mark": "4"
}
]
}
}
}
/////////// jsonここまで ///////////

VS標準の以下を参照してデシリアライズしています。
[参照]
Imports System.Runtime.Serialization.Json
[デシリアライズクラス]
Public Function Deserialize(Of T)(ByVal json As String) As T
Dim result As T
Dim serializer As New DataContractJsonSerializer(GetType(T))

Using stream As New IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(json)) result = DirectCast(serializer.ReadObject(stream), T) End Using Return result

End Function

Public Class grade_select_Rootobject
Public Property response As Response
End Class

Public Class grade_select_Response
Public Property id As String
Public Property content As grade_select_Content
End Class

Public Class grade_select_Content
Public Property menus() As grade_select_Menu
End Class

Public Class grade_select_Menu
Public Property grade As String
Public Property mark As String
End Class

以下は実行部分とそのエラーです。
[jsonの読み込み]
Rootobject = Deserialize(Of grade_select_Rootobject)(json)

[menusの件数取得]
Dim count As Integer = Rootobject.response.content.menus.Count
→ 9が取得できます。

この後、取得した件数(9)でループをしながら、各gradeとmarkを取得できると考えていました。
Dim i As Integer
For i = 0 To count - 1
MsgBox(grade_select_Rootobject.response.content.menus(i).grade.ToString)
Next
ループ内のメッセージボックスで、gradeの値が1件ずつ表示されると想定していましたが、
エラーメッセージは、「公開メンバー'grade'は型'Object'にみつかりませんでした」です。

どなたかお知恵のある方、解決策あるいは小職がミスをしている箇所をご指摘いただけないでしょうか。
よろしくお願いいたします。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

coco_bauer

2018/04/07 01:38

質問に書かれている jsonのデータでは、menusは4要素の配列ですよね?  「件数(9)」という解釈は間違っていませんか?
dodox86

2018/04/07 03:14 編集

コードも未完成のように見えます。 プロパティのPublic Property response As Response は、Public Property response As grade_select_Response の間違いではありませんか? また、読みにくいのでコード貼り付けもマークダウンを利用しましょう。 https://teratail.com/help#about-markdown
guest

回答1

0

ベストアンサー

一部補完して宣言の仕方など修正しましたが、おおむね元のご提示のコードでご要望のとおり動作しています。もとのコードに不備があったのではないでしょうか。再度確認してみてください。

(Visual Studio 2017 + .NET Framework 4.5 環境で確認)

UTF8 BOM有りのJsonファイルの内容(D:\data.json)

{ "response": { "id": "xxxxxx", "content": { "menus": [ { "grade": "A", "mark": "1" }, { "grade": "B", "mark": "2" }, { "grade": "C", "mark": "3" }, { "grade": "D", "mark": "4" } ] } } }

コードです。(WPF)

Imports System.Runtime.Serialization.Json Imports System.Text Class MainWindow Private Shared path As String = "D:\data.json" Public Function Deserialize(Of T)(ByVal json As String) As T Dim result As T Dim serializer As New DataContractJsonSerializer(GetType(T)) Using stream As New IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(json)) result = DirectCast(serializer.ReadObject(stream), T) End Using Return result End Function Private Sub Button1_Click(sender As Object, e As RoutedEventArgs) Handles Button1.Click Dim json As String = System.IO.File.ReadAllText(path, Encoding.UTF8) Using stream As New IO.MemoryStream(System.Text.Encoding.UTF8.GetBytes(json)) Dim root As grade_select_Rootobject root = Deserialize(Of grade_select_Rootobject)(json) Debug.Assert(root.response.content.menus IsNot Nothing) Dim count As Integer = root.response.content.menus.Count Trace.WriteLine("count = " + count.ToString()) For i As Integer = 0 To count - 1 Dim grade As String = root.response.content.menus(i).grade Dim mark As String = root.response.content.menus(i).mark Dim s As String = String.Format("{0}: grade={1}, mark={2}", i + 1, grade, mark) Trace.WriteLine(s) Next End Using End Sub End Class Public Class grade_select_Rootobject Public Property response As grade_select_Response End Class Public Class grade_select_Response Public Property id As String Public Property content As grade_select_Content End Class Public Class grade_select_Content ' Public Property menus() As grade_select_Menu Public Property menus As grade_select_Menu() End Class Public Class grade_select_Menu Public Property grade As String Public Property mark As String End Class

実行結果です。

count = 4 1: grade=A, mark=1 2: grade=B, mark=2 3: grade=C, mark=3 4: grade=D, mark=4

投稿2018/04/07 05:33

dodox86

総合スコア9183

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

bananaman

2018/04/07 17:27

ありがとうございました。コード不備が原因でした。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.50%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問