JSON (array/dictionaries) parsing

ricca.bruno

New member
Dear guys, i've recently moved from an iPhone to an android phone and found macrodroid to be a good alternative to iOS Shortcut app. For simple tasks and automation works like a charm, in some cases even with more advanced controls. However for what i consider a more complex task i fail to achieve what i want...I'm sure i just need to learn a different way to accomplish the same results.

So basically i would like to get, parse and send back JSON payloads to an API, I've managed to do that "easily" on iOS Shortcuts but I'm struggling with Macrodroid.

Let's come straight to the point, is the JSON parse explanation right on the wiki? https://macrodroidforum.com/wiki/index.php/Action:_JSON_Parse
Assuming it is, given an object with an entries that has an array i should be able to get all the keys from the entries of the given array
dictionary[phoneNumbers][type] = "home"

This is not happening however. I'll leave a screenshot of a macro I've created using the same exact example JSON. I'm unable to get that same output.

Screenshot.png
 

RSF

Well-known member
Your json_ext variable is a string, so it takes only a string value. The phoneNumbers variable is an array (of dictionaries).

You could get the phone type of the first array member with
1701890747873.png
(that'd put the value "Home" into the json_ext variable).

Is that what you're looking to do?
 

ricca.bruno

New member
Nope, this is not what i want to do. I would like to understand how to accomplish the same outcome of the example mentioned in the wiki:
Where it says "This data will be parsed into a dictionary variable in MacroDroid and end up populated with the data below:"
dictionary[phoneNumbers][type] = "home"

So i'm supposing that given an array "phoneNumbers" with multiple values all with a key named "type" i could get all the string/values for the given key using dictionary[phoneNumbers][type] which in my case would be json_dict[phoneNumbers][type]

Am I missing something?

I need to do a more complex thing at the end, but i'm struggling to understand how these data are getting parsed and how i can access them.

What i would like to accomplish at the end would be given a JSON response, parsed into a dictionary i want to create a new JSON with an array of "key:value" from the first JSON (which are in different positions and changes frequently, so i can't use array indexes) then make a selection dialog with only the keys and extract the corresponding value to be used for a new HTTP requests. I don't know if I managed to explain it correctly.
 

RSF

Well-known member
JSON Structure
The wiki is correct. MacroDroid is parsing your JSON and putting it into the json_dict variable. But note that the "phoneNumbers" element of the dictionary is an array; and, at least in MacroDroid, you can't "skip" a level of the JSON structure.

Looking at the example json_dict...
Screenshot 2023-12-07 8.51.53 AM.png
... its structure is:
  • A dictionary (json_dict) containing, as one of its elements, an
    • Array (json_dict[phoneNumbers); this contains an array of
      • Dictionaries (json_dict[phoneNumber][0], json_dict[phoneNumber][1], etc.), each of which contains a
        • String called number (json_dict[phoneNumber][0][number[) and a
        • String called type (json_dict[phoneNumber][0][type[)
In order to get to a phone number or type, you must include that array index (0, 1, etc.) in the middle, to pick which phoneNumber element you want.

So, you'll almost certainly need to implement some sort of iteration loop, to step through the values in the JSON and build your new variable.

Creating Selection Dialog
But it could help if you manually create an example of a dictionary or array to use in a Selection Dialog action, showing how you want to display the choices from the dictionary/array, and how you want to assign the user's choice to another variable.

For example, if you want a display like so...
1701970616716.png
You'd need to create an array like so:
1701970740592.png

Knowing that end result will help.
 

ricca.bruno

New member
Thank you very much for this extensive answers, I really appreciate the time you spent in writing the answer!

However that doesn't clarify why on the wiki there is
dictionary[phoneNumbers][type] = "home"

Would mind explaining what does the wiki want to "explain" with that? And how they skip the array index selection?

Yeah i thought iterating was the solution but I'm still struggling to understand how to "push" or add new data to a variable. Let's say i have an array consisting of 20 elements, and i want to extract two values from each element and put them on a new array or dictionary...what's the most simple way to accomplish that?
 

Endercraft

Moderator
Thank you very much for this extensive answers, I really appreciate the time you spent in writing the answer!

However that doesn't clarify why on the wiki there is
dictionary[phoneNumbers][type] = "home"

Would mind explaining what does the wiki want to "explain" with that? And how they skip the array index selection?

Yeah i thought iterating was the solution but I'm still struggling to understand how to "push" or add new data to a variable. Let's say i have an array consisting of 20 elements, and i want to extract two values from each element and put them on a new array or dictionary...what's the most simple way to accomplish that?
On the wiki it is an example and not your data.
 

RSF

Well-known member
Wiki Error
Ah. The example in the wiki does indeed have a mistake. Instead of
1701971880702.png
it should be
1701971950452.png
Apologies for having missed that point. I'm not an editor for the wiki, and don't see a way to send an edit request.

Iteration Example
See attached JSON.macro for an example of how you could iterate through the array-within-the-dictionary, creating a new array, called phoneNumber_array. Note that I edited the JSON text to add a second phone number, so it no longer matches the example JSON in the wiki.
1701972540135.png
 

Attachments

  • JSON.macro
    8.5 KB · Views: 3

ricca.bruno

New member
Now you got me, it would've been so easier if the wiki was correct since it would indeed help getting rid of iterate. Anyway thanks again, another extensive answer and now i understood a bit more. I don't want to bother you too much but i guess with your help and tips i could get where i want 😄 is there any way to send a private message so i don't keep posting here?
 

RSF

Well-known member
is there any way to send a private message so i don't keep posting here?
Not sure. But it's OK to post here; someone else might get some benefit from reading further posts...

how to "push" or add new data to a variable
See if that example macro helps. It adds entries to the phoneNumber_array array variable. Basically, one just assigns a value to a particular entry (arr[0] = "xyz" sets the value of array element number 0); there's no explicit "push" action unlike in e.g. Tasker or some coding languages,
 

ricca.bruno

New member
Alright, yeah yeah it definitely clarify my doubts, however this implies i can't iterate two times and still add data to an array since the index is hard to manage. Anyway i got a solution for that, i just need to make an additional selection dialog. A bit of mess with variables too but for now i got what i wanted.

So now I'm having a few issues as well as would like some clarification.

1. Coming back to the start i need to pick up a date (only day and month are needed) and using uiTask plugin i was able to achieve that. However the string variables it saves doesn't have leading zero, which is required to make an HTTP requests afterwards. What's the easiest method to add leading zero to that string, only when its needed so from 1-9?

Some clarification of what you did which would make my life easier i guess
1. I noticed you used clear variables, i could understand why for the array...since iterating with variable length arrays would may cause mess if a given index is not present but was previously saved. But i don't understand why you also used for phone_choice which i guess it "resets" every time the user makes the selection or I'm missing something here? Basically i would like to understand whenever it is necessary/useful to clear variables.

2. Why you have created an "index" variable...can't you keep using iterator_array_index on the second set variable? (maybe it just to keep it cleaner?)
 

RSF

Well-known member
What's the easiest method to add leading zero to that string, only when its needed so from 1-9?
You could prepend a zero subject to the string matching a regular expression of n digits (in the example below, if the string is five digits long, a zero is prepended; if you wanted to prepend the zero only to a single digit, change the regular expression to \d{1}, or just \d):
1701985270602.png
why you also used for phone_choice which i guess it "resets" every time the user makes the selection
If the user makes a selection, then, yes, that value resets. But if the user taps their "Back" button, the prior value is retained. By clearing its value each time the macro is run, then you could check for it being empty after the Selection Dialog action, to detect if the user tapped the Back button.

understand whenever it is necessary/useful to clear variables
In this macro, as you pointed out, when the number of iterations / array entries may vary; or to handle all user possibilities like a Cancel or Back button. From a "defensive programming" perspective, it's probably always a good idea to clear any non-persistent variable at the start of a macro (not that I always do that...).

Why you have created an "index" variable...can't you keep using iterator_array_index on the second set variable? (maybe it just to keep it cleaner?)
Good question. It'd probably be clearer, actually, to simply use the built-in iterator_array_index variable. I've run into a couple situations, in the past, where that value hasn't always worked in all actions or uses. It may have been a temporary glitch in MacroDroid since fixed, or wouldn't be an issue in this macro in any case. So, it was just me being over-cautious...
Change it to eliminate that "index" variable, and see if it works OK. Minimizing unnecessary variables is generally a good idea.

i can't iterate two times and still add data to an array since the index is hard to manage.
Yeah; in general, multi-dimensional arrays / dictionaries are currently pretty cumbersome in MacroDroid. It's not like you can just type in a complex multi-dimensional reference; you have to go through the MacroDroid UI choices and it can be a bit maddening with nested arrays or dictionaries.

If you're comfortable with JavaScript, note that MacroDroid recently added a JavaScript action, which could allow for more straightforward manipulation of complex data structures.
 

Endercraft

Moderator
I've run into a couple situations, in the past, where that value hasn't always worked in all actions or uses. It may have been a temporary glitch in MacroDroid since fixed, or wouldn't be an issue in this macro in any case. So, it was just me being over-cautious...
Change it to eliminate that "index" variable, and see if it works OK. Minimizing unnecessary variables is generally a good idea.
Same for me. It you are planning on using nested iteration loops should create 2 indexes instead of [iterator_array_index] because it might break.
 

ricca.bruno

New member
You could prepend a zero subject to the string matching a regular expression of n digits (in the example below, if the string is five digits long, a zero is prepended; if you wanted to prepend the zero only to a single digit, change the regular expression to \d{1}, or just \d):
View attachment 7825
I ended up doing a similar thing, don't know if its easier/better or not

Screenshot.png

If you're comfortable with JavaScript, note that MacroDroid recently added a JavaScript action, which could allow for more straightforward manipulation of complex data structures.
Yeah this was basically the first thing i tried, since I'm pretty familiar with JavaScript...however the thing that it only accept a string as output was a bit disappointing. Anyway since I've now figured out how to iterate correctly i added a few JavaScript snippets to adjust the end result of each iteration. Wayyy better! Thanks again for all your precious tips! I'm very happy that i was able to recreate a script that i did on iOS using Shortcuts here in Macrodroid in less than 2 weeks since i have Android.

Lastly (maybe ahah) but not least I'm doing a bit of refining, and i have a few question:
1. Whats your preferred way to display content of a macro? Either text or whatever, I've seen "floating text" and "display dialog" the last one being my preferred choice since its similar to the option or selection dialog I've used in the macro. Just wondering if there is any other option

2. In my macro i mostly have to display selection dialog but at the end it should either display a list of elements (text) or a single one. As far as i understood until now the only way to display a list made through iterate is using an array variable right? However even if i enable HTML formatting on display dialog it still shows array indexes which is something i would like to avoid. Any alternative to that? Can't create a string variable and add new lines right? I guess the only solution would be making that using Javascript code
 

RSF

Well-known member
preferred way to display content of a macro
I typically use either Notification / Popup Message (for quick "FYI" type notifications that I don't really care if I miss, e.g. "Volume set") or Notification / Display Dialog (for messages and results that I want to make sure I read). They're straightforward/quick.
Floating Text is of course a lot more customizable, appearance-wise, so it's a good option if that's needed or desired.

the only way to display a list made through iterate is using an array variable right
To display the values without indices, you could build up a string-type variable in your iteration loop, appending each value followed by a new-line to the string. Something like:
1702061477688.png

I ended up doing a similar thing, don't know if its easier/better or not
Better since you added the explicit begin/end regular expression terms, which are needed. I assumed the "equals" option (vs. the "contains" option) meant the entire variable had to match the regular expression, but that's not accurate; it's treated the same as "contains" when the "Regular expression" is selected.
 

Dm114

Well-known member
I ended up doing a similar thing, don't know if its easier/better or not

View attachment 7832
This Regex means that you prepend a 0 if {lv=sel_day} contains only 1 digit. Is it really what you mean or do you want to add a 0 when the (first) number included in the string is only 1 digit long?

If so, you could use the Regex below to modify a string such as "Friday 8/11" into "Friday 08/11"

20231208_160402.jpg
 

Dm114

Well-known member
2. In my macro i mostly have to display selection dialog but at the end it should either display a list of elements (text) or a single one. As far as i understood until now the only way to display a list made through iterate is using an array variable right? However even if i enable HTML formatting on display dialog it still shows array indexes which is something i would like to avoid. Any alternative to that? Can't create a string variable and add new lines right? I guess the only solution would be making that using Javascript code
Last MD version has improved Selection Dialog action mainly to display and select items from a dictionary. Now it works fine. Maybe it could help you.
 

ricca.bruno

New member
I typically use either Notification / Popup Message (for quick "FYI" type notifications that I don't really care if I miss, e.g. "Volume set") or Notification / Display Dialog (for messages and results that I want to make sure I read). They're straightforward/quick.
Floating Text is of course a lot more customizable, appearance-wise, so it's a good option if that's needed or desired.
I'll stick to Display Dialog for now but good to know the alternative!
To display the values without indices, you could build up a string-type variable in your iteration loop, appending each value followed by a new-line to the string. Something like:
View attachment 7833
I feel dumb here...why i haven't thought to append the result variable before the iterator value lol
thank you again man, you made my day
This Regex means that you prepend a 0 if {lv=sel_day} contains only 1 digit. Is it really what you mean or do you want to add a 0 when the (first) number included in the string is only 1 digit long?

If so, you could use the Regex below to modify a string such as "Friday 8/11" into "Friday 08/11"
Nope, that's exactly what i wanted to do, sel_day is generated by UiTask date picker and will always contain only the date as a number within 1-31 so yeah i only need to prepend the 0 if its 1 digit. But thanks for letting me know the regex to modify a full string, it might be useful in the future!
 
Top