2

I'm getting grades from a gradebook in GradPoint using their DLAP API (we have an in-house Student Info System at my school that I built). It's a bit of a nightmare because their arrays are nested many times over. Here's the output array I need to retrieve data from (replacing some values with "REMOVED" because student data):

Array
(
    [@attributes] => Array
        (
            [code] => OK
        )

    [enrollments] => Array
        (
            [enrollment] => Array
                (
                    [@attributes] => Array
                        (
                            [id] => REMOVED
                            [userid] => REMOVED
                            [entityid] => REMOVED
                            [roleid] => 0
                            [domainid] => REMOVED
                            [reference] => REMOVED
                            [guid] => REMOVED
                            [flags] => REMOVED
                            [status] => 1
                            [startdate] => 2015-07-30T06:00:00Z
                            [enddate] => 2015-12-17T06:59:00Z
                        )

                    [data] => Array
                        (
                            [status] => Array
                                (
                                    [performance] => Array
                                        (
                                            [@attributes] => Array
                                                (
                                                    [signal] => Red
                                                    [code] => 2
                                                )

                                        )

                                    [pace] => Array
                                        (
                                            [@attributes] => Array
                                                (
                                                    [signal] => Green
                                                )

                                        )

                                )

                        )

                    [user] => Array
                        (
                            [@attributes] => Array
                                (
                                    [id] => REMOVED
                                    [firstname] => REMOVED
                                    [lastname] => REMOVED
                                    [reference] => REMOVED
                                    [guid] => REMOVED
                                    [userspace] => REMOVED
                                    [username] => REMOVED
                                    [email] => REMOVED
                                    [lastlogindate] => 2015-08-07T21:43:46.11Z
                                )

                        )

                    [domain] => Array
                        (
                            [@attributes] => Array
                                (
                                    [id] => REMOVED
                                    [name] => REMOVED 
                                )

                        )

                    [grades] => Array
                        (
                            [@attributes] => Array
                                (
                                    [achieved] => 13.5
                                    [possible] => 100
                                    [letter] => F
                                    [passingscore] => 0.8
                                    [complete] => 0.5
                                    [seconds] => 8331
                                )

                            [categories] => Array
                                (
                                    [category] => Array
                                        (
                                            [0] => Array
                                                (
                                                    [@attributes] => Array
                                                        (
                                                            [id] => 15
                                                            [name] => Assignments
                                                            [achieved] => 27
                                                            [possible] => 30
                                                            [letter] => A
                                                            [seconds] => 5580
                                                        )

                                                )

                                            [1] => Array
                                                (
                                                    [@attributes] => Array
                                                        (
                                                            [id] => 138
                                                            [name] => Assessments
                                                            [achieved] => 0
                                                            [possible] => 25
                                                            [letter] => F
                                                            [seconds] => 2760
                                                        )

                                                )

                                        )

                                )

                        )

                )

        )

)

I'm trying to get the [grade] section. Specifically, the data inside @attributes that's inside of [grades]. Here's my foreach code:

foreach ($array_data as $key=>$value)
{
    if($key == "enrollments")
    {
        foreach ($value as $key1=>$value1)
        {
            if($key1 == "enrollment")
            {
                foreach ($value1 as $key2=>$value2)
                {
                    if($key2 == "grades")
                    {
                        foreach ($value2 as $key3=>$value3)
                        {
                            if($key3 == "@attributes")
                            {
                                foreach ($value3 as $key4=>$value4)
                                {
                                    switch($key4)
                                    {
                                        case "achieved":
                                            $gpAchieved = $value4;
                                        break;

                                        case "possible":
                                            $gpPossible = $value4;
                                        break;

                                        case "letter":
                                            $gpLetter = $value4;
                                        break;

                                        case "passingscore":
                                            $gpPassingScore = $value4;
                                        break;

                                        case "complete":
                                            $gpComplete = $value4;
                                        break;

                                        case "seconds":
                                            $gpSeconds = $value4;
                                        break;
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }
}

My Question: Is my giant foreach statement really the best way to retrieve this data? Is there a function that will iterate through all that and give me just what I want?

What I need to do is input those values as a line item in a MySQL table, as an fyi, that's why I saved those values in variables. This giant foreach will work, so I'm not asking for handouts. But there must be a better way!

Thanks in advanced.

6
  • 1
    maybe arrray_walk_recursive is what you need php.net/manual/en/function.array-walk-recursive.php Commented Aug 8, 2015 at 5:51
  • 1
    You foreach looks ugly,but even if you use array_walk_recurisve or use a function for array_map it will still be about the same,performance wise.You might want to try it here also codereview.stackexchange.com Commented Aug 8, 2015 at 6:01
  • 1
    This looks like simplexml cast to an array... you are probably better off working with the DomDocument api and using xpath to hone in on what you want. Try dumping a student that has more then one enrollment and you will see why this result type isn't really the best. Commented Aug 8, 2015 at 6:32
  • @Orangepill - I don't have control of how the data is output to me, beside either XML or JSON format. Wee Zel's solution may work for me because, while I don't have control of the data structure output, I can control how much of the data comes back. You're correct that if I query more than one student, the structure of the underlying XML changes. But if I limit to query one student at a time, per course, at least I can be certain of the structure. Commented Aug 8, 2015 at 6:39
  • DomDocument is for working with XML files... same as simplexml. If you are familiar with working with the Dom in javascript it's basically the same. Commented Aug 8, 2015 at 6:42

1 Answer 1

1

if your data structure is always the same you don't always need to loop through every field, just go directly to the entry you want.

if only 1 enrollment is returned you could fix your lookup to something like this:

if (isset($arr_test['enrollments']['enrollment']['grades']['@attributes'])) {
  $arr_gradesAttributes = $arr_test['enrollments']['enrollment']['grades']['@attributes'];

  $gpAchieved = $arr_gradesAttributes['achieved'];
  $gpPossible = $arr_gradesAttributes['possible'];
  $gpLetter = $arr_gradesAttributes['letter'];
  $gpPassingScore = $arr_gradesAttributes['passingscore'];
  $gpComplete = $arr_gradesAttributes['complete'];
  $gpSeconds = $arr_gradesAttributes['seconds'];
}

print("\$gpAchieved={$gpAchieved}, \$gpPossible={$gpPossible}, \$gpLetter={$gpLetter}, \$gpPassingScore={$gpPassingScore}, \$gpComplete={$gpComplete}, \$gpSeconds={$gpSeconds}");
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you. This worked for me. While it could potentially break if the resulting XML structure changes, for my scenario, where I can at least control what outputs, it will work. Additionally, I will now use this for a lot of the outputs I need to get data out of. As a general answer not so specific to my problem, so long as you know the levels and names, this solution prevents mistakes from so many foreach levels. Thanks again.
And come to think of it, even my original giant foreach statement will break if the structure changes with the output. I think at that point, a simple IF statement to check the structure result will work. So if the output structure is off, do something else. Adding this comment in case someone else finds this question useful and wonders if this answer would work on a structure change.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.