Swiftwater Logo

Writing A Robust Little Parser in Swift –Part 4

This entry is part 15 of 17 in the series Swiftwater

ABSTRACT

At this point, we have defined the problem domain, have decided on a pattern, and have established a TDD framework. We have an empty function, waiting for fulfillment, and a bunch of failing tests.

Time to start to put some meat on the bones.

FIRST PASS

Run In and Grab The String

Looks pretty straightforward. All of our strings are at the “leaf” nodes of the data structures, so we should be able to just “drill down,” until we reach a single String. Let’s give that a try:

func recursiveDescentParser(_ inDictionaryToBeParsed: [AnyHashable: Any]) -> [String] {
    var ret = [String]()
    
    inDictionaryToBeParsed.forEach {
        if let asString = $0.value as? String {
            ret += [asString]
        } else if let asDictionary = $0.value as? [AnyHashable: Any] {
            ret += recursiveDescentParser(asDictionary)
        } else if let asDictionaryArray = $0.value as? [[AnyHashable: Any]] {
            asDictionaryArray.forEach { elem in
                ret += recursiveDescentParser(elem)
            }
        } else if let asArray = $0.value as? [String] {
            asArray.forEach { elem in
                ret += recursiveDescentParser(["": elem])
            }
        }
    }
    
    return ret
}

Let’s walk through what we are doing here:

In Line 1 (the function entrypoint), we have redefined the Dictionary to “[AnyHashable: String]“.

Remember that we have determined that all of our Dictionary instances will have String keys, so that means that we can make an assumption that any Dictionary object will have String keys. However, just because we can, and Swift allows us great latitude, we will use the “AnyHashable” protocol as a Dictionary key. That gives us a bit more future-proofing.

This is one of those things that Swift is nice for. Its extensive reliance on protocols allows us to “genericize” a lot of stuff.

In Line 2, we define a return Array of String. This is what the function will return in Line 20.

In Line 4, we use a higher-order function from the Sequence protocol (forEach). This loops through each entry of the Dictionary, and calls the closure immediately following the statement. This means that everything in the the braces is called repeatedly, and the $0 variable will contain the current Dictionary element (it will have a “key” and a “value” component).

Within the loop, we will test each element, and see what type it is (remember that it comes in as the type-erasing “Any” type).

We do this, using another nice Swift feature: the ability to conditionally declare variables in a conditional test. We use optional chaining to accomplish this (at the moment, the “chain” has one “link,” but it is still a “chain”).

When a variable is declared (and the declaration succeeds), then that variable is available in the condition context. If the assignment doesn’t work (either the test target is nil, or the cast fails), then the condition fails, and any “else” is checked.

The first test is in Line 5, where we see if the element value is a String. If so, we have reached the end of the path for that element, and we add the value (as a String) to our return Array, which is available to the function context. We then just go on to the next one.

Failing that, we then see if it’s an open-ended Dictionary, in Line 7. If so, we simply recursively call ourselves, passing the Dictionary in. We append the results of that recursion to our return Array. No more needs to be done for this element, and we go on to the next one.

Failing that, we next test to see if it’s an Array of Dictionaries, in Line 9. If so, we then use the forEach higher-order function on that Array, and pass each element into a recursion, appending the results to our return Array.

Lastly, in Line 13, we test to see if it’s an Array of String. That means that we’re almost there!

If it is, we use the forEach higher-order function on that Array, and create a “Dictionary” to recurse. We do that by assigning a blank String as the key.

It would certainly be more efficient to simply append the entire Array to our result collection, instead of looping and recursing, but if we recurse, that gives us more options for acting on the data in the future (as we restrict the addition to the set to one single place), and there’s a really good chance that the performance hit will be negligible.

BTW: You could also use the “reduce” higher-order function to deliver the results to a context outside the loop, but that’s more a matter of style, than anything else. forEach works fine, and is a little less verbose.

ret += asArray.reduce(into: [String]()) { (current: inout [String], next) in
    current += recursiveDescentParser(["": next])
}

Throw the Switch, Igor!

Run the playground, and see what you get:

Passes!
Passes!
Passes!
Passes!
Passes!
Passes!
Passes!
Passes!
ERROR! Bad Result!
ERROR! Bad Result!
ERROR! Bad Result!
Passes!
Passes!
ERROR! Bad Result!
ERROR! Bad Result!
Passes!
ERROR! Bad Result!

Not bad, but we still have six errors. Another fundamental tenet of high-quality engineering (not just TDD), is that even one error should SCRAM the whole reactor.

Let’s find out what those errors are, and how to deal with them in the next post.

SAMPLE PLAYGROUND

/*
    <containerElement>
        <arrayElement>Element Value 01</arrayElement>
        <arrayElement>Element Value 02</arrayElement>
        <arrayElement>Element Value 03</arrayElement>
        <arrayElement>Element Value 04</arrayElement>
        <arrayElement>Element Value 05</arrayElement>
    </containerElement>

    <!--
        {"containerElement": [  {"arrayElement": "Element Value 01"},
                                {"arrayElement": "Element Value 02"},
                                {"arrayElement": "Element Value 03"},
                                {"arrayElement": "Element Value 04"},
                                {"arrayElement": "Element Value 05"}
                                ]
        }

 
        {"containerElement": {"arrayElement": [ "Element Value 01",
                                                "Element Value 02",
                                                "Element Value 03",
                                                "Element Value 04",
                                                "Element Value 05"
                                                ]
                            }
        }

        {"containerElement": [  {"arrayElement": {"value": "Element Value 01"}},
                                {"arrayElement": {"value": "Element Value 02"}},
                                {"arrayElement": {"value": "Element Value 03"}},
                                {"arrayElement": {"value": "Element Value 04"}},
                                {"arrayElement": {"value": "Element Value 05"}}
                                ]
        }
    -->

    <containerElement>
        <arrayElement>
            <value>Element Value 01</value>
            <value>Element Value 02</value>
            <value>Element Value 03</value>
            <value>Element Value 04</value>
            <value>Element Value 05</value>
        </arrayElement>
    </containerElement>

    <!--
        {"containerElement": {"arrayElement": [ {"value": "Element Value 01"},
                                                {"value": "Element Value 02"},
                                                {"value": "Element Value 03"},
                                                {"value": "Element Value 04"},
                                                {"value": "Element Value 05"}
                                                ]
                            }
        }
 
        {"containerElement": {"arrayElement": [ "Element Value 01",
                                                "Element Value 02",
                                                "Element Value 03",
                                                "Element Value 04",
                                                "Element Value 05"
                                                ]
                            }
        }
    -->

    <containerElement>
        <arrayElement value="Element Value 01"/>
        <arrayElement value="Element Value 02"/>
        <arrayElement value="Element Value 03"/>
        <arrayElement value="Element Value 04"/>
        <arrayElement value="Element Value 05"/>
    </containerElement>

    <!--
        {"containerElement": [  {"arrayElement": {"attributes": [{"value": "Element Value 01"}]}},
                                {"arrayElement": {"attributes": [{"value": "Element Value 02"}]}},
                                {"arrayElement": {"attributes": [{"value": "Element Value 03"}]}},
                                {"arrayElement": {"attributes": [{"value": "Element Value 04"}]}},
                                {"arrayElement": {"attributes": [{"value": "Element Value 05"}]}}
                                ]
        }

        {"containerElement": [  {"arrayElement": {"attributes": {"value": "Element Value 01"}}},
                                {"arrayElement": {"attributes": {"value": "Element Value 02"}}},
                                {"arrayElement": {"attributes": {"value": "Element Value 03"}}},
                                {"arrayElement": {"attributes": {"value": "Element Value 04"}}},
                                {"arrayElement": {"attributes": {"value": "Element Value 05"}}}
                                ]
        }
    -->

    <containerElement>
        <arrayElement index="0">Element Value 01</arrayElement>
        <arrayElement index="1">Element Value 02</arrayElement>
        <arrayElement index="2">Element Value 03</arrayElement>
        <arrayElement index="3">Element Value 04</arrayElement>
        <arrayElement index="4">Element Value 05</arrayElement>
    </containerElement>

    <!--
        {"containerElement": [  {"arrayElement": [{"attributes": [{"index": 0}]}, {"value": "Element Value 01"}]},
                                {"arrayElement": [{"attributes": [{"index": 1}]}, {"value": "Element Value 02"}]},
                                {"arrayElement": [{"attributes": [{"index": 2}]}, {"value": "Element Value 03"}]},
                                {"arrayElement": [{"attributes": [{"index": 3}]}, {"value": "Element Value 04"}]},
                                {"arrayElement": [{"attributes": [{"index": 4}]}, {"value": "Element Value 05"}]}
                                ]
        }

        {"containerElement": [  {"arrayElement": [{"attributes": [{"index": "0"}]}, {"value": "Element Value 01"}]},
                                {"arrayElement": [{"attributes": [{"index": "1"}]}, {"value": "Element Value 02"}]},
                                {"arrayElement": [{"attributes": [{"index": "2"}]}, {"value": "Element Value 03"}]},
                                {"arrayElement": [{"attributes": [{"index": "3"}]}, {"value": "Element Value 04"}]},
                                {"arrayElement": [{"attributes": [{"index": "4"}]}, {"value": "Element Value 05"}]}
                                ]
        }

        {"containerElement": [  {"arrayElement": [{"attributes": {"index": "0"}}, {"value": "Element Value 01"}]},
                                {"arrayElement": [{"attributes": {"index": "1"}}, {"value": "Element Value 02"}]},
                                {"arrayElement": [{"attributes": {"index": "2"}}, {"value": "Element Value 03"}]},
                                {"arrayElement": [{"attributes": {"index": "3"}}, {"value": "Element Value 04"}]},
                                {"arrayElement": [{"attributes": {"index": "4"}}, {"value": "Element Value 05"}]}
                                ]
        }

        {"containerElement": [  {"arrayElement": [{"attributes": [{"index": "0"}, {"value": "Element Value 01"}]}]},
                                {"arrayElement": [{"attributes": [{"index": "1"}, {"value": "Element Value 02"}]}]},
                                {"arrayElement": [{"attributes": [{"index": "2"}, {"value": "Element Value 03"}]}]},
                                {"arrayElement": [{"attributes": [{"index": "3"}, {"value": "Element Value 04"}]}]},
                                {"arrayElement": [{"attributes": [{"index": "4"}, {"value": "Element Value 05"}]}]}
                                ]
        }
    -->

    <containerElement>
        <arrayElement row="0" value="Element Value 01"/>
        <arrayElement row="1" value="Element Value 02"/>
        <arrayElement row="2" value="Element Value 03"/>
        <arrayElement row="3" value="Element Value 04"/>
        <arrayElement row="4" value="Element Value 05"/>
    </containerElement>

    <!--
        {"containerElement": [  {"arrayElement": {"attributes": [{"row": 0}, {"value": "Element Value 01"}]}},
                                {"arrayElement": {"attributes": [{"row": 1}, {"value": "Element Value 02"}]}},
                                {"arrayElement": {"attributes": [{"row": 2}, {"value": "Element Value 03"}]}},
                                {"arrayElement": {"attributes": [{"row": 3}, {"value": "Element Value 04"}]}},
                                {"arrayElement": {"attributes": [{"row": 4}, {"value": "Element Value 05"}]}}
                                ]
        }

        {"containerElement": [  {"arrayElement": [{"attributes": [{"row": 0}, {"value": "Element Value 01"}]}]},
                                {"arrayElement": [{"attributes": [{"row": 1}, {"value": "Element Value 02"}]}]},
                                {"arrayElement": [{"attributes": [{"row": 2}, {"value": "Element Value 03"}]}]},
                                {"arrayElement": [{"attributes": [{"row": 3}, {"value": "Element Value 04"}]}]},
                                {"arrayElement": [{"attributes": [{"row": 4}, {"value": "Element Value 05"}]}]}
                                ]
        }

        {"containerElement": [  {"arrayElement": {"attributes": [{"row": "0"}, {"value": "Element Value 01"}]}},
                                {"arrayElement": {"attributes": [{"row": "1"}, {"value": "Element Value 02"}]}},
                                {"arrayElement": {"attributes": [{"row": "2"}, {"value": "Element Value 03"}]}},
                                {"arrayElement": {"attributes": [{"row": "3"}, {"value": "Element Value 04"}]}},
                                {"arrayElement": {"attributes": [{"row": "4"}, {"value": "Element Value 05"}]}}
                                ]
        }

        {"containerElement": [  {"arrayElement": [{"attributes": [{"row": "0"}, {"value": "Element Value 01"}]}]},
                                {"arrayElement": [{"attributes": [{"row": "1"}, {"value": "Element Value 02"}]}]},
                                {"arrayElement": [{"attributes": [{"row": "2"}, {"value": "Element Value 03"}]}]},
                                {"arrayElement": [{"attributes": [{"row": "3"}, {"value": "Element Value 04"}]}]},
                                {"arrayElement": [{"attributes": [{"row": "4"}, {"value": "Element Value 05"}]}]}
                                ]
        }
    -->
 */

import Foundation

func convertJSONToDictionary(_ inJSON: String) -> [String: Any] {
    do {
        if let stringData = inJSON.data(using: .utf8), let jsonDict = try JSONSerialization.jsonObject(with: stringData) as? [String: Any] {
            return jsonDict
        }
    } catch(let error) {
        print(String(describing: error))
    }
    return [:]
}

var jsonInterpretations: [[String: Any]] = []

var jsonInterpretationsSecondaryTests: [[String: Any]] = []

func loadJSONIntoDictionaries() {
    // Initial test set
    jsonInterpretations.append(convertJSONToDictionary("{\"containerElement\": [{\"arrayElement\": \"Element Value 01\"}, {\"arrayElement\": \"Element Value 02\"}, {\"arrayElement\": \"Element Value 03\"}, {\"arrayElement\": \"Element Value 04\"}, {\"arrayElement\": \"Element Value 05\"}]}"))
    jsonInterpretations.append(convertJSONToDictionary("{\"containerElement\": {\"arrayElement\": [\"Element Value 01\", \"Element Value 02\", \"Element Value 03\", \"Element Value 04\", \"Element Value 05\"]}}"))
    jsonInterpretations.append(convertJSONToDictionary("{\"containerElement\": [{\"arrayElement\": {\"value\": \"Element Value 01\"}}, {\"arrayElement\": {\"value\": \"Element Value 02\"}}, {\"arrayElement\": {\"value\": \"Element Value 03\"}}, {\"arrayElement\": {\"value\": \"Element Value 04\"}}, {\"arrayElement\": {\"value\": \"Element Value 05\"}}]}"))
    jsonInterpretations.append(convertJSONToDictionary("{\"containerElement\": {\"arrayElement\": [{\"value\": \"Element Value 01\"}, {\"value\": \"Element Value 02\"}, {\"value\": \"Element Value 03\"}, {\"value\": \"Element Value 04\"}, {\"value\": \"Element Value 05\"}]}}"))
    jsonInterpretations.append(convertJSONToDictionary("{\"containerElement\": {\"arrayElement\": [\"Element Value 01\", \"Element Value 02\", \"Element Value 03\", \"Element Value 04\", \"Element Value 05\"]}}"))
    jsonInterpretations.append(convertJSONToDictionary("{\"containerElement\": [{\"arrayElement\": {\"attributes\": [{\"value\": \"Element Value 01\"}]}}, {\"arrayElement\": {\"attributes\": [{\"value\": \"Element Value 02\"}]}}, {\"arrayElement\": {\"attributes\": [{\"value\": \"Element Value 03\"}]}}, {\"arrayElement\": {\"attributes\": [{\"value\": \"Element Value 04\"}]}}, {\"arrayElement\": {\"attributes\": [{\"value\": \"Element Value 05\"}]}}]}"))
    jsonInterpretations.append(convertJSONToDictionary("{\"containerElement\": [{\"arrayElement\": {\"attributes\": {\"value\": \"Element Value 01\"}}}, {\"arrayElement\": {\"attributes\": {\"value\": \"Element Value 02\"}}}, {\"arrayElement\": {\"attributes\": {\"value\": \"Element Value 03\"}}}, {\"arrayElement\": {\"attributes\": {\"value\": \"Element Value 04\"}}}, {\"arrayElement\": {\"attributes\": {\"value\": \"Element Value 05\"}}}]}"))
    jsonInterpretations.append(convertJSONToDictionary("{\"containerElement\": [{\"arrayElement\": [{\"attributes\": [{\"index\": 0}]}, {\"value\": \"Element Value 01\"}]}, {\"arrayElement\": [{\"attributes\": [{\"index\": 1}]}, {\"value\": \"Element Value 02\"}]}, {\"arrayElement\": [{\"attributes\": [{\"index\": 2}]}, {\"value\": \"Element Value 03\"}]}, {\"arrayElement\": [{\"attributes\": [{\"index\": 3}]}, {\"value\": \"Element Value 04\"}]}, {\"arrayElement\": [{\"attributes\": [{\"index\": 4}]}, {\"value\": \"Element Value 05\"}]}]}"))
    jsonInterpretations.append(convertJSONToDictionary("{\"containerElement\": [{\"arrayElement\": [{\"attributes\": [{\"index\": \"0\"}]}, {\"value\": \"Element Value 01\"}]}, {\"arrayElement\": [{\"attributes\": [{\"index\": \"1\"}]}, {\"value\": \"Element Value 02\"}]}, {\"arrayElement\": [{\"attributes\": [{\"index\": \"2\"}]}, {\"value\": \"Element Value 03\"}]}, {\"arrayElement\": [{\"attributes\": [{\"index\": \"3\"}]}, {\"value\": \"Element Value 04\"}]}, {\"arrayElement\": [{\"attributes\": [{\"index\": \"4\"}]}, {\"value\": \"Element Value 05\"}]}]}"))
    jsonInterpretations.append(convertJSONToDictionary("{\"containerElement\": [{\"arrayElement\": [{\"attributes\": {\"index\": \"0\"}}, {\"value\": \"Element Value 01\"}]}, {\"arrayElement\": [{\"attributes\": {\"index\": \"1\"}}, {\"value\": \"Element Value 02\"}]}, {\"arrayElement\": [{\"attributes\": {\"index\": \"2\"}}, {\"value\": \"Element Value 03\"}]}, {\"arrayElement\": [{\"attributes\": {\"index\": \"3\"}}, {\"value\": \"Element Value 04\"}]}, {\"arrayElement\": [{\"attributes\": {\"index\": \"4\"}}, {\"value\": \"Element Value 05\"}]}]}"))
    jsonInterpretations.append(convertJSONToDictionary("{\"containerElement\": [{\"arrayElement\": [{\"attributes\": [{\"index\": \"0\"}, {\"value\": \"Element Value 01\"}]}]}, {\"arrayElement\": [{\"attributes\": [{\"index\": \"1\"}, {\"value\": \"Element Value 02\"}]}]}, {\"arrayElement\": [{\"attributes\": [{\"index\": \"2\"}, {\"value\": \"Element Value 03\"}]}]}, {\"arrayElement\": [{\"attributes\": [{\"index\": \"3\"}, {\"value\": \"Element Value 04\"}]}]}, {\"arrayElement\": [{\"attributes\": [{\"index\": \"4\"}, {\"value\": \"Element Value 05\"}]}]}]}"))
    jsonInterpretations.append(convertJSONToDictionary("{\"containerElement\": [{\"arrayElement\": {\"attributes\": [{\"row\": 0}, {\"value\": \"Element Value 01\"}]}}, {\"arrayElement\": {\"attributes\": [{\"row\": 1}, {\"value\": \"Element Value 02\"}]}}, {\"arrayElement\": {\"attributes\": [{\"row\": 2}, {\"value\": \"Element Value 03\"}]}}, {\"arrayElement\": {\"attributes\": [{\"row\": 3}, {\"value\": \"Element Value 04\"}]}}, {\"arrayElement\": {\"attributes\": [{\"row\": 4}, {\"value\": \"Element Value 05\"}]}}]}"))
    jsonInterpretations.append(convertJSONToDictionary("{\"containerElement\": [{\"arrayElement\": [{\"attributes\": [{\"row\": 0}, {\"value\": \"Element Value 01\"}]}]}, {\"arrayElement\": [{\"attributes\": [{\"row\": 1}, {\"value\": \"Element Value 02\"}]}]}, {\"arrayElement\": [{\"attributes\": [{\"row\": 2}, {\"value\": \"Element Value 03\"}]}]}, {\"arrayElement\": [{\"attributes\": [{\"row\": 3}, {\"value\": \"Element Value 04\"}]}]}, {\"arrayElement\": [{\"attributes\": [{\"row\": 4}, {\"value\": \"Element Value 05\"}]}]}]}"))
    jsonInterpretations.append(convertJSONToDictionary("{\"containerElement\": [{\"arrayElement\": {\"attributes\": [{\"row\": \"0\"}, {\"value\": \"Element Value 01\"}]}}, {\"arrayElement\": {\"attributes\": [{\"row\": \"1\"}, {\"value\": \"Element Value 02\"}]}}, {\"arrayElement\": {\"attributes\": [{\"row\": \"2\"}, {\"value\": \"Element Value 03\"}]}}, {\"arrayElement\": {\"attributes\": [{\"row\": \"3\"}, {\"value\": \"Element Value 04\"}]}}, {\"arrayElement\": {\"attributes\": [{\"row\": \"4\"}, {\"value\": \"Element Value 05\"}]}}]}"))
    jsonInterpretations.append(convertJSONToDictionary("{\"containerElement\": [{\"arrayElement\": [{\"attributes\": [{\"row\": \"0\"}, {\"value\": \"Element Value 01\"}]}]}, {\"arrayElement\": [{\"attributes\": [{\"row\": \"1\"}, {\"value\": \"Element Value 02\"}]}]}, {\"arrayElement\": [{\"attributes\": [{\"row\": \"2\"}, {\"value\": \"Element Value 03\"}]}]}, {\"arrayElement\": [{\"attributes\": [{\"row\": \"3\"}, {\"value\": \"Element Value 04\"}]}]}, {\"arrayElement\": [{\"attributes\": [{\"row\": \"4\"}, {\"value\": \"Element Value 05\"}]}]}]}"))
    
    // Extra Credit
    jsonInterpretations.append(convertJSONToDictionary("{\"arrayElement\": [{\"value\": \"Element Value 01\"}, {\"value\": \"Element Value 02\"}, {\"value\": \"Element Value 03\"}, {\"value\": \"Element Value 04\"}, {\"value\": \"Element Value 05\"}]}"))
    jsonInterpretations.append(convertJSONToDictionary("{\"containerElement\": [{\"arrayElement\": {\"attributes\": [{\"row\": 3}, {\"value\": \"Element Value 04\"}]}}, {\"arrayElement\": {\"attributes\": [{\"row\": 2}, {\"value\": \"Element Value 03\"}]}}, {\"arrayElement\": {\"attributes\": [{\"row\": 1}, {\"value\": \"Element Value 02\"}]}}, {\"arrayElement\": {\"attributes\": [{\"row\": 4}, {\"value\": \"Element Value 05\"}]}}, {\"arrayElement\": {\"attributes\": [{\"row\": 0}, {\"value\": \"Element Value 01\"}]}}]}"))
    
    // Differing Data
    jsonInterpretationsSecondaryTests.append(convertJSONToDictionary("{\"containerElement\": [{\"arrayElement\": {\"attributes\": [{\"row\": 3}, {\"value\": 3}]}}, {\"arrayElement\": {\"attributes\": [{\"row\": 2}, {\"value\": \"3.14\"}]}}, {\"arrayElement\": {\"attributes\": [{\"index\": 1}, {\"value\": \"0123456789!@~*&^%$#.,;:?/'\"}]}}, {\"arrayElement\": {\"attributes\": [{\"row\": 4}, {\"value\": 1234567890}]}}, {\"arrayElement\": {\"attributes\": [{\"index\": 0}, {\"value\": \"12345.6789\"}]}}]}"))
    jsonInterpretationsSecondaryTests.append(convertJSONToDictionary("{\"containerElement\": [{\"arrayElement\": \"3\"}, {\"arrayElement\": \"3.14\"}, {\"arrayElement\": \"0123456789!@~*&^%$#.,;:?/'\"}, {\"arrayElement\": \"1234567890\"}, {\"arrayElement\": \"12345.6789\"}]}"))
    jsonInterpretationsSecondaryTests.append(convertJSONToDictionary("{\"containerElement\": [{\"arrayElement\": 3}, {\"arrayElement\": 3.14}, {\"arrayElement\": \"0123456789!@~*&^%$#.,;:?/'\"}, {\"arrayElement\": 1234567890}, {\"arrayElement\": 12345.6789}]}"))
}

loadJSONIntoDictionaries()

let whatWeWantToSee: [String] = ["Element Value 01", "Element Value 02", "Element Value 03", "Element Value 04", "Element Value 05"]
let whatWeWantToSee2: [String] = ["0123456789!@~*&^%$#.,;:?/'", "12345.6789", "1234567890", "3", "3.14"]

func recursiveDescentParser(_ inDictionaryToBeParsed: [AnyHashable: Any]) -> [String] {
    var ret = [String]()
    
    inDictionaryToBeParsed.forEach {
        if let asString = $0.value as? String {
            ret += [asString]
        } else if let asDictionary = $0.value as? [AnyHashable: Any] {
            ret += recursiveDescentParser(asDictionary)
        } else if let asDictionaryArray = $0.value as? [[AnyHashable: Any]] {
            asDictionaryArray.forEach { elem in
                ret += recursiveDescentParser(elem)
            }
        } else if let asArray = $0.value as? [String] {
            asArray.forEach { elem in
                ret += recursiveDescentParser(["": elem])
            }
        }
    }
    
    return ret
}

// Test Set 1
jsonInterpretations.forEach {
    let parsedResult = recursiveDescentParser($0)
    if whatWeWantToSee != parsedResult {
//        print("ERROR! Bad Result for \($0)")
        print("ERROR! Bad Result!")
    } else {
//        print("\($0) Passes!")
        print("Passes!")
    }
}

// Test Set 2
//jsonInterpretationsSecondaryTests.forEach {
//    let parsedResult = recursiveDescentParser($0)
//    if whatWeWantToSee2 != parsedResult {
//        print("ERROR! Bad Result for \($0)")
//    } else {
//        print("\($0) Passes!")
//    }
//}