jlrdw's avatar
Level 75

Basic Json

Recently a question came up on Json, and this is just one technique to deal with it.

The in coming Json was:

{"document_tone":{"tones":[{"score":0.706991,"tone_id":"sadness","tone_name":"Sadness"},{"score":0.955445,"tone_id":"analytical","tone_name":"Analytical"}]}}

To make it easier to work with one could remove the beginning:

{"document_tone":{"tones":

And end

}}

Knowing those are the same each time.

So then to remove them, your variable $str would already hold the Json, here I am putting it in hard coded:

       $prefix = '{"document_tone":{"tones":';
        $str = '{"document_tone":{"tones":[{"score":0.706991,"tone_id":"sadness","tone_name":"Sadness"},{"score":0.955445,"tone_id":"analytical","tone_name":"Analytical"}]}}';
        if (substr($str, 0, strlen($prefix)) == $prefix) {
            $str = substr($str, strlen($prefix));
        }

        $substring = '}}';
        if (substr($str, -strlen($substring)) === $substring) {
            $str = substr($str, 0, strlen($str) - strlen($substring));
        }

That would just leave

[{"score":0.706991,"tone_id":"sadness","tone_name":"Sadness"},{"score":0.955445,"tone_id":"analytical","tone_name":"Analytical"}]

To deal with

Then:

$json = json_decode($str, true);

A var dump looks like:

array(2) {
  [0]=>
  array(3) {
    ["score"]=>
    float(0.706991)
    ["tone_id"]=>
    string(7) "sadness"
    ["tone_name"]=>
    string(7) "Sadness"
  }
  [1]=>
  array(3) {
    ["score"]=>
    float(0.955445)
    ["tone_id"]=>
    string(10) "analytical"
    ["tone_name"]=>
    string(10) "Analytical"
  }
}

To loop over:

$keys = array_keys($json);
        for ($i = 0; $i < count($json); $i++) {
            echo $keys[$i] > 0 ? " -------------------- <br>" : '';
            foreach ($json[$keys[$i]] as $key => $value) {
                echo $key . " : " . $value . "<br>";
            }
        }

Which gives

score : 0.706991
tone_id : sadness
tone_name : Sadness
--------------------
score : 0.955445
tone_id : analytical
tone_name : Analytical

I just put in

echo $keys[$i] > 0 ? " -------------------- <br>" : '';

to have a separator.

I did all in controller here just for demo, but a real app, pass the final result to the view and loop over.

To note, as array's get more nested, it can be a trick and some trial and error to loop correctly.

If you do a search on looping a php array, nested, associative, etc, there are tons of stackoverflow questions.

If it was easy, there would not be so many questions.

Just remember some trial and error is required at times.

And if you had this in a variable called $str:

{"score":0.706991,"tone_id":"sadness","tone_name":"Sadness"},{"score":0.955445,"tone_id":"analytical","tone_name":"Analytical"}

Notice no brackets.

You could:

$str = chr(91) . $str . chr(93);

Just prior to using json_decode.

I'd welcome @cronix or @snapey or anyone to add a more complex example, as hopefully this guide will help someone.

0 likes
24 replies
Cronix's avatar

So many things to say with this. I'd never do it that way. Use json functions to properly handle json.

$str = '{"document_tone":{"tones":[{"score":0.706991,"tone_id":"sadness","tone_name":"Sadness"},{"score":0.955445,"tone_id":"analytical","tone_name":"Analytical"}]}}';

$json = json_decode($str, true);

dd($json['document_tone']['tones']);
[
     [
       "score" => 0.706991,
       "tone_id" => "sadness",
       "tone_name" => "Sadness",
     ],
     [
       "score" => 0.955445,
       "tone_id" => "analytical",
       "tone_name" => "Analytical",
     ],
]

You're manually manipulating the data string, which is not a good idea. It also uses a lot more code.

2 likes
jlrdw's avatar
Level 75

@cronix, can you show how you would loop over the above?

And how you handle json that don't have brackets to start with. A json_decode on that seems to always return a null.

That's why I did

$str = chr(91) . $str . chr(93);
1 like
click's avatar

wow, you make developing more complex than it actually is. json_decode / json_encode should do the trick in all cases if not I wonder what case it does not work.

2 likes
jlrdw's avatar
Level 75

@click on your machine, json_decode works without the brackets, mine it does not. It only works with brackets.

Try it first and show results, a blanket comment doesn't help anyone.

And yes one can json_decode, but there's a lot more than just json_decode, now isn't it.

You still have the data to work with, a simple dd does not help anyone properly loop over the data and display it.

It's a pitty, new to laravel folks see rude comments from (people that is supposed to be helpful), I shutter to think what goes through their mind.

Well thanks for the help.

1 like
Cronix's avatar
foreach ($json['document_tone']['tones'] as $array) {
    foreach ($array as $key => $value) {
        echo "$key - $value<br>";
    }
    echo "<hr>";
}
score - 0.706991
tone_id - sadness
tone_name - Sadness
--------------------------------------
score - 0.955445
tone_id - analytical
tone_name - Analytical
--------------------------------------

Or using blade so that there isn't a hr tag after the last element in the array

@foreach ($json['document_tone']['tones'] as $array) {
    @foreach ($array as $key => $value) {
        echo "$key - $value<br>";
    @endforeach
    
    @if ( ! $loop->last)
        <hr>
    @endif
@endforeach
score - 0.706991
tone_id - sadness
tone_name - Sadness
--------------------------------------
score - 0.955445
tone_id - analytical
tone_name - Analytical
1 like
jlrdw's avatar
Level 75

@cronix, thanks, now that will help. On your machine, does json_decode work without brackets, mine does not. I get null if I dd.

1 like
click's avatar
$str = '{"document_tone":{"tones":[{"score":0.706991,"tone_id":"sadness","tone_name":"Sadness"},{"score":0.955445,"tone_id":"analytical","tone_name":"Analytical"}]}}';

$object = json_decode($str);
$array = json_decode($str, true);


dd($object->document_tone->tones)


You mean like this? This works fine here. You say this does not work on your environment? What do you mean with "without brackets"? Without surround brackets like [ json ] ?

jlrdw's avatar
Level 75

If the json was only:

{"score":0.706991,"tone_id":"sadness","tone_name":"Sadness"},{"score":0.955445,"tone_id":"analytical","tone_name":"Analytical"}

Raw Json, NO brackets in a variable called $str.

If I attempt to

$array = json_decode($str, true);
dd($array);

I get null.

If I

$str = chr(91) . $str . chr(93);
$array = json_decode($str, true);
dd($array);

Then I get the data.

jlrdw's avatar
Level 75

You'd never receive a json object like that.

That is a json object, with brackets, it's a json array.

So I take it that json_decode is for a json array only.

https://www.w3schools.com/js/js_json_objects.asp

A Newton Json example

string json = @"{ 'name': 'Admin' }{ 'name': 'Publisher' }";

IList<Role> roles = new List<Role>();

JsonTextReader reader = new JsonTextReader(new StringReader(json));
reader.SupportMultipleContent = true;

while (true)
{
    if (!reader.Read())
    {
        break;
    }

    JsonSerializer serializer = new JsonSerializer();
    Role role = serializer.Deserialize<Role>(reader);

    roles.Add(role);
}

foreach (Role role in roles)
{
    Console.WriteLine(role.Name);
}

// Admin
// Publisher

I guess a stray comma.

jlrdw's avatar
Level 75

@Cronix I think you misunderstood the last part I didn't say your code didn't work I said what if they received Json object not an array, just a hypothetical. For dealing with Json.

jlrdw's avatar
Level 75

@cronix, that's all well and good, but json is also raw at times, an example from a stackoverflow question:

{"Sensor_ID":"874233","Date":"Apr 29,2016 08:49:58 Info Log1"}
{"Sensor_ID":"34234","Date":"Apr 29,2016 08:49:58 Info Log12"}
{"Sensor_ID":"56785","Date":"Apr 29,2016 08:49:58 Info Log13"}
{"Sensor_ID":"235657","Date":"Apr 29,2016 08:49:58 Info Log14"}
{"Sensor_ID":"568678","Date":"Apr 29,2016 08:49:58 Info Log15"}

If you took all that and put it in https://jsonlint.com/ yes it would fail, that is no doubt.

If however you put one line like

{"Sensor_ID":"874233","Date":"Apr 29,2016 08:49:58 Info Log1"}

of course it passed with flying colors.

That's my whole point. If someone is receiving raw json data (multiple json objects), probably a file,

You have to read each line and place the comma's and a opening and closing bracket prior to using json_decode.

[{
    "Sensor_ID": "874233",
    "Date": "Apr 29,2016 08:49:58 Info Log1"
}, {
    "Sensor_ID": "34234",
    "Date": "Apr 29,2016 08:49:58 Info Log12"
}, {
    "Sensor_ID": "56785",
    "Date": "Apr 29,2016 08:49:58 Info Log13"
}, {
    "Sensor_ID": "235657",
    "Date": "Apr 29,2016 08:49:58 Info Log14"
}, {
    "Sensor_ID": "568678",
    "Date": "Apr 29,2016 08:49:58 Info Log15"
}]

Of course passes.

And it's nice if comma's are there already.

You are probably mostly correct, most modern API's will have it ready for json_decode.

But there are older systems still in place that might not.

Of course a dump of that:

array(5) {
  [0]=>
  array(2) {
    ["Sensor_ID"]=>
    string(6) "874233"
    ["Date"]=>
    string(30) "Apr 29,2016 08:49:58 Info Log1"
  }
  [1]=>
  array(2) {
    ["Sensor_ID"]=>
    string(5) "34234"
    ["Date"]=>
    string(31) "Apr 29,2016 08:49:58 Info Log12"
  }
  [2]=>
  array(2) {
    ["Sensor_ID"]=>
    string(5) "56785"
    ["Date"]=>
    string(31) "Apr 29,2016 08:49:58 Info Log13"
  }
  [3]=>
  array(2) {
    ["Sensor_ID"]=>
    string(6) "235657"
    ["Date"]=>
    string(31) "Apr 29,2016 08:49:58 Info Log14"
  }
  [4]=>
  array(2) {
    ["Sensor_ID"]=>
    string(6) "568678"
    ["Date"]=>
    string(31) "Apr 29,2016 08:49:58 Info Log15"
  }
}

Something that can be looped.

That's all I was trying to add above, what if no brackets. Json can be sent many ways, a long text string, etc.

jlrdw's avatar
Level 75

That's what I just said above:

If someone is receiving raw json data (multiple json objects), probably a file,

You have to read each line and place the comma's and a opening and closing bracket prior to using json_decode.

But each line is valid json object on it's own.

Snapey's avatar

You have to read each line and place the comma's and a opening and closing bracket prior to using json_decode.

no, you would decode each line as a separate json object

jlrdw's avatar
Level 75

@SNAPEY - That would be another way, But you'd still need the brackets.

I noticed newtonsoft json handles it with or without brackets.

Snapey's avatar

brackets just makes it an array of objects (even if its only one object)

jlrdw's avatar
Level 75

Why would you need brackets

    public function myData()
    {
        $param = '{"Sensor_ID":"874233","Date":"Apr 29,2016 08:49:58 Info Log1"}';
        $json = json_decode($param, true);
        echo '<pre>';
        var_dump($json);
        echo '</pre>';
        
    }

Returns null

However:

    public function myData()
    {
        $param = '[{"Sensor_ID":"874233","Date":"Apr 29,2016 08:49:58 Info Log1"}]';
        $json = json_decode($param, true);
        echo '<pre>';
        var_dump($json);
        echo '</pre>';
        
    }

Returns

array(1) {
  [0]=>
  array(2) {
    ["Sensor_ID"]=>
    string(6) "874233"
    ["Date"]=>
    string(30) "Apr 29,2016 08:49:58 Info Log1"
  }
}

I am going to try your above code.

jlrdw's avatar
Level 75

@CRONIX - Okay any idea why I get null with no brackets, like shown above?

Using php 7.3.1-0

jlrdw's avatar
Level 75

@CRONIX - Okay, if I take out true

$json = json_decode($param);

I get

object(stdClass)#240 (2) {
  ["Sensor_ID"]=>
  string(6) "874233"
  ["Date"]=>
  string(30) "Apr 29,2016 08:49:58 Info Log1"
}

But not array.

jlrdw's avatar
Level 75

Your example worked gret, had to change one line:

echo $json->Sensor_ID . "<br>";

That's without brackets around the json.

jlrdw's avatar
Level 75

@CRONIX - Okay weird, what I said above is working in Chrome but not Firefox, I am going to do some searching.

NEVER MIND, some cache needed cleared, all fine.

Roni's avatar

@TALINON - Damn that made me laugh out loud at an inappropriate time!

jlrdw's avatar
Level 75

@CRONIX - As said my last reply, it worked, had to clear browser cache.

It works with

$param = '{"Sensor_ID":"874233","Date":"Apr 29,2016 08:49:58 Info Log1"}';
        $json = json_decode($param, true);
        echo '<pre>';
        var_dump($json);
        echo '</pre>';

So a single object is fine, but if dealing with more than one you have to have a json array first (brackets)

Would WORK

$param = '[{"Sensor_ID":"874233","Date":"Apr 29,2016 08:49:58 Info Log1"},{"Sensor_ID":"34234","Date":"Apr 29,2016 08:49:58 Info Log12"}]';
        $json = json_decode($param, true);
        echo '<pre>';
        var_dump($json);
        echo '</pre>';

I believe I said this in the first place, the comma and brackets makes it correct Json.

I just didn't use the term

correct Json

But thank you for multiple examples. I knew how to deal with fopen, etc already, but hopefully it can help someone who has never used it.

Was working on a code generator a while back, but decided not to use:

<?php
$in = fopen("array1.txt", "rb");
$out = fopen("list2.txt", "wb");
$nl = "";
while(!feof($in)) { 
        //$b = trim(fgets($a));
        $line = trim(fgets($in));
        //$line = preg_replace("/[\n|\r]/",'',$line);
        // $line =  fgets($fp, $length);
        // $lineLessNewLine = preg_replace('/\r?\n$/', '', $line);  
        
        
        //$line = trim(fgets($in));
        echo $line;
$nl1 = "echo".chr(32).chr(34).chr(60)."td".chr(62).chr(34). chr(32) . chr(46). chr(32).chr(36)."row"."->[";
    $nl1 = $nl1 . chr(39) . $line . chr(39) . "]";
    $nl1 = $nl1 . chr(32). chr(46). chr(32).chr(34).chr(60)."/td".chr(62).chr(34).chr(59). PHP_EOL;
    fwrite($out, $nl1);
    
    }
    
    fclose($in);
    fclose($out);

/*$in = fopen('list2.txt', 'rb');
$out = fopen('list3.txt', 'wb');

while(!feof($in)) { 
        
        $line2 = fgets($in);
        
        echo $line2 . "<br />";

    
    }

fclose($in);
    fclose($out);*/


?>

Gives:

echo "<td>" . $row->['petid'] . "</td>";
echo "<td>" . $row->['petname'] . "</td>";
echo "<td>" . $row->['ownerid'] . "</td>";
echo "<td>" . $row->['petowner'] . "</td>";
echo "<td>" . $row->['species'] . "</td>";
echo "<td>" . $row->['sex'] . "</td>";
echo "<td>" . $row->['ostreet'] . "</td>";
echo "<td>" . $row->['odate'] . "</td>";
echo "<td>" . $row->['ocheck'] . "</td>";
echo "<td>" . $row->['dogpic'] . "</td>";

It was going to be for my custom framework, but using laravel now.

I still don't understand people asking about a code generator, when they could just write one if they need one that bad.

jlrdw's avatar
Level 75

Nice to know there are some who never makes mistakes, like maybe forgetting to clear cache at times.

I usually remember but had browser open still.

I truly hope you eventually make it to the top of the laravel list.

I will continue to try to help folks, but I know I'm not perfect.

When I answered this original question I used the whole Json as the user provider.

https://laracasts.com/discuss/channels/laravel/ibm-watson-tone-analyzer-with-laravel-57

But I would imagine you can re answer that question also pluck my answer apart and give the original poster a better answer.

I had only started to experiment with different ways people can receive Json.

That question just made me more curious.

Knowing that it all doesn't come from a modern API.

I was merely trying to work out numerous techniques to get it to the Point where you can Loop over it.

I am sorry if you did not understand.

But thanks again for sharing some real good examples I just wanted a post that could help people.

instead of picking apart what I did has it dawned on anyone I could change my original wording to something better instead of being dug into so much.

But thank you so much for the criticism.

Please or to participate in this conversation.