TypeMismatch Exception when Arrays from Dictionary

I know this is not a new topic. I have read the past posts, but still cannot get this to work, even using the examples provided.

I am storing an array (of strings) in a dictionary, then exporting the dictionary to JSON using GenerateJSON. Inspecting the JSON file shows the array of strings propertly formatted.

Then I read file back into a TextInputStream and call ParseJSON (Xojo 2019 r3.1 Mac).
So far, so good, no Exceptions

Here is what happens when I try to access the result of ParseJSON

var x as integer
var s as string
var d as dictionary
var list() as string

var restoredData() as variant = ParseJSON( textFromInputStream )
for each dict as Dictionary in restoredData     'OK
   x = dict.value("keyFor_AnInteger")          'OK
   s = dict.value("keyFor_AString")         'OK
   d = dict.value("keyFor_ADictionary")        'OK
   list = dict.value("keyFor_StringArray")        'TYPE MISMATCH EXCEPTION         
next

Ok, everything is a variant. I see that in the Docs
But the for…each loop iterator coerces a variant() into a dictionary() behind the scenes.
Not so for the string() stored in the dictionary.

I can view the data on disk, retrieve it, but not reference it. I cannot caste the variant back into a string(), nor loop it.

I have tried:

for each s as string in dict.value("keyFor_StringArray")          
    'Compiler says:  This is not an array but you are using it as one
next

var retrieved() as string = data.value("keyFor_StringArray")       'Compiles, but
for each s as string in retrieved          'TYPE MISMATCH EXCEPTION
     ...
next

list = Array(dict.value("keyFor_StringArray"))     'NOPE..compiler says TypeMismatchError

var v as variant = dict.value("keyFor_StringArray")
if v.isArray then
     //still cannot refernce the variant as an array
end if

There is an obvious trick here, but somehow I can’t see the forest through the trees.

What is the best technique to solve this?

Thanks in advance

Are you sure? The For each condition seems wrong to me (answering from my iPhone)

Something like

For each v as variant in RestoredData
Dim dict as new dictionary = dict(v)

keyFor_StringArray may be an array of variant, not string.

The new framework JSON stuff is too ambiguous for my taste. It’s worlds faster, but it’s significantly harder to develop with. Classic framework JSONItem was always JSONItem and easy to work with.

my use of “keyFor_StringArray” was illustrative in my posting. The actual code is using another key, which is a different string, but the results are the same no matter what key I choose for the string(). Thanks

Thanks for the suggestion. I modified my code to:

var d as dictionary
for each v as variant in restoredData
    d = Dictionary(v)
    ....
next

The coercion (Variant to Dictionary) is now explicit, but the result is the same. The string() stored under (any) key yields a Type Mismatch Exception if I try to loop the variant returned from that key.

There must be a way to coerce the variant into String(), or loop the array and get the strings back out somehow.

Thanks

Christian:

list = dict.value("keyFor_StringArray")

The returned value stored in “list” is definitely a variant. Also, when testing for .isArray, the result is true:

if list.isArray then         'OK..true
  for each s as string in list       'TYPE MISMATCH EXCEPTION here
     ...
   next
end if

What I can’t seem to do is coerce the variant back into a string(), or reference any of the array indices because it doesn’t loop in an interator. Compiler rejects the code with “not an array” compiler message if I try to use any interation.

Thanks

I think it might help if we could see the JSON source it’s trying to parse. That may yield a clue to what Xojo is thinking…

Something like this may help:

if list.isArray then
  Dim List2() as variant = list
  for each s as string in list2
     ...
   next
end if

With assignment of variant to local list2 variable, we convert it and then for each works.

1 Like

list is a variant. To use it, you need to assign it to a string array

dim list as variant = dict.value("keyFor_StringArray")
dim stringarray() as string = list
for each s as string in stringarray
   // do something with s
next

Christian:

Yes, your method worked. Many thanks
I had to test it with some real data, and of course it makes perfect sense (now) that each array item needs to be caste back to string, rather than the array itself.

I haven’t tested Tim Hare’s idea yet, but this also makes sense

Thanks to all