I have a number of JSON files and when there is a single object in them, their datatype is inconsistent. I am trying to alter the files that contain one item so that the element I am referencing is always an array.
Here's an example of a 'good' JSON file:
{
"apiv2": {
"items": [{
"id": "00001",
"name": "ITEM 1"
}, {
"id": "00002",
"name": "ITEM 2"
}]
}
}
In PHP terms, $json->apiv2->items is always an array I can apply the same functions to.
Every so often I have a JSON file that contains one item:
{
"apiv2": {
"items": {
"id": "00003",
"name": "ITEM 3"
}
}
}
When I attempt to iterate through 'items' with the same functions, they fail as it is now an object instead of an array.
My goal is to alter the JSON data and rewrite the file so the single item files are consistent with the multiple item files:
{
"apiv2": {
"items": [{
"id": "00003",
"name": "ITEM 3"
}]
}
}
Maybe it's because it's Friday afternoon, but I can't seem to wrap my head around this one. I thought it would be as simple as:
$json->apiv2->items = (array) $json->apiv2->items;
But that just turns it into an array with two elements, "id" and "name", not one element with the object.
As I said in the comments
When you do
$json->apiv2->items = (array) $json->apiv2->items;
PHP will convert $items to an actual array [ "id" => "00003", "name" => "ITEM 3"]
Which will give you the results ['items' => [ "id" => "00003", "name" => "ITEM 3"]]
Instead of converting your object, you need to wrap it
$json->apiv2->items = [$json->apiv2->items];
More advanced: since sometimes items can be an array and sometimes not, you can make a function [1] to wrap them
function wrap($value)
{
if (is_null($value)) {
return [];
}
return is_array($value) ? $value : [$value];
}
$json->apiv2->items = wrap($json->apiv2->items);
POC : https://3v4l.org/7p9b0
[1] Stolen from Laravel helpers
Use json_decode() and access it like this:
$json = '{"apiv2":{"items": [{"id": "00001", "name": "ITEM 1" }, {"id": "00002", "name": "ITEM 2" }]}}';
print_r(json_decode($json, true)['apiv2']['items']);
Related
I'm working on WordPress site and been asked to supply mobile developer by JSON API data for a slider. I have to add the slider data like images and titles etc. I've found a plugin which serve an end point called MetaSlider. I've did required things and the response was perfect. but the developer replied by this:
"I am not talking about data. It should be a valid JSON array. Plz have a look at data structure of response object
"0": {
"id": 2669,
"title": "New Slideshow",
This is not valid json. It should be a JSON Array like this
[ {
"id": 2669,
"title": "New Slideshow","
Does any one have a clue?
I looked for a plugin that can do the job but I didn't find any.
I was experiencing the same issue.
If your array is as result of using array_map, wrap your response with array_values($data).
This is the function I have as a callback for register_rest_route;
public function terms_ep( $request ) {
$terms = get_terms('my_taxonomy', []);
$data = array_map(function($t){
return [
'id' => $t->term_id,
'name' => $t->name
];
}, $terms);
return rest_ensure_response( array_values($data) );
}
With array_values it produces a nice json array:
[
{
"id": 13,
"name": "A"
},
{
"id": 12,
"name": "B"
}
]
Without the response is this object response:
{
"0": {
"id": 13,
"name": "A"
},
"2": {
"id": 12,
"name": "B"
}
}
I am trying to adhere to an integration requirement of having multiple items with the same key names, including its meta data into a main array to properly json_encode.
I have tried splitting out and joining arrays, array_push. The only workable solution I have is to manually build this part of the json package. Any help would be greatly appreciated.
Here is a sample of what I am struggling with:
$message_pack["Header"]["Sequence"] = 'TEST1';
$message_pack["Header"]["TC"] = "1";
$message_pack["ItemDetail"]["ItemName"] = "Item1";
$message_pack["ItemDetail"]["ItemCode"] = "123";
$message_pack["ItemDetail"]["Itemname"] = "Item2";
$message_pack["ItemDetail"]["ItemCode"] = "234";
$json_msg = json_encode($message_pack);
This will obviously only take the last value passed to the matching key name.
I need to adhere to this json format:
{
"Header": {
"Sequence": "TEST1",
"TC": "1",
},
"ItemDetail": [{
"ItemName": "Item1",
"ItemCode": "123" }
{ "ItemName": "Item2",
"ItemCode": "234" }]
}
You need to make "ItemDetail" an array, else you'll overwrite $message_pack["ItemDetail"]["Itemname"] and $message_pack["ItemDetail"]["ItemCode"]:
<?php
$message_pack["Header"]["Sequence"] = 'TEST1';
$message_pack["Header"]["TC"] = "1";
$message_pack["ItemDetail"][] = ["ItemName" => "Item1", 'ItemCode' => 123];
$message_pack["ItemDetail"][] = ["ItemName" => "Item2", 'ItemCode' => 234];
$json_msg = json_encode($message_pack, JSON_PRETTY_PRINT);
echo ($json_msg);
will output:
{
"Header": {
"Sequence": "TEST1",
"TC": "1"
},
"ItemDetail": [
{
"ItemName": "Item1",
"ItemCode": 123
},
{
"ItemName": "Item2",
"ItemCode": 234
}
]
}
I have a Laravel controller that returns a collection of items (in this case Answers):
return AnswerResource::collection($correctAns);
This returns a JSON object as expected of course. How would I go about appending an item to that object so it's more like this?
{
"data": [
{
"id": "2",
"answer_text": "True"
},
{
"id": "3",
"answer_text": "False"
}
],
"testKey": "arsnteio12345"
}
(where the testKey thing is what's added)
Try something like this
return Response::json(['data '=> $correctAns, 'testKey' => 'arsnteio12345'],200);
I am trying to create a custom controller for the WordPress JSON API plugin and so far everything is working except the JSON Data I have is not in the correct format.
This is my current JSON output:
{
"status": "ok",
"all_tags": {
"tag-1": {
"term_name": "Tag 1",
"category_details": {
"0": {
"category_ID": 8,
"category_name": "category 1",
"category_count": 2
},
"2": {
"category_ID": 13,
"category_name": "category 2",
"category_count": 1
}
}
},
"tag-2": {
"term_name": "Tag 2",
"category_details": [
{
"category_ID": 8,
"category_name": "category 1",
"category_count": 2
}
]
}
}
}
However, in order to parse the data I must have the json data in a specific format. The correct format should be like this:
{
"status": "ok",
"all_tags": [
{
"id": 1,
"term_name": "Tag 1",
"category_details": [
{
"id": 2,
"category_ID": 8,
"category_name": "category 1",
"category_count": 2
},
{
"id": 3,
"category_ID": 13,
"category_name": "category 2",
"category_count": 1
}
]
},
{
"id": 2,
"term_name": "Tag 2",
"category_details": [
{
"id": 2,
"category_ID": 8,
"category_name": "category 1",
"category_count": 2
}
]
}
]
}
This is how I am creating the array for the json:
<?php
...
$cats_all = array(); // the array
if (!isset($cats_all[$custom_term->slug])) {
// create the array
$cats_all[$custom_term->slug] = array(
'term_name' => $custom_term->name,
'category_details' => array(
array(
'category_ID' => $categories[0]->term_id,
'category_name' => $categories[0]->name,
'category_count' => $mycats[0]->category_count
)
)
);
} else {
$cats_all[$custom_term->slug]['category_details'][] = array(
'category_ID' => $categories[0]->term_id,
'category_name' => $categories[0]->name,
'category_count' => $mycats[0]->category_count
);
}
...
// remove duplicates
$input = $this->super_unique( $cats_all );
// return the array for json output by the plugin
return array(
'all_tags' => $input,
);
Any help will be greatly appreciated. Also the entire controller can be viewed here.
There are two things you need to achieve:
The all_tags value must be a sequential array, not an associative one. This you can achieve by taking the array_values at the last statement:
return array(
'all_tags' => array_values($input)
);
The category_details values must be sequential arrays, not associative ones. This one is more tricky, as you actually do create them as sequential arrays, but the function super_unique will sometimes turn them into associative arrays, when it eliminates at least one duplicate. I suggest this fix to the function super_unique by adding two statements, around this one:
$result = array_map( 'unserialize', array_unique( array_map( 'serialize', $array ) ) );
To get this:
$is_seq = end(array_keys($array)) == count($array)-1;
$result = array_map( 'unserialize', array_unique( array_map( 'serialize', $array ) ) );
if ($is_seq) $result = array_values($result);
If you get an error on end, then you can use this for that line instead:
end($array); $is_seq = key($array) == count($array)-1;
The $is_seq variable checks that $array is sequential, and if so, calls array_values after the removal of the duplicates, which always returns a sequential array.
I think that the problem here is this:
"0": {
"category_ID": 8,
"category_name": "category 1",
"category_count": 2
},
"2": {
"category_ID": 13,
"category_name": "category 2",
"category_count": 1
}
if you want an array to be a json encoded array, indexes must be numeric and correlatives (0,1,2,3...)
Probably, after using your $this->super_unique( $cats_all ), or inside this function, you should call array_values on every array that has been reindexed; it reset the values of the array to 0, 1, ... etc... and when encoded, it will be an array isntead of an object.
Generally speaking, it´s a good practice to use $array = array_values($array) after using array_filter(...) to correctly reindex the array, elsewhere, you can get indexes like 0,2,7... etc...
Let me know if you need more details
I am creating an very large multidimensional array using PHP. Each object contains Name, ID, ParentID and Children. Children is an array of more objects in the same format.
It is critical I name the IDs of each object - this helps me put each object under the correct parent. (In the code below, I use 101, 102 etc.)
However, the problem I am having is when I return the array in JSON using json_encode. Each 'Children' array is being printed as an object, not an array - as shown in the JSON code below.
As I read on another SO thread here, they "are made as objects because of the inclusion of string keys" - although they are numbers, they are still strings.
{
"101": {
"ID": "101",
"ParentID": "0",
"Name": "Root One"
"Children": {
"102": {
"ID": "102",
"ParentID": "101",
"Name": "Child One"
},
"103": {
"ID": "103",
"ParentID": "101",
"Name": "Child Two",
"Children": {
"104": {
"ID": "104",
"ParentID": "103",
"Name": "Child Child One"
}
}
},
Does anyone know how to overcome this issue?
Edit: The JSON should look like this (the square brackets are important!):
[
{
"ID": "101",
"ParentID": "0",
"Name": "Root One",
"Children": [
{
"ID": "102",
"ParentID": "101",
"Name": "Child One",
"Children": [
A JSON array has no explicit indexes, it's just an ordered list. The only JSON data structure that has named keys is an object. The literal should make this quite obvious:
["foo", "bar", "baz"]
This array has no named indices and there isn't any provision to add any.
PHP conflates both lists and key-value stores into one array data type. JSON doesn't.
This is your object:
$parent=new StdClass();
$parent->ID=101;
$parent->ParentID=0;
$parent->Name='Root One';
$child1=new StdClass();
$child1->ID=1011;
$child1->ParentID=$parent->ID;
$child1->Name='Child One';
$parent->Children[]=$child1;
$child1_1=new StdClass();
$child1_1->ID=10111;
$child1_1->ParentID=$child1->ID;
$child1_1->Name='Child One One';
$child1->Children[]=$child1_1;
This is your JSON convert function:
echo json_encode($parent,JSON_PRETTY_PRINT);
and this is your object coded into JSON format:
{
"ID": 101,
"ParentID": 0,
"Name": "Root One",
"Children": [
{
"ID": 1011,
"ParentID": 101,
"Name": "Child One",
"Children": [
{
"ID": 10111,
"ParentID": 1011,
"Name": "Child One One"
}
]
}
]
}
The answer came later because I started learning PHP later. Anyway, some day, someone might find it useful.
I have now got a working solution which is fast and works well.
Firstly, as written in SO link from the question;
In JSON, arrays only have numeric keys, whereas objects have string
properties. The inclusion of a array key forces the entire outer
structure to be an object by necessity.
In JSON; Curly braces hold objects ({}), Square brackets hold arrays ([]).
So using a string as a key will result in the json_encode function returning objects, whereas reseting the keys will ensure it creates arrays.
Therefore, just before I return my JSON encoded string, I run a function to reset all the array keys. The code I found on this SO thread (Reset array keys in multidimensional array) was particularly useful!
http://php.net/manual/en/function.json-decode.php
Set 2nd parameter of json_decode to true to atleast get assoc arrays.
Aside from that: javascript can't handle non-sequential/non-contiguous array indexes, so as soon as the id's are not sequential, json has no other option then to convert it into "string" indexes.