-3

I am working on a small project that requests data from UK National Rail. I have this part working where the data returned is an object. How can I convert the data object in to an array and be able to access selected parts of that array.

My data object looks like:

stdClass Object
(
[GetStationBoardResult] => stdClass Object
    (
        [generatedAt] => 2018-01-22T16:08:03.2671614+00:00
        [locationName] => London Paddington
        [crs] => PAD
        [nrccMessages] => stdClass Object
            (
                [message] => stdClass Object
                    (
                        [_] => <P>Trains at Oxford may be cancelled, delayed or revised. More information can be found in <A href="http://nationalrail.co.uk/service_disruptions/182185.aspx">Latest Travel News</A></P>
                    )

            )

        [platformAvailable] => 1
        [trainServices] => stdClass Object
            (
                [service] => stdClass Object
                    (
                        [std] => 15:45
                        [etd] => Delayed
                        [operator] => Great Western Railway
                        [operatorCode] => GW
                        [serviceType] => train
                        [delayReason] => This train has been delayed by a shortage of train drivers
                        [serviceID] => U1uclHPAaZ+YyHhPMfca1A==
                        [rsid] => GW611100
                        [origin] => stdClass Object
                            (
                                [location] => stdClass Object
                                    (
                                        [locationName] => London Paddington
                                        [crs] => PAD
                                    )

                            )

                        [destination] => stdClass Object
                            (
                                [location] => stdClass Object
                                    (
                                        [locationName] => Swansea
                                        [crs] => SWA
                                    )

                            )

                    )

            )

    )

)

Var Dump.

array(1) {
    ["GetStationBoardResult"]=>
    object(stdClass)#6 (6) {
    ["generatedAt"]=>
    string(33) "2018-01-22T15:56:58.6642415+00:00"
    ["locationName"]=>
    string(17) "London Paddington"
    ["crs"]=>
    string(3) "PAD"
    ["nrccMessages"]=>
    object(stdClass)#7 (1) {
    ["message"]=>
    object(stdClass)#8 (1) {
    ["_"]=>
    string(185) "<P>Trains at Oxford may be cancelled, delayed or revised. More information can be found in <A href="http://nationalrail.co.uk/service_disruptions/182185.aspx">Latest Travel News</A></P>"
    }
    }
    ["platformAvailable"]=>
    bool(true)
    ["trainServices"]=>
    object(stdClass)#9 (1) {
    ["service"]=>
    object(stdClass)#10 (10) {
    ["std"]=>
    string(5) "15:45"
    ["etd"]=>
    string(7) "Delayed"
    ["operator"]=>
    string(21) "Great Western Railway"
    ["operatorCode"]=>
    string(2) "GW"
    ["serviceType"]=>
    string(5) "train"
    ["delayReason"]=>
    string(58) "This train has been delayed by a shortage of train drivers"
    ["serviceID"]=>
    string(24) "U1uclHPAaZ+YyHhPMfca1A=="
    ["rsid"]=>
    string(8) "GW611100"
    ["origin"]=>
    object(stdClass)#11 (1) {
    ["location"]=>
    object(stdClass)#12 (2) {
    ["locationName"]=>
    string(17) "London Paddington"
    ["crs"]=>
    string(3) "PAD"
    }
    }
    ["destination"]=>
    object(stdClass)#13 (1) {
    ["location"]=>
    object(stdClass)#14 (2) {
    ["locationName"]=>
    string(7) "Swansea"
    ["crs"]=>
    string(3) "SWA"
    }
    }
    }
    }
    }
}

Can anyone show me how this can be done. Many thanks in advance for your time.

RAW DATA with 3 records

object(stdClass)#5 (1) {
["GetStationBoardResult"]=>
object(stdClass)#6 (5) {
["generatedAt"]=>
string(33) "2018-01-23T12:35:38.6358435+00:00"
["locationName"]=>
string(17) "London Paddington"
["crs"]=>
string(3) "PAD"
["platformAvailable"]=>
bool(true)
["trainServices"]=>
object(stdClass)#7 (1) {
  ["service"]=>
  array(3) {
    [0]=>
    object(stdClass)#8 (9) {
      ["std"]=>
      string(5) "12:33"
      ["etd"]=>
      string(5) "12:35"
      ["operator"]=>
      string(16) "Heathrow Connect"
      ["operatorCode"]=>
      string(2) "HC"
      ["serviceType"]=>
      string(5) "train"
      ["serviceID"]=>
      string(24) "rnsoBNmZejPq0MYoqh4RrA=="
      ["rsid"]=>
      string(8) "HC010500"
      ["origin"]=>
      object(stdClass)#9 (1) {
        ["location"]=>
        object(stdClass)#10 (2) {
          ["locationName"]=>
          string(17) "London Paddington"
          ["crs"]=>
          string(3) "PAD"
        }
      }
      ["destination"]=>
      object(stdClass)#11 (1) {
        ["location"]=>
        object(stdClass)#12 (2) {
          ["locationName"]=>
          string(21) "Heathrow Airport T123"
          ["crs"]=>
          string(3) "HXX"
        }
      }
    }
    [1]=>
    object(stdClass)#13 (10) {
      ["std"]=>
      string(5) "12:40"
      ["etd"]=>
      string(7) "On time"
      ["platform"]=>
      string(2) "12"
      ["operator"]=>
      string(16) "Heathrow Express"
      ["operatorCode"]=>
      string(2) "HX"
      ["serviceType"]=>
      string(5) "train"
      ["serviceID"]=>
      string(24) "Ti/5lChQ5BZgVT/8gmULBA=="
      ["rsid"]=>
      string(8) "HX010000"
      ["origin"]=>
      object(stdClass)#14 (1) {
        ["location"]=>
        object(stdClass)#15 (2) {
          ["locationName"]=>
          string(17) "London Paddington"
          ["crs"]=>
          string(3) "PAD"
        }
      }
      ["destination"]=>
      object(stdClass)#16 (1) {
        ["location"]=>
        object(stdClass)#17 (2) {
          ["locationName"]=>
          string(19) "Heathrow Airport T5"
          ["crs"]=>
          string(3) "HWV"
        }
      }
    }
    [2]=>
    object(stdClass)#18 (10) {
      ["std"]=>
      string(5) "12:42"
      ["etd"]=>
      string(7) "On time"
      ["platform"]=>
      string(2) "14"
      ["operator"]=>
      string(21) "Great Western Railway"
      ["operatorCode"]=>
      string(2) "GW"
      ["serviceType"]=>
      string(5) "train"
      ["serviceID"]=>
      string(24) "H+VXbe2oimkbSMAGgS4vBQ=="
      ["rsid"]=>
      string(8) "GW756600"
      ["origin"]=>
      object(stdClass)#19 (1) {
        ["location"]=>
        object(stdClass)#20 (2) {
          ["locationName"]=>
          string(17) "London Paddington"
          ["crs"]=>
          string(3) "PAD"
        }
      }
      ["destination"]=>
      object(stdClass)#21 (1) {
        ["location"]=>
        object(stdClass)#22 (2) {
          ["locationName"]=>
          string(7) "Twyford"
          ["crs"]=>
          string(3) "TWY"
        }
      }
    }
  }
}
}
}

Hi RamRaider, I have one final question. When the "service" array has data on station calling points along the route how can I read the variables for each location.

I have tried to use the following code based on your example but for whatever reason I can't access the variables.

if( is_array( $callingAt ) ){
  /* Multiple records */

  /* an array of objects */
  foreach( $callingAt as $index => $obj ){
    $keys=array_keys( get_object_vars( $obj ) );
    //print_r ($keys);

    foreach( $keys as $key ){
      ${$key}=$obj->$key;

      //print_r (${$key});

      printf("<pre>\nStation: %s\n</pre>\n", $locationName->subsequentCallingPoints->callingPointList->callingPoint );
    }
  }
}

Code with the calling points

    stdClass Object  (
   [GetStationBoardResult] => stdClass Object (
      [generatedAt] => 2018-01-26T10:34:47.9177301+00:00
      [locationName] => London Euston
      [crs] => EUS
      [platformAvailable] => 1
      [trainServices] => stdClass Object (
         [service] => Array (
           [0] => stdClass Object (
             [std] => 10:34
             [etd] => On time
             [platform] => 11
             [operator] => West Midlands Trains
             [operatorCode] => LM
             [serviceType] => train
             [serviceID] => JsXOPFy5xbo8LmsvGLTj8Q==
             [rsid] => LM318200
             [origin] => stdClass Object  (
               [location] => stdClass Object (
                 [locationName] => London Euston
                 [crs] => EUS
               )
                 )

         [destination] => stdClass Object (
           [location] => stdClass Object (
             [locationName] => Tring
             [crs] => TRI
            )
             )

    [subsequentCallingPoints] => stdClass Object (
     [callingPointList] => stdClass Object (
       [callingPoint] => Array (
        [0] => stdClass Object (
         [locationName] => Harrow & Wealdstone
         [crs] => HRW
         [st] => 10:46
         [et] => On time
        )

      [1] => stdClass Object (
           [locationName] => Bushey
           [crs] => BSH
           [st] => 10:51
           [et] => On time
         )
  )

  [serviceType] => train
  [serviceChangeRequired] =>
  [assocIsCancelled] =>
)
)
)
DCJones
  • 3,121
  • 5
  • 31
  • 53
  • 4
    Possible duplicate of [Convert PHP object to associative array](https://stackoverflow.com/questions/4345554/convert-php-object-to-associative-array) – user2342558 Jan 22 '18 at 16:05
  • would be nice to see the original data rather than a var_dump of it – Professor Abronsius Jan 22 '18 at 16:07
  • @RamRaider Hi, I have added the original data. – DCJones Jan 22 '18 at 16:10
  • Makes it much easier to read like that imo. Have you tried simply type casting as an array? ie `$data=(array)$object;`? – Professor Abronsius Jan 22 '18 at 16:13
  • @RamRaider I have tried $data=(array)$object; but the created array has the same data in the same format so how do I access its parts? – DCJones Jan 22 '18 at 16:20
  • Hi all, Having looked at the "Possible duplicate" question I don't see any duplication. what I am asking is how to read selected parts of the Object after its converted to an array. Or without converts the object, just read selected parts of the object and echo out the result. – DCJones Jan 22 '18 at 17:35
  • Is it for ease of use that you wish to have this as a multi-dimensional array because I find it quicker to use the object notation. Sorry - been out and about otherwise I'd have replied sooner. – Professor Abronsius Jan 22 '18 at 17:42
  • @RamRaider Hi, no worries I know everyone is busy. If I could just access the individual elements of the object I can work with that. Needless to say I have not worked much with objects. – DCJones Jan 22 '18 at 17:56
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/163713/discussion-between-dcjones-and-ramraider). – DCJones Jan 23 '18 at 12:43

1 Answers1

1

To demonstrate how you can access the constituent parts of the data I re-created the object data like this. Presumably this is from a json string from the railway API which you have already decoded into an object.

$data=(object)array(
    'GetStationBoardResult'=>(object)array(
        'generatedAt'   =>  '2018-01-22T16:08:03.2671614+00:00',
        'locationName'  =>  'London Paddington',
        'crs'           =>  'PAD',
        'nrccMessages'  =>  (object)array(
            'message'   =>  (object)array(
                '_' =>  '<P>Trains at Oxford may be cancelled, delayed or revised. More information can be found in <A href="http://nationalrail.co.uk/service_disruptions/182185.aspx">Latest Travel News</A></P>'
            )
        ),
        'platformAvailable' =>  1,
        'trainServices'     =>  (object)array(
            'service'   =>  array(
                (object)array(
                    'std'           =>  '15:45',
                    'etd'           =>  'Delayed',
                    'operator'      =>  'Great Western Railway',
                    'operatorCode'  =>  'GW',
                    'serviceType'   =>  'train',
                    'delayReason'   =>  'This train has been delayed by a shortage of train drivers',
                    'serviceID'     =>  'U1uclHPAaZ+YyHhPMfca1A==',
                    'rsid'          =>  'GW611100',
                    'origin'        =>  (object)array(
                        'location'  =>  (object)array(
                            'locationName'  =>  'London Paddington',
                            'crs'           =>  'PAD'
                        )
                    ),
                    'destination'   =>  (object)array(
                        'location'  =>  (object)array(
                            'locationName'  =>  'Swansea',
                            'crs'           =>  'SWA'
                        )
                    )
                ),
                (object)array(
                    'std'           =>  '12:25',
                    'etd'           =>  'On time',
                    'operator'      =>  'Heathrow Express',
                    'operatorCode'  =>  'HX',
                    'serviceType'   =>  'train',
                    'delayReason'   =>  'This train is unusual - it is not late',
                    'serviceID'     =>  'voGWZn1GnW5o3TnqXptUXg',
                    'rsid'          =>  'HX010000',
                    'origin'        =>  (object)array(
                        'location'  =>  (object)array(
                            'locationName'  =>  'London Paddington',
                            'crs'           =>  'PAD'
                        )
                    ),
                    'destination'   =>  (object)array(
                        'location'  =>  (object)array(
                            'locationName'  =>  'Heathrow Airport T5',
                            'crs'           =>  'HWV'
                        )
                    )
                )
            )
        )
    )
);










/* Get reference to the parent node in data structure */
$results=$data->GetStationBoardResult;
/* 
    The direct child elements of the parent 
    are  easily accessible using object notation 
*/
$generatedAt=$results->generatedAt;
$locationName=$results->locationName;
$crs=$results->crs;
$message=$results->nrccMessages->message->{'_'}; /* looks like a smiley face ~ not sure that's possible on British trains! */
$platform=$results->platformAvailable;

/* The services... */
$service=$results->trainServices->service;
if( is_array( $service ) ){
    /* Multiple records */

    /* an array of objects */
    foreach( $service as $index => $obj ){
        $keys=array_keys( get_object_vars( $obj ) );

        foreach( $keys as $key ){
            ${$key}=$obj->$key;
        }

        printf("<pre>Time: %s\nOperator: %s\nServiceID: %s</pre>", $std, $operator, $serviceID );
    }


} else {
    /* Single record */

    /* if we get the keys we can loop through them */
    $keys=array_keys( get_object_vars( $service ) );

    foreach( $keys as $key ){
        /* 
            You could generate variable variables from the data at this point
            which would allow you to access them as variables such as 

            $delayReason or $std etc ( vars named the same as the keys )
        */ 
        ${$key}=$service->$key;

        /*
            or
            printf('<p>%s: %s</p>', $key, $service->$key ); etc
        */
    }
    /*
        The services have `origin` and `destination`
        so you can access these like this 
        ( assuming variable variables as above )
    */
    $origin_location=$origin->location->locationName;
    $origin_crs=$origin->location->crs;

    /* and */

    $dest_location=$destination->location->locationName;
    $dest_crs=$destination->location->crs;


    /* Or, without variable variables... */
    $dest_location=$service->destination->location->locationName;

}

For the calling-points, if I recreated the structure correctly then like this:

$subsequentCallingPoints=$results->subsequentCallingPoints;
$callingPointList=$subsequentCallingPoints->callingPointList;
$callingPoint=$callingPointList->callingPoint;

/* or */
$callingPoint=$results->subsequentCallingPoints->callingPointList->callingPoint;

foreach( $callingPoint as $obj ){
    $locationName=$obj->locationName;
    $crs=$obj->crs;

    printf('callingPoint -> $locationName=%s, $crs=%s<br />', $locationName, $crs );
}
Professor Abronsius
  • 33,063
  • 5
  • 32
  • 46
  • Many thanks for all your time. I have this working in as much my code writes one record in to my data table, If there is more than one record, using your code how can I loop through the object/array so that each record is written to the data table. Again, thanks for your time. – DCJones Jan 23 '18 at 11:40
  • if you can post the raw data above it should be easy enough to work out... – Professor Abronsius Jan 23 '18 at 12:25
  • Hi, I have added the raw data to the original question. Many thanks. – DCJones Jan 23 '18 at 12:29
  • this is the warning I get: Warning: get_object_vars() expects parameter 1 to be object, array given on line 69 which "$keys=array_keys( get_object_vars( $service ) );" – DCJones Jan 23 '18 at 12:30
  • Raw data as the original string – Professor Abronsius Jan 23 '18 at 12:32
  • The `service` is an array of objects so a simple loop should work ok – Professor Abronsius Jan 23 '18 at 12:36
  • I have added a var_dump of the raw data. – DCJones Jan 23 '18 at 12:38
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/163712/discussion-between-ramraider-and-dcjones). – Professor Abronsius Jan 23 '18 at 12:42
  • Ok. Thanks and I will see you over there. – DCJones Jan 23 '18 at 12:43
  • sorry for the delay getting back to you. Your code is perfect, I could not have done this without your help and time. Many thanks. – DCJones Jan 24 '18 at 20:37
  • No problems - happy to try to help. Good luck with the rest of your project. – Professor Abronsius Jan 24 '18 at 21:06
  • Hi and sorry to bother you again. I have one small issue, for some reason the "destination locatonName" is not getting populated. The var_dump shows shows that the data is there. If I add the "locationName" to the follwong line of code printf("
    Time: %s\nOperator: %s\nServiceID: %s\nDestination: %s
    ", $std, $operator, $serviceID, $locationName ); $locationName is null. Any ideas?
    – DCJones Jan 25 '18 at 11:24
  • `$destination->location->locationName` – Professor Abronsius Jan 25 '18 at 11:39
  • Hi again, I have one final question. I am trying to access some variables in the "subsequentCallingPoints". I have added an additional data dump to my original question showing the calling points. If you have time, could you take a look and advise me the way this is done. Again, thanks you for your time. – DCJones Jan 26 '18 at 10:27
  • a `var_dump` of the data is no use ~ raw string data that can be created into an object not the representation of that data please – Professor Abronsius Jan 26 '18 at 10:33
  • Hi, raw string added to origianl question. It is a cut down version because there are so many calling points. Again, Thanks. – DCJones Jan 26 '18 at 10:48
  • that is `parsed` data - you are not getting that response from the api surely? – Professor Abronsius Jan 26 '18 at 10:49
  • Thats what I get when I run the script. It is parsed data but I don't know how to get the raw string. I am using "OpenLDBWS.php" to get the data which does parse it. – DCJones Jan 26 '18 at 10:52
  • Hi, I get the error Invalid argument supplied for foreach()" when using $subsequentCallingPoints=$results->subsequentCallingPoints; $callingPointList=$subsequentCallingPoints->callingPointList; $callingPoint=$callingPointList->callingPoint; or $callingPoint=$results->subsequentCallingPoints->callingPointList->callingPoint;. I did try to do it this way before I asked you again for help, but with the same error. – DCJones Jan 26 '18 at 12:50
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/163945/discussion-between-ramraider-and-dcjones). – Professor Abronsius Jan 26 '18 at 13:05