Manipulate JSON node to have [] parentheses - php

Json response from 3rd party platform which I cant control.
$json = '{
"question1": "answera",
"question2": [
"answerb",
"answerc"]
}';
Any 'question' can have multiple 'answers', however if there is only one 'answer' for that question the response comes back without the [] parentheses - this is breaking the insert into the next system (that I also dont have control over) as it is expecting the [].
Using PHP is there a way to manipulate the json string to be the following, irrelevant of the number of 'answers':
"question1": ["answera"],

You can convert string contents into an array. But you habe to iterate over all answers for this purpose.
Creating an array with an if-condition
<?php
$json = '{
"question1": "answera",
"question2": [
"answerb",
"answerc"
]
}';
// second parameter for array result
$array = json_decode($json, true);
foreach ($array as $question => $answer) {
if (is_string($answer) === true) {
$array[$question] = [ $answer ];
}
}
This one results into ...
array(2) {
'question1' =>
array(1) {
[0] =>
string(7) "answera"
}
'question2' =>
array(2) {
[0] =>
string(7) "answerb"
[1] =>
string(7) "answerc"
}
}
For any further JSON processing you can convert the PHP array back into JSON.
$json = json_encode($array);
Results into ...
string(109) "{
"question1": [
"answera"
],
"question2": [
"answerb",
"answerc"
]
}"
Casting with (array)
Another solution taken from the comments was mentioned by #RickN. Casting with (array) avoids the if condition and could possibly be faster, if that matters for your application.
foreach ($array as $question => $answer) {
$array[$question] = (array) $answer;
}

Related

Correctly format JSON file

I'm trying to create a JSON file which contains objects and an array. Yet I'm missing the [ ]-brackets. I don't really know the exact terms for these JSON parts, which makes finding a solution using Google incredibly hard. I'm also a fairly new PHP coder, so I'm still learning. Any help or tips are really appreciated!
Code to create the JSON file:
$db_export = [
'account' => [
'username' => $username,
'email' => $email
]
];
file_put_contents("output.json", json_encode($db_export, JSON_PRETTY_PRINT));
Which outputs as:
{
"account": {
"username": "test",
"email": "test#domain.com"
}
}
What it's supposed to be:
{
"account": [
{
"username": "test",
"email": "test#domain.com"
}
]
}
Adding [] characters will help. This creates an array inside the array.
$db_export = [
'account' => [[ // <--- Added
'username' => $username,
'email' => $email
]] // <--- Added
];
file_put_contents("output.json", json_encode($db_export, JSON_PRETTY_PRINT));
This is how you get the result you want.
Output :
{ "account": [ { "username": null, "email": null } ] }
I guess it was a little simple :)
I am adding this to explain what is going on with the original answer. You can find this same information in the json_encode php manual page, in the example sections.
With any simple PHP array, json_encode will transform the PHP array into a JSON array:
$simple = array('apple', 'banana', 'coconut');
echo json_encode($simple);
Returns:
["apple","banana","coconut"]
Any associative array will be turned into a json object {} and each associative key will become a property name.
$associative = array('breakfast' => 'apple', 'lunch' => 'banana', 'dinner' => 'coconut');
echo json_encode($associative);
Returns:
{"breakfast":"apple","lunch":"banana","dinner":"coconut"}
In your example, you have an array with an associative key 'account' that contains an array with 2 child elements, each with an associative key.
This is the reason json_encode() is turning your structure into json objects.
In #Smokie's answer, the addition of an extra parent array that is "simple" ie. not keyed with a name, causes json_encode (following it's simple transformation rules) to create a javascript array, which it then sticks the javascript object inside of.
$username = 'test user';
$email = 'foo#bar.com';
$db_export = [
'account' => [[ // <--- Added
'username' => $username,
'email' => $email
]] // <--- Added
];
var_dump($db_export);
Returns:
array(1) {
["account"]=>
array(1) {
[0]=>
array(2) {
["username"]=>
string(9) "test user"
["email"]=>
string(11) "foo#bar.com"
}
}
}
Here I use var_dump as a quick debugging tool to show what the PHP array looks like. The important thing to note is that 'account' is now an array(1) with one element ( the 0th element) that contains your original child array.
Presumably you need this because the assumption is that an account could have multiple accountname/email address pairs. If that isn't the case, I would question why you need to force a useless array. I personally don't see how an 'account' could have multiple username/email pairs associated with it.
With that said, this code should further illustrate how this all works, and why:
$username = 'test user';
$email = 'foo#bar.com';
$db_export = [
'account' => [[ // <--- Added
'username' => $username,
'email' => $email
]] // <--- Added
];
//Add another username/email pair to account
$db_export['account'][] = ['username' => 'test2 user', 'email' => 'test2#bar.com'];
echo json_encode($db_export, JSON_PRETTY_PRINT);
Returns:
{
"account": [
{
"username": "test user",
"email": "foo#bar.com"
},
{
"username": "test2 user",
"email": "test2#bar.com"
}
]
}

Create JSON with Square brackets instead of curly brackets

Tunnelvision:
I have a pretty basic array like this:
array(1) {
["locations"]=>
array(13) {
["identifier"]=>
string(4) "0815"
["status"]=>
string(6) "ACTIVE"
["street"]=>
string(12) "Mainstreet"
}
}
What I need is a simple output in JSON in object-form like this:
{
"locations":[
{
"identifier":0815,
"status":"ACTIVE",
"street":"Mainstreet"
}
]
}
I simply can't get it formatted correctly. I tried json_encode with the 2nd, optional parameter JSON_FORCE_OBJECT like this:
var_dump(json_encode($patchObjectArray, JSON_FORCE_OBJECT));
I tried wrapping it around another array, but also without success. I always end up with having this structure:
{
"locations":{
"identifier":"0815",
"status":"ACTIVE",
"street":"Mainstreet"
}
}
I also tried to parse it into an object with (object)$patchObjectArray, also didn't work.
Wrapped another array around it like this:
array(array("locations" => $patchObjectArray)), that just led to another "0"-index, also with curly brackets
What am i missing here?
This is the data structure that will give you the required output:
echo json_encode([
"locations" => [
[
"identifier" => "0815",
"status" => "ACTIVE",
"street" => "Mainstreet"
]
]
]);
As you can see - your "locations" must be array of arrays.
$a = ['locations' => [[
'identifier' => '0815',
'status' => 'Active',
'street' => 'Mainstreet'
]]];
echo json_encode($a);

How to decode multi-layers nested JSON String and display in PHP?

I know how to decode a JSON string and get the data from one dimensional array but how to get the data from the nested array?
Below is my code:
$data = json_decode($json);
and below is the JSON return value:
{
"area_metadata": [
{
"name": "A",
"label_location": {
"latitude": 1,
"longitude": 1
}
},
{
"name": "B",
"label_location": {
"latitude": 1,
"longitude": 1
}
}
],
"items": [
{
"update_timestamp": "2017-05-02T09:51:20+08:00",
"timestamp": "2017-05-02T09:31:00+08:00",
},
"locations": [
{
"area": "A",
"weather": "Showers"
},
{
"area": "B",
"weather": "Cloudy"
}
]
}
]}
I had tested:
echo $data->items->locations[0]->area;
but I got this error
Trying to get property of non-object
Also,I tried to convert JSON into array instead of object:
$data = json_decode($json,true);
if (isset($data))
{
foreach ($data->items->locations as $location)
{
if (empty($location["area"])) { continue; }
if ($location["area"] == "A")
{
echo $location["weather"];
}
}
}
but it also not working.
Could anyone can advise which step that I did wrongly?
Thanks!
Edited:
Below is the pastebin link with full JSON content.
https://pastebin.com/cewszSZD
The JSON you provided (in your question) is malformed and using json_decode() on it will result in NULL. Thus nothing will happen when you try to access the decoded object because it doesn't exist.
The full JSON you provided is valid and the reason why your code didn't yield any results is because in items there is an "inner"-array:
(...)
["items"] => array(1) {
[0] => array(4) {
// ^^^^^^^^^^^^^^^^^
["update_timestamp"] => string(25) "2017-05-02T09:21:18+08:00"
["timestamp"] => string(25) "2017-05-02T09:07:00+08:00"
["valid_period"] => array(2) {
["start"] => string(25) "2017-05-02T09:00:00+08:00"
["end"] => string(25) "2017-05-02T11:00:00+08:00"
}
["forecasts"] => array(47) {
[0] => array(2) {
["area"] => string(10) "Ang Mo Kio"
["forecast"] => string(19) "Partly Cloudy (Day)"
}
(...)
You'll have to access that array through key 0, for arrays it will look like this:
$data = json_decode($json, true);
echo $data['items'][0]['forecasts'][0]['area'];
// ^^^
And for objects like this:
$data = json_decode($json);
echo $data->items[0]->forecasts[0]->area;
// ^^^
The second 0 changes the location (the different arrays in the forecasts array).
You can check the output here (array approach) and here (object approach).
It would be easier to help if you post all the JSON data or link to a screenshot of it. Try:
$items[0]['locations'][0]['area'];
Single quotes on strings, no quotes on numbers.

PHP - compare the structure of two JSON objects

I have two JSON objects and I would like to compare their structure. How can I do it?
Those object are being generated on-the-fly and depending on dynamic content.
Which means that the objects are always different but most of the time have the same structure. I want to be able to catch the changes once they occur.
Example: These two objects should be considered as equal, because both have the same structure: index var and tags array.
{
"index": 0,
"tags": [
"abc"
]
}
{
"index": 1,
"tags": [
"xyz"
]
}
Thoughts?
## You can use this library TreeWalker php .##
TreeWalker is a simple and smal API in php
(I developed this library, i hope it helps you)
It offers two methods
1- Get json difference
2- Edit json value (Recursively)
this method will return the diference between json1 and json2
$struct1 = array("casa"=>1, "b"=>"5", "cafeina"=>array("ss"=>"ddd"), "oi"=>5);
$struct2 = array("casa"=>2, "cafeina"=>array("ss"=>"dddd"), "oi2"=>5);
//P.s
print_r($treeWalker->getdiff($struct1, $struct2))
{
new: {
b: "5",
oi: 5
},
removed: {
oi2: 5
},
edited: {
casa: {
oldvalue: 2,
newvalue: 1
},
cafeina/ss: {
oldvalue: "dddd",
newvalue: "ddd"
}
},
time: 0
}
It's a bit rough, but you get the picture;
$json = '[
{
"index": 0,
"tags": [
"abc"
]
},
{
"index": 1,
"tags": [
"xyz"
]
},
{
"foo": 2,
"bar": [
"xyz"
]
}]';
$array = json_decode($json, true);
$default = array_keys($array[0]);
$error = false;
$errors = array();
foreach ($array as $index => $result):
foreach ($default as $search):
if (!isset($result[$search])):
$error = true;
$errors[] = "Property '{$search}' at entry '{$index}' not found. ";
endif;
endforeach;
endforeach;
if ($error):
echo 'Objects are not the same. ';
foreach ($errors as $message):
echo $message;
endforeach;
endif;
returns:
Objects are not the same. Property 'index' at entry '2' not found. Property 'tags' at entry '2' not found.
You can try to use package https://github.com/coduo/php-matcher
Example: These two objects should be considered as equal, because both have the same structure: index var and tags array.
You can create a "php-matcher pattern" like this:
{
"index": "#integer#",
"tags": "#array#.repeat(\"#string#\")"
}
Then you match your JSONs against this pattern. If you have 2 JSONs and both match this pattern then it means that they are "equal" according to your definition of equality above.
Please see results in "php-matcher sandbox" for the example JSONs you gave:
Example 1 in sandbox
Example 2 in sandbox
Additionally you can use package https://github.com/sebastianbergmann/diff (which you should already have if you have phpunit) to generate a diff when the pattern doesnt match the value.
For example:
use SebastianBergmann\Diff\Differ;
use SebastianBergmann\Diff\Output\UnifiedDiffOutputBuilder;
...
$valueToCheck = '{
"foo": 0,
"bar": {"one": 1, "two": "2"}
}';
$expectedValuePattern = '{
"foo": "#integer#",
"bar": {"one": 1, "two": 2}
}';
if (!$matcher->match($valueToCheck, $expectedValuePattern)) {
$differ = new Differ(
new UnifiedDiffOutputBuilder(
"Json value is not matching expected format:\n",
true
)
);
$diffOutput = $differ->diff(
\json_encode(\json_decode($expectedValuePattern, true), JSON_PRETTY_PRINT),
\json_encode(\json_decode($valueToCheck, true), JSON_PRETTY_PRINT)
);
var_dump(
$diffOutput
. "\n".$matcher->getError()."\n"
);
} else {
var_dump('OK');
}
it will print:
Json value is not matching expected format:
## -1,7 +1,7 ##
{
- "foo": "#integer#",
+ "foo": 0,
"bar": {
"one": 1,
- "two": 2
+ "two": "2"
}
}
That message with diff is especially helpfull for bigger JSON's to quickly see which element is not matching.
See more ways of usage in README of that package - especially:
https://github.com/coduo/php-matcher#json-matching
https://github.com/coduo/php-matcher#json-matching-with-unbounded-arrays-and-objects
This package is very good to use in automatic tests (for example: phpunit) to assert if JSON from API responses is correct etc - considering that in integration tests there are often many id's, uuid's, datetime's etc which change on each test execution - like database generated id's etc.
I hope it helps :)
You mean by structure, like model array like:
array ( 'index' => int, 'tags' => array() )
If that's what you are trying to get, try this...
$arr1 = array (
array (
'index' => 0,
'tags' => ['abc']
),
array (
'index' => 1,
'tags' => ['xyz']
),
array (
'index' => 2,
'tags' => ['xyz'],
'boom' => 'granade'
),
array (
'index' => 3,
'tags' => 'xyz'
)
);
$holder = array();
$model = array ('index' => 0, 'tags' => array());
for ($i = 0;$i < count($arr1); $i++)
{
$holder = array_diff(array_merge_recursive($arr1[$i], $model), $model);
if (!empty($holder))
{
echo "different structure<br>";
}
else
{
echo "same structure<br>";
// for further validation
/*
$keys = array_keys($model);
if (is_int($arr1[$i][$keys[0]]) && is_array($arr1[$i][$keys[1]]))
echo "same structure<br>";
else
echo "different structure<br>";
*/
}
}
Sample output:
same structure
same structure
different structure
different structure
You can convert the json string to a php array then use the array_diff($arr1,$arr2) function to compare the newly created array with another array
the result is an array containing the elements of the first array that doesn't exist in the other array
example :
<?php
$array1 = '{"name":"myname","age":"40"}';
//convert the obtained stdclass object to an array
$array1 = (array) json_decode($array1);
$array2 = array("name"=>"myname123","age"=>10);
print_r($array2);
$result_array = array_diff($array1,$array2);
if(empty($result_array[0])){
echo "they have the same structure ";
}
?>

PHP encode JSON (2 dimensional array)

I am querying a table that return to fields(message_type & percentage).
I use PHP to encode the json data, here is how i do it
$json = array();
while ($row = odbc_fetch_array($rs)) {
$json[][] = $row;
}
echo json_encode($json);
output :
[ [ { "message_type" : "bullying",
"percentage" : "60"
} ],
[ { "message_type" : "cheating",
"percentage" : " 14"
} ],
[ { "message_type" : "Stress",
"percentage" : "16"
} ],
[ { "message_type" : "Gang",
"percentage" : "7"
} ]
]
As you can see json_encode function is adding curly braces, quotes and the object key name.
What I want is to parse the json as two dimensional array only, here is the desired output:
[
["bullying", 60],
["harrassment", 9],
["cheating", 14],
["Stress", 16],
["Gang", 7]
]
I also tried to encode it manually but I could not get the result I need.
PHP's json_encode() uses a certain amount of magic to determine whether a given vector is encoded as a JSON object or an array, but the simple rule is this: If the array has contiguous, zero-indexed, numeric keys, it will be encoded as an array. Any other vector (object or associative array) will be encoded as an object.
Because you are using odbc_fetch_array(), your result rows are returned as an associative array with the keys being the column names. To get the result you want you have 3 options:
Pass the result rows through array_values():
$json[] = array_values($row);
Manually construct the individual arrays:
$json[] = array($row['message_type'], $row['percentage']);
Or probably the best option is to use odbc_fetch_row() instead, which will return indexed arrays straight away:
while ($row = odbc_fetch_row($rs)) {
$json[] = $row;
}

Categories