I'm working with a large set of nested arrays in PHP. The data originally started as a JSON data object that was converted with json_decode true. I've been able to navigate the resulting nested array without too much issue up till now. I've run into the following problem.
Scores
Team1
Info1
Info2
Element1
Element2
**Info3**
Element1
Item1
Item2
Element2
Item1
Item2
**Info3**
Element1
Item1
Item2
Element2
Item1
Item2
The problem is that Info3 are two distinct arrays with their own collections of data that I need to extract, but they have the same exact name. Running something like:
echo $Scores['Team1']['Info3'][0]['Item1']
Works to a degree; but it only captures the items of the elements of the last Info3 instance. Info3 instances further up the chain are ignored. I've also tried specifying the instance of the array I want specifically, like so:
$echo $Scores['Team1'][3]['Element1']['Item1']
Which is very similar to the above but for some reason doesn't work. It's as if the Element arrays are keyed, but the Info arrays are not. I've also tried a foreach loop through Team1 and taking action only if the value was equal to Info3, but again no joy. To further complicate things, the number of Info3 arrays is itself variable, number 0-5, so my capture has to be similarly dynamic.
Edit: Adding a JSON snippet, as requested.
"scores": {
"team1": {
"info1": 0,
"info2": [
{
"element1": 1,
"element2": 144568658
},
{
"element1": 2,
"element2": 132020087
}
]
,
"info3": [
{
"item1": 5462,
"item2": 1
}
]
,
"info3": [
{
"item1": 5608,
"item2": 1
},
{
"item1": 5611,
"item2": 1
}
]
,
"info3": [
{
"item1": 5127,
"item2": 1
}
]
},
"team2": { etc...
Edit: Thanks to everyone who took time to answer. Seems the problem with not with my coding attempts but with the JSON source being malformed.
Based off the comment from Jujunol we came up with this workaround for the bad JSON data:
$info3Count = substr_count($jsonString, '"info3": [');
$c = 1;
while ($c <= $info3Count) {
$pos = strpos($jsonString, '"info3": [');
$jsonString = substr_replace($jsonString, '"info3-'.$c.'": [', $pos,
strlen('"info3": ['));
$c++;
}
Basically, we imported the JSON as raw text, hunted through it for info3 instances and appended a -n to the end of it where n was a simple counter. This rendered each instance of info3 unique enough for a successful json_decode.
Related
I'm working on a PHP script to add new item in JSON array (JSON is in a file) and I've found a prob and its solution. My question is: can someone explains why the first code doesn't work?
The JSON is built on several imbricated arrays describing batiments, stairs and objects on each stair of each batiment:
"bats":[
// each batiment
{"name":"Bat A","photo":"photo-bat-0.png",
"stairs":[
// level 0
{"plan":"plan-0-0.png","note":"",
"objs":[
{"id":"obj-0-0-0","type":"MER","col":"black","left":"","top":"","cable":22,"img":""},
{"id":"obj-0-0-1","type":"SER","col":"blue","left":"","top":"","cable":12,"img":""}
],
},
// level 1
{"plan":"plan-0-1.png","note":"",
"objs":[
{"id":"obj-0-1-0","type":"TFT","col":"red","left":"","top":"","cable":8,"img":""},
{"id":"obj-0-1-1","type":"AP1","col":"green","left":"","top":"","cable":12,"img":""},
{"id":"obj-0-1-2","type":"AP2","col":"green","left":"","top":"","cable":14,"img":""}
]
}
]
},
{"name":"Bat B","photo":"photo-bat-1.png"
"stairs":[
...
Adding a new object to BAT 1 LEVEL 0:
$bat = 1;
$lev = 0;
// get existing objects
$objects = $json_data['bats'][$bat]['stairs'][$lev]['objs'];
$n = count($objects);
echo "found $n objects on level $lev of bat $bat<br>";
for($o=0; $o<count($objects); $o++){
echo $objects[$o]['id']."<br>";
}
The object to add to array
$newobject = array("id"=>"obj-".$bat."-".$lev."-".$o,"type"=>"AP","coul"=>"green","left"=>123,"top"=>155,"cable"=>5,"img"=>"image-obj-".$bat."-".$lev."-".$o);
This code doesn't work: (JSON file remains the same once reloaded)
array_push($objects,$newobject);
This one works: (JSON file updated)
array_push($json_data['bats'][$bat]['stairs'][$lev]['objs'],$newobject);
Why is it necessary to recreate the full access path to array 'objs'?
this question comes from the posting I found here:
DataTables Multiple Tables from Multiple JSON Arrays
I'd like to know the simplest and best way to generate the JSON below. I can see the pattern is 'JSON object -> Array Header -> Array -> JSON object' but I do not know how to do this in PHP, from a mySQLi query result. I imagine having a mySQL table with a 'policies' and 'services' column so the query might look something like:
Select name, id, score, type from myTable where type = 'policies' and
type = 'services'
And the result would come back something like:
name id score type
A 1 0 policies
B 2 0 services
But then how would I take that query and generate this JSON in php?
{
"Policies": [
{
"name": "A",
"id": "1",
"score": "0"
}
],
"Services": [
{
"name": "B",
"id": "2",
"score": "0"
}
]
}
Thanks for your help!
Start by creating the new empty array.
Then, iterate through the result and add it in the correct sub-array:
$new = [];
foreach ($result as $item) {
// Uppercase the first character
$type = ucfirst($item['type']);
if (!isset($new[$type])) {
// This type doesn't exist in the new array yet, let's create it.
$new[$type] = [];
}
// Add the item
$new[$type][] = $item;
}
// Output it as json
echo json_encode($new, JSON_PRETTY_PRINT);
The above code will also work if new types are added to the database.
PS. The JSON_PRETTY_PRINT argument is just to make the json string a bit more readable while developing. When everything looks good, you can remove it.
I have an array like so
id | userID | item
1 ! 1 | {"property": 0, "property": "string"}
2 ! 1 | {"property": 4, "property": "string2"}
and I wish to return one array with like so:
[{
"property": 0,
"property": "string"
},
{
"property": 4,
"property": "string2"
}]
No matter what I try I cannot seem to get it to work properly. Either I get a whole string so number values get converted, or I get an object with \" everywhere. Currently I have this code
if ($query = $mysqli->query("SELECT item FROM userItems WHERE userID = 'id' "))
{
while ($row = $query->fetch_object())
{
$result->items[count($result)] = $row;
}
}
$test = stripslashes(json_encode($result->items));
which returns this ...
{"1":{"item":"{"property":"0","property":"string"}"}}
Been trying to solve it for hours and can't get it right
I tried your code and there're two main things:
you're building an array of associative arrays but associative array tends to overwrite identical associative keys with the latter in your code - in your case both keys are property,
the data you're retrieving from DB (userItems.item) already seems to be JSON encoded so you need to call json_decode() somewhere instead of calling json_encode() again; decoding your $row->item ($result->items[count($result)] = json_decode($row->item);) seems to do the trick.
Just as a sidenote you should consider wrapping your id parameter in SQL query into mysqli_real_escape_string() or so.
Let me know if that helped and you see the desired result now.
I have some troubles with the following situation. I want to output nested information that looks a bit like this:
"name": "X",
"children": [
{
"name": "categories",
"children": [
{
"name": "Cat A",
"children": [
{"name": "B"},
{"name": "C"},
{"name": "D"}
]
},
{
"name": "Cat B",
"children": [
{"name": "C"},
{"name": "D"}
]
}
In this case you see that the last } of child Cat A has an comma at the end, while the last nest (Cat B) does not have comma at the end. In a previous topic I learned how to resolve the comma within the the inner loop ({"name": "D"}). However, using the implode (with sprintf instead of printf) at the end of the first while loop (see code below) created double prints of the data.
This is what the code looks like (slightly adjusted):
while ($ucs = mysqli_fetch_object($uc))
{
printf('{');
printf('"name": "%s",', $ucs->cat);
/*for ($i = 0; $i < 100; $i++)
{
$cat_name = $ucs->cat;
}*/
printf('"children": [');
$rtitle = "SELECT title FROM table WHERE genre='$category'";
//Some other code of lesser relevance for this issue
$names = array();
while ($title2 = mysqli_fetch_object($ptitles)) {
$names[] = sprintf('"name": "%s"', $title2->title);
}
echo implode(',', $names);
printf(']');
printf('},');
//Some other code
Now the main issue is to have the comma out of the last print statement.
However, using implode for the category did not work out. In the previous topic a user pointed me out to add it before the code if it isn't the first output. However, would that work in this scenario? If so, how could I flag whether this is the first iteration?
I hope someone can help me out here,
Help is again very much appreciated,
Thanks in advance!
At the beginning of your loop set a variable to 0 and at the end of the loop increment it by 1. Then, use an if statement to see if the variable is equal to 0.
Use json_encode(), though. It will lead to cleaner, more maintainable code.
I've got an array with different "columns", for example: id, title, date, data etc.
It is a JSON array.
The data element has multiple entries:
"data":["test = test", "2nd test", "3rd test"]
How can I find how many entries there are in the "data" element of the "result" array?
When I try result.data.length, it gives me the whole length, so all the characters.
Here, it would say something like 27, while I want 3 as an answer.
EDIT: this is how I get the elements and push them (I get a JSON array):
$.getJSON("test.php?id=" + id, function(data) {
$.each(data, function(index, data1) {
window.result.push(data1);
});
And this is the test.php code:
if(isset($_GET['id'])){
$id = $_GET['id'];
$liste = getData($id);
$arr = array();
$i = 0;
foreach($liste as $result){
$arr[$i]['id'] = $result->id();
$arr[$i]['titre'] = $result->titre();
$arr[$i]['data'] = $result->listeMot();
$i++;
}
echo json_encode($arr);
Thanks for the help.
The answer was finally found (thanks a lot to #RocketHamzat).
It was indeed a string, and not an array. In that case, I had returns after each pair of words (I thought they were separated by commas, but they weren't).
So, to count, this is what I did:
result.data.split('\r\n').length;
This worked like a charm. Thanks for your help!
I agree with the comments posted - your return object does not look as if it is formatted properly. data should be an object with a key value of the array. Your return should look like the following:
var d = '{"data":["test = test", "2nd test", "3rd test"]}';
console.dir(JSON.parse(d));
var arr = JSON.parse(d);
console.log(arr.data.length);
The console.dir will display the object, and the console.log displays a length of 3.
Are you formatting the response as a JSON string manually? If so wrap with {}
Hope that helps.