Visual Basic 中学校 掲示板 投稿内容
タグのない投稿を抽出 統計 RSS

Visual Basic 中学校 > 投稿一覧 >

WebView2で複雑な戻り値を取得するには? 解決済み

タグの編集...

投稿者 Ado   (高校生)   投稿日時 2022/6/26 11:37:00
こんにちは!
WebView2を使って自作HPにアクセスするプログラムを作っています。
WebBrowserだと直接タグ要素を扱うHtmlElement等があるのですが、
WebView2ではすべてJavaScriptで行う必要があるということまでは理解できました。
戻り値のあるJavaScriptを書けばVB側でそれを受け取ることも可能であることも分かりましたが、
例えば、
・文字列(String)
・数値(例えばInteger)の配列
を同時に受け取るにはどうすればいいのでしょうか?

ぼくの方で出来たのは、
WebView2のExecuteScriptAsyncの戻り値をjsとして、
System.Text.JsonのDeserializeを使って、
・文字列(String)のみ
 System.Text.Json.JsonSerializer.Deserialize(Of String)(js)
・文字列(String)の配列
 System.Text.Json.JsonSerializer.Deserialize(Of String())(js)
・値が文字列(String)の連想配列
・System.Text.Json.JsonSerializer.Deserialize(Of Dictionary(Of String, String))(js)

のようにして値を受け取ることが出来ました。
ただし、文字列と数値配列の両方を受け取ろうと試してみたところ、
例えば、ExecuteScriptAsyncの戻り値が
{"NAME":"○○流星","ITEMS":[0,2,4,6,8]}のようになりました。
この時に"NAME"の値と"ITEMS"の配列を受け取る方法が分かりません。
Javascript側で数値配列をすべて文字列にして、1つの文字列配列にする方法なら
自力でできるのですが、やっぱり目的の異なる値を同じ配列に入れるのもどうかと思います。
どのようにすればよいでしょうか?

投稿者 (削除されました)   ()   投稿日時 2022/6/26 14:11:39
(削除されました)

投稿者 魔界の仮面弁士   (社会人)   投稿日時 2022/6/26 22:20:53
> ExecuteScriptAsyncの戻り値が
> {"NAME":"○○流星","ITEMS":[0,2,4,6,8]}のようになりました。
ExecuteScriptAsync の戻り値は、常に「Json エンコードされた文字列」ですからね。
Json ライブラリによって、Json の配列オブジェクトの扱い方が異なるので、初見ではわかりにくいかも。

なお JavaScript に Integer は無いので、数値を扱うとすれば、
プリミティブな number (または Number オブジェクト)を入れておいて
それを VB 側で Integer に変換して使うといった手法を取ります。

JavaScript の number 型は VB の Double 型に相当していますが、
NaN や Infinity は Json で扱えません。そのため、数値範囲によっては
string で出力して、VB 側で追加変換するといった手法がとられることもあります。
今回は Integer の範囲なので気にしなくても良いですが。



> 目的の異なる値を同じ配列に入れるのもどうかと思います。
> どのようにすればよいでしょうか?
目的ごとに別のメンバーにした方が良いとは思いますよ。
それに Json の階層構造は幾らでも増やせますので、
配列の中にまた別のオブジェクト構造を入れるといったこともできます。


Json 配列のデシアライズの方法は色々ありますが…何パターンか記載してみます。
型付きなら例1か例4を試してみてください。
前準備が必要ではありますが、利用するのはとても簡単です。

型が動的である場合は、自分は例3を使うことが多いです。
(下記の他にも幾つかの手法があります)

'例1および例4で使うクラス 
Class Example
    Public Property NAME As String
    Public Property ITEMS As Integer()
End Class

Dim jsonResult As String = <json>{"NAME":"○○流星","ITEMS":[0,2,4,6,8]}</json>.Value

'--- Newtonsoft.Json 編 ---> 
'例1 
Dim obj1 = JsonConvert.DeserializeObject(Of Example)(jsonResult)
Dim name1 = obj1.NAME
Dim items1 = obj1.ITEMS

'例2 
Dim obj2 = JsonConvert.DeserializeObject(Of JObject)(jsonResult)
Dim name2 = CStr(obj2!NAME)
Dim items2 = obj2!ITEMS.Select(AddressOf Convert.ToInt32).ToArray()

'例3 
Dim obj3 = JObject.Parse(jsonResult)
Dim name3 = obj3.Value(Of String)("NAME")
Dim jItems3 = obj3("ITEMS").ToObject(Of Integer())



'--- System.Text.Json 編 ---> 
'Imports System.Dynamic 
'Imports System.Text.Json 

'例4 
Dim obj4 = JsonSerializer.Deserialize(Of Example)(jsonResult)
Dim name4 = obj4.NAME
Dim items4 = obj4.ITEMS

'例5 
Dim obj5 As IDictionary(Of StringObject) = JsonSerializer.Deserialize(Of ExpandoObject)(jsonResult)
Dim name5 = obj5!NAME.ToString()
Dim items5 = CType(obj5!ITEMS, JsonElement).EnumerateArray().Select(Function(o) o.GetInt32()).ToArray()

'例6 
Dim obj6 = JsonDocument.Parse(jsonResult).RootElement
Dim name6raw = obj6.GetProperty("NAME").GetRawText()  '「"○○流星"」 
Dim name6 = obj6.GetProperty("NAME").GetString()      '「○○流星」 
Dim items6 = obj6.GetProperty("ITEMS").EnumerateArray().Select(Function(o) o.GetInt32()).ToArray()


投稿者 魔界の仮面弁士   (社会人)   投稿日時 2022/6/27 11:24:42
あー…すみません。例6で Dispose が漏れてましたね。
JsonDocument は IDisposable なので Using ブロックで囲んで Dispose を保証するようにします。

'例6 
Using doc6 = JsonDocument.Parse(jsonResult)
    Dim obj6 = doc6.RootElement

    Dim name6raw = obj6.GetProperty("NAME").GetRawText()  '「"○○流星"」 生データ 
    Dim name6 = obj6.GetProperty("NAME").GetString()      '「○○流星」 

    Dim objItems6 = obj6.GetProperty("ITEMS")
    Dim legth6 = objItems6.GetArrayLength()      '「5」配列の要素数 
    Dim items6raw = objItems6.GetRawText()       '「[0,2,4,6,8]」生データ 
    Dim items6_0 = objItems6(0).GetInt32()       '「0」 
    Dim items6_1 = objItems6(1).GetInt32()       '「2」 
    Dim items6_2 = objItems6(2).GetInt32()       '「4」 
    Dim items6_3 = objItems6(3).GetInt32()       '「6」 
    Dim items6_4 = objItems6(4).GetInt32()       '「8」 
    items6_3 = obj6.GetProperty("ITEMS")(3).GetInt32() '「6」 

    For Each item6 In objItems6.EnumerateArray()
        Dim i = item6.GetInt32() '「0」「2」「4」「6」「8」が列挙される 

    Next

    '「Dim items6 As Integer() = {0, 2, 4, 6, 8}」に変換するための LINQ  
    Dim items6 = objItems6.EnumerateArray().Select(Function(o) o.GetInt32()).ToArray()
End Using



ついでなので、System.Text.Json で JSON の要素を返す Function を作る場合の注意。

'これは OK 。 
'ただし、受領側で Dispose が必須となるため取り扱いに注意。 
Return JsonDocument.Parse(s)    'JsonDocument 型 

'これは OK。 
'Clone で複製した場合、複製元は Dispose が必要だが、複製先は Dispose 不要となる。 
Using doc = JsonDocument.Parse(s)
    Return doc.RootElement.Clone()  'JSonElemet 型 
End Using

'これは NG。JSonDocument を Dispose できないため。 
Return JsonDocument.Parse(s).RootElement  'JSonElemet 型 

'これはもっと NG。ObjectDisposedException を誘発してしまう。 
Using doc = JsonDocument.Parse(s)
 Return doc.RootElement  'JSonElemet 型 
End Using


投稿者 Ado   (社会人)   投稿日時 2022/6/27 16:43:48
魔界の仮面弁士先生、ありがとうございました!
例4のやり方がやりやすくて、うまくいきました。
他の方法も勉強してみます!