CSV to nested dictionary

Hi everyone :partying_face:

Recently @Sagar_Thosre requested an app to create a “Book of Laws” with
section >> subsections >> articles

@securebugs suggested using Google Sheets/Airtable.
Since Google Sheets is much more widely used and can be easily accessed in CSV format via the Web component, I thought it would be useful to find a way to proceed with it.

Here’s what I managed to do.

Data on Google Sheets


This is the structure, where each element is repeated if it belongs to the same category.

Blocks

I want to preface by saying I’m sure it can be further optimized, so if anyone has a smarter/more efficient method, I’d be happy to update it and give credit.

I won’t explain every single block of the aia project because my main goal is to share the procedure.

The procedure receives two parameters:

  • csvText: the CSV text
  • stopNestingAtIndex: this is the index at which the procedure will stop nesting the columns and will create a dictionary {"columnName":"cellValue"} for each subsequent value.
    In our example it will stop at the “Text” column, which is number 4
    (the column following the last nesting)


We create 3 variables that we’ll use later:

  • nestedDictionary: which will contain our dictionary
  • listOfList: which will be our CSV formatted as a list of lists
  • headers: which will be the first row of listOfList containing the list of column names
    (Section SubSection Article Text Unique ID)

After populating the headers variable with the first row of listOfList, we remove it from listOfList so that only the data remains.

At this point, to explain how it works, instead of commenting on each part as I usually do, I think it’s more effective to give a practical example.


stopNestingAtIndex = 4
Where I marked with a red dot, we are at colNumber = 3.
For each row in list, have row = (2 2.1 Art. 10 Article text 10 Law_uid10)
For each wkNumber it will loop from 1 to 3 and will add to keypath the element in row at that index, in this case (2 2.1 Art. 10)
Then, if the key(Art. 10) is not present in the keypath butLast(2 2.1), it will create the key inside nestedDictionary with the value of tempDictionary, which in this case is empty.


stopNestingAtIndex = 4
Here we are at colNumber = 5.
For each row in list, have row = (2 2.3 Art. 17 Article text 17 Law_uid17)
For each wkNumber it will loop from 1 to 3 and will add to keypath the element in row at that index, in this case (2 2.1 Art. 10)
From 4 to 5 it will add to tempDictionary some dictionaries which in this case will be,
at cycle 4 {"Text":"Article text 17"}
at cycle 5 {"Unique ID":"Law_uid17"}.

Then, if the key(Art. 10) is not present in the keypath butLast(2 2.3 Art. 17), it will create the key inside nestedDictionary with the value of tempDictionary.

{
{"Text": "Article text 17"},
{"Unique ID": "Law_uid17"}
}

I hope these examples can make it clearer,

so by passing a CSV like this:

CSV
Section,SubSection,Article,Text,Unique ID
1,1.1,Art. 1,Article text 1,Law_uid1
1,1.1,Art. 2,Article text 2,Law_uid2
1,1.1,Art. 3,Article text 3,Law_uid3
1,1.2,Art. 4,Article text 4,Law_uid4
1,1.2,Art. 5,Article text 5,Law_uid5
1,1.2,Art. 6,Article text 6,Law_uid6
1,1.3,Art. 7,Article text 7,Law_uid7
1,1.3,Art. 8,Article text 8,Law_uid8
1,1.3,Art. 9,Article text 9,Law_uid9
2,2.1,Art. 10,Article text 10,Law_uid10
2,2.1,Art. 11,Article text 11,Law_uid11
2,2.2,Art. 12,Article text 12,Law_uid12
2,2.2,Art. 13,Article text 13,Law_uid13
2,2.2,Art. 14,Article text 14,Law_uid14
2,2.3,Art. 15,Article text 15,Law_uid15
2,2.3,Art. 16,Article text 16,Law_uid16
2,2.3,Art. 17,Article text 17,Law_uid17
3,3.1,Art. 18,Article text 18,Law_uid18
3,3.1,Art. 19,Article text 19,Law_uid19
3,3.2,Art. 20,Article text 20,Law_uid20
3,3.2,Art. 21,Article text 21,Law_uid21
3,3.2,Art. 22,Article text 22,Law_uid22
3,3.3,Art. 23,Article text 23,Law_uid23
3,3.3,Art. 24,Article text 24,Law_uid24
3,3.3,Art. 25,Article text 25,Law_uid25
4,4.1,Art. 26,Article text 26,Law_uid26
4,4.1,Art. 27,Article text 27,Law_uid27
4,4.2,Art. 28,Article text 28,Law_uid28
4,4.2,Art. 29,Article text 29,Law_uid29
4,4.2,Art. 30,Article text 30,Law_uid30
4,4.3,Art. 31,Article text 31,Law_uid31
4,4.3,Art. 32,Article text 32,Law_uid32
4,4.3,Art. 33,Article text 33,Law_uid33
5,5.1,Art. 34,Article text 34,Law_uid34
5,5.1,Art. 35,Article text 35,Law_uid35
5,5.2,Art. 36,Article text 36,Law_uid36
5,5.2,Art. 37,Article text 37,Law_uid37
5,5.2,Art. 38,Article text 38,Law_uid38
5,5.3,Art. 39,Article text 39,Law_uid39
5,5.3,Art. 40,Article text 40,Law_uid40
5,5.3,Art. 41,Article text 41,Law_uid41
6,6.1,Art. 42,Article text 42,Law_uid42
6,6.1,Art. 43,Article text 43,Law_uid43
6,6.2,Art. 44,Article text 44,Law_uid44
6,6.2,Art. 45,Article text 45,Law_uid45
6,6.2,Art. 46,Article text 46,Law_uid46
6,6.3,Art. 47,Article text 47,Law_uid47
6,6.3,Art. 48,Article text 48,Law_uid48
6,6.3,Art. 49,Article text 49,Law_uid49
7,7.1,Art. 50,Article text 50,Law_uid50

We will get a JSON like this:

JSON
{
	"1":{
		"1.1":{
			"Art. 1":{
				"Text":"Article text 1",
				"Unique ID":"Law_uid1"
			},
			"Art. 2":{
				"Text":"Article text 2",
				"Unique ID":"Law_uid2"
			},
			"Art. 3":{
				"Text":"Article text 3",
				"Unique ID":"Law_uid3"
			}
		},
		"1.2":{
			"Art. 4":{
				"Text":"Article text 4",
				"Unique ID":"Law_uid4"
			},
			"Art. 5":{
				"Text":"Article text 5",
				"Unique ID":"Law_uid5"
			},
			"Art. 6":{
				"Text":"Article text 6",
				"Unique ID":"Law_uid6"
			}
		},
		"1.3":{
			"Art. 7":{
				"Text":"Article text 7",
				"Unique ID":"Law_uid7"
			},
			"Art. 8":{
				"Text":"Article text 8",
				"Unique ID":"Law_uid8"
			},
			"Art. 9":{
				"Text":"Article text 9",
				"Unique ID":"Law_uid9"
			}
		}
	},
	"2":{
		"2.1":{
			"Art. 10":{
				"Text":"Article text 10",
				"Unique ID":"Law_uid10"
			},
			"Art. 11":{
				"Text":"Article text 11",
				"Unique ID":"Law_uid11"
			}
		},
		"2.2":{
			"Art. 12":{
				"Text":"Article text 12",
				"Unique ID":"Law_uid12"
			},
			"Art. 13":{
				"Text":"Article text 13",
				"Unique ID":"Law_uid13"
			},
			"Art. 14":{
				"Text":"Article text 14",
				"Unique ID":"Law_uid14"
			}
		},
		"2.3":{
			"Art. 15":{
				"Text":"Article text 15",
				"Unique ID":"Law_uid15"
			},
			"Art. 16":{
				"Text":"Article text 16",
				"Unique ID":"Law_uid16"
			},
			"Art. 17":{
				"Text":"Article text 17",
				"Unique ID":"Law_uid17"
			}
		}
	},
	"3":{
		"3.1":{
			"Art. 18":{
				"Text":"Article text 18",
				"Unique ID":"Law_uid18"
			},
			"Art. 19":{
				"Text":"Article text 19",
				"Unique ID":"Law_uid19"
			}
		},
		"3.2":{
			"Art. 20":{
				"Text":"Article text 20",
				"Unique ID":"Law_uid20"
			},
			"Art. 21":{
				"Text":"Article text 21",
				"Unique ID":"Law_uid21"
			},
			"Art. 22":{
				"Text":"Article text 22",
				"Unique ID":"Law_uid22"
			}
		},
		"3.3":{
			"Art. 23":{
				"Text":"Article text 23",
				"Unique ID":"Law_uid23"
			},
			"Art. 24":{
				"Text":"Article text 24",
				"Unique ID":"Law_uid24"
			},
			"Art. 25":{
				"Text":"Article text 25",
				"Unique ID":"Law_uid25"
			}
		}
	},
	"4":{
		"4.1":{
			"Art. 26":{
				"Text":"Article text 26",
				"Unique ID":"Law_uid26"
			},
			"Art. 27":{
				"Text":"Article text 27",
				"Unique ID":"Law_uid27"
			}
		},
		"4.2":{
			"Art. 28":{
				"Text":"Article text 28",
				"Unique ID":"Law_uid28"
			},
			"Art. 29":{
				"Text":"Article text 29",
				"Unique ID":"Law_uid29"
			},
			"Art. 30":{
				"Text":"Article text 30",
				"Unique ID":"Law_uid30"
			}
		},
		"4.3":{
			"Art. 31":{
				"Text":"Article text 31",
				"Unique ID":"Law_uid31"
			},
			"Art. 32":{
				"Text":"Article text 32",
				"Unique ID":"Law_uid32"
			},
			"Art. 33":{
				"Text":"Article text 33",
				"Unique ID":"Law_uid33"
			}
		}
	},
	"5":{
		"5.1":{
			"Art. 34":{
				"Text":"Article text 34",
				"Unique ID":"Law_uid34"
			},
			"Art. 35":{
				"Text":"Article text 35",
				"Unique ID":"Law_uid35"
			}
		},
		"5.2":{
			"Art. 36":{
				"Text":"Article text 36",
				"Unique ID":"Law_uid36"
			},
			"Art. 37":{
				"Text":"Article text 37",
				"Unique ID":"Law_uid37"
			},
			"Art. 38":{
				"Text":"Article text 38",
				"Unique ID":"Law_uid38"
			}
		},
		"5.3":{
			"Art. 39":{
				"Text":"Article text 39",
				"Unique ID":"Law_uid39"
			},
			"Art. 40":{
				"Text":"Article text 40",
				"Unique ID":"Law_uid40"
			},
			"Art. 41":{
				"Text":"Article text 41",
				"Unique ID":"Law_uid41"
			}
		}
	},
	"6":{
		"6.1":{
			"Art. 42":{
				"Text":"Article text 42",
				"Unique ID":"Law_uid42"
			},
			"Art. 43":{
				"Text":"Article text 43",
				"Unique ID":"Law_uid43"
			}
		},
		"6.2":{
			"Art. 44":{
				"Text":"Article text 44",
				"Unique ID":"Law_uid44"
			},
			"Art. 45":{
				"Text":"Article text 45",
				"Unique ID":"Law_uid45"
			},
			"Art. 46":{
				"Text":"Article text 46",
				"Unique ID":"Law_uid46"
			}
		},
		"6.3":{
			"Art. 47":{
				"Text":"Article text 47",
				"Unique ID":"Law_uid47"
			},
			"Art. 48":{
				"Text":"Article text 48",
				"Unique ID":"Law_uid48"
			},
			"Art. 49":{
				"Text":"Article text 49",
				"Unique ID":"Law_uid49"
			}
		}
	},
	"7":{
		"7.1":{
			"Art. 50":{
				"Text":"Article text 50",
				"Unique ID":"Law_uid50"
			}
		}
	}
}

CSV file

LawsBook - Sheet1.csv (2.0 KB)

AIA

ezgif-11182c9585d8e6d9

NestedJsonFromCSV.aia (134.1 KB)
Remember to set the spreadsheet ID.
blocks(93)

With different table


stopNestingAtIndex = 6

{
	"MasterBook1": {
		"Book1": {
			"1": {
				"1.1": {
					"Art. 1": {
						"Text": "Article text 1",
						"Unique ID": "Law_uid1",
						"Date": "1 January 1997",
						"Status": "repealed"
					}
				}
			}
		}
	}
}	

As always, I’m available for any clarification.

Happy :kodular:oding!

4 Likes

you are always introducing the best Guides in simple way
Thank you :heart_eyes:

1 Like

Thank for this

1 Like