my question has to do with PHP and XML. I would like to echo out some attributes, but echo ones that repeat only once.
Say this was the XML I was dealing with, and it was called beatles.xml:
<XML_DATA item=“TheBeatles”>
<Beatles>
<Beatle Firstname=“George” Lastname=“Harrison” Instrument=“Guitar”>Harrison, George</Beatle>
<Beatle Firstname=“John” Lastname=“Lennon” Instrument=“Guitar”>Lennon, John</Beatle>
<Beatle Firstname=“Paul” Lastname=“McCartney” Instrument=“Bass”>McCartney, Paul</Beatle>
<Beatle Firstname=“Ringo” Lastname=“Starr” Instrument=“Drums”>Starr, Ringo</Beatle>
</Beatles>
</XML_DATA>
This is the PHP I have so far:
$xml = simplexml_load_file("http://www.example.com/beatles.xml");
$beatles = $xml->Beatles->Beatle;
foreach($beatles as $beatle) {
echo $beatle->attributes()->Instrument.',';
}
I would expect this to echo out Guitar,Guitar,Bass,Drums, but I would like Guitar to only display once. How would I prevent repeat attribute values from echoing out?
Inside the foreach loop, cast the instrument name as a string and push it into an array. Once the loop finishes execution, you will have an array containing all the instrument names (with duplicates, of course). You can now use array_unique() to filter out the duplicate values from the array:
$instruments = array();
foreach($beatles as $beatle) {
$instruments[] = (string) $beatle->attributes()->Instrument;
}
$instruments = array_unique($instruments);
Demo.
$xml = simplexml_load_file("http://www.example.com/beatles.xml");
$beatles = $xml->Beatles->Beatle;
$result = array();
foreach($beatles as $beatle) {
if (!array_key_exists($beatle->attributes()->Instrument, $result)) {
$result[] = $beatle->attributes()->Instrument;
// echo $beatle->attributes()->Instrument.',';
}
}
then Loop through the $result array with foreach
Either use xpath.
Related
I have a JSON file. (Steam API). I want to display player inventory in my website. I use this url: https://steamcommunity.com/id/majidsajadi/inventory/json/730/2
Then I decode it with json_decode function.
Now there are two arrays: rgInventory and rgDescription. I need to check if class id in rgInventory and classid in rgDescription match I use some of values in igDescription.
So I think I should use 2 foreach loop and a if condition to check if class id match. then I echo out the information I need.
The question is how should I use nested foreach?
You can use two nested foreach loops like this:
Assuming that $decoded_data is your decoded data after applying json_decode() function on the end result, like this: $decoded_data = json_decode($your_json_data, true);
foreach($decoded_data['rgInventory'] as $arr1){
foreach($decoded_data['rgDescriptions'] as $arr2){
if($arr1['classid'] == $arr2['classid']){
// both the classid matches
// your code
}
}
}
Try this code:
$steamData = json_decode(file_get_contents("https://steamcommunity.com/id/majidsajadi/inventory/json/730/2"), true);
if($steamData["success"] != 1){
exit();
}
$match = array();
foreach($steamData["rgInventory"] as $v1){
$match[$v1["classid"]]["match"] = false;
$match[$v1["classid"]]["count"] = 0;
}
foreach($steamData["rgDescriptions"] as $v2){
if(array_key_exists($v2["classid"],$match)){
$match[$v2["classid"]]["match"] = true;
$match[$v2["classid"]]["count"]++;
}
}
print_r($match);
I'm trying to parse a json file into a for each loop. The issue is the data is nested in containers with incremented numbers, which is an issue as I can't then just grab each value in the foreach. I've spent a while trying to find a way to get this to work and I've come up empty. Any idea?
Here is the json file tidied up so you can see what I mean - http://www.jsoneditoronline.org/?url=http://ergast.com/api/f1/current/last/results.json
I am trying to get values such as [number] but I also want to get deeper values such as [Driver][code]
<?php
// get ergast json feed for next race
$url = "http://ergast.com/api/f1/current/last/results.json";
// store array in $nextRace
$json = file_get_contents($url);
$nextRace = json_decode($json, TRUE);
$a = 0;
// get array for next race
// get date and figure out how many days remaining
$nextRaceDate = $nextRace['MRData']['RaceTable']['Races']['0']['Results'][' . $a++ . '];
foreach ($nextRaceDate['data'] as $key=>$val) {
echo $val['number'];
}
?>
While decoding the json there's no need to flatten the object to an Associative array. Just use it how it is supposed to be used.
$nextRace = json_decode($json);
$nextRaceDate = $nextRace->MRData->RaceTable->Races[0]->Results;
foreach($nextRaceDate as $race){
echo 'Race number : ' . $race->number . '<br>';
echo 'Race Points : ' . $race->points. '<br>';
echo '====================' . '<br>';
}
CodePad Example
You are nearly correct with your code, you are doing it wrong when you try the $a++. Remove the $a = 0, you won't need it.
Till here you are correct
$nextRaceDate = $nextRace['MRData']['RaceTable']['Races']['0']['Results']
What you have to do next is this
$nextRaceDate = $nextRace['MRData']['RaceTable']['Races']['0']['Results'];
foreach($nextRaceDate as $key => $value){
foreach($value as $key2 => $value2)
print_r($value2);
So, in my code, you are stopping at Results, and then, you want to iterate over all the results, from 0 to X, the first foreach will do that, you have to access $value for that. So, add another foreach to iterate over all the content that $value has.
There you go, I added a print_r to show you that you are iterating over what you wanted.
The problem is how you access to the elements in the nested array.
Here a way to do it:
$mrData = json_decode($json, true)['MRData'];
foreach($nextRace['RaceTable']['Races'] as $race) {
// Here you have access to race's informations
echo $race['raceName'];
echo $race['round'];
// ...
foreach($race['Results'] as $result) {
// And here to a result
echo $result['number'];
echo $result['position'];
// ...
}
}
I don't know where come's from your object, but, if you're sure that you'll get everytime one race, the first loop could be suppressed and use the shortcut:
$race = json_decode($json, true)['MRData']['RaceTable']['Races'][0];
Your problem is that the index must be an integer because the array is non associative. Giving a string, php was looking for the key '$a++', and not the index with the value in $a.
If you need only the number of the first race, try this way
$a = 0;
$nextRaceDate = $nextRace['MRData']['RaceTable']['Races']['0']['Results'][$a];
echo "\n".$nextRaceDate['number'];
maybe you need to iterate in the 'Races' attribute
If you need all, try this way :
$nextRaceDate = $nextRace['MRData']['RaceTable']['Races'];
foreach ($nextRaceDate as $key => $val) {
foreach ($val['Results'] as $val2) {
echo "\nNUMBER " . $val2['number'];
}
}
I am trying to parse a json. I am running this in a foreach loop and if I do the following it works:
$places = array('restaurant', 'store', 'etc')
foreach ($this->placesCachingTypes as $places) {
$places_location_lat = $json_decoded->json[0]->restaurant[0]->geometry->location->lat;
$places_location_lng = $json_decoded->json[0]->restaurant[0]->geometry->location->lng;
}
However, when I do the following, i.e. I change restaurant to $places (I need to do this since I have an array of different places and I want to parse all of them in a foreach loop) it doesn't work.
foreach ($this->placesCachingTypes as $places) {
$places_location_lat = $json_decoded->json[0]->$places[0]->geometry->location->lat;
$places_location_lng = $json_decoded->json[0]->$places[0]->geometry->location->lng;
}
Solution is changing $places to {$places}[0]
The $places array contains keywords, such as restaurant or store. So the [0] is referring to the first one in the json which is why it's needed.
Why do you have this in the first loop:
json[0]->restaurant[0]
json[0]->$restaurant[0]
But then in the next you have:
json[0]->$places[0]
json[0]->$places[0]
Perhaps you are parsing the JSON incorrectly and it should be:
foreach ($this->placesCachingTypes as $places) {
$places_location_lat = $json_decoded->json[0]->places[0]->geometry->location->lat;
$places_location_lng = $json_decoded->json[0]->places[0]->geometry->location->lng;
}
And then in the first loop, you should do a similar edit to get rid of $restaurant[0]:
foreach ($this->placesCachingTypes as $places) {
$places_location_lat = $json_decoded->json[0]->restaurant[0]->geometry->location->lat;
$places_location_lng = $json_decoded->json[0]->restaurant[0]->geometry->location->lng;
}
Then again, unclear on what value $places has when you loop via foreach ($this->placesCachingTypes as $places) {. It does’t make sense what you would be looping through with the value of $places. And perhaps assigning that $places in the loop object of $json_decoded->json[0]-> is the source of your issues? Need more info from you to confirm this.
I'm trying to get the result of my foreach loop into an url to do a simplexml_load_file with.
So it goes like this:
(...) //SimpleXML_load_file to get $feed1
$x=1;
$count=$feed1->Count; //get a count for total number of loop from XML
foreach ($feed1->IdList->Id as $item1){
echo $item1;
if($count > $x) {
echo ',';} //Because I need coma after every Id, except the last one.
$x++;
}
The two echo are just to see the result. It gives me something like:
22927669,22039496,21326191,18396266,18295747,17360921,15705350,15681025,15254092,12939407,11943825,11495650,10964843
I would like to put that in a url to make a simplexml_load_file just like that
$feed_url = 'http://www.whatevergoeshere'. $RESULT_OF_FOREACH . 'someothertext';
So it would look like:
$feed_url = 'http://www.whatevergoeshere22927669,22039496,21326191,18396266,18295747,17360921,15705350,15681025,15254092,12939407,11943825,11495650,10964843someothertext';
I've try to store it into an array or a function and then call it into the feed_url but it did not work the way I tried it.
I hope it's clear, I'll answer fast to questions if not.
Thanks.
It's really difficult to make out what you want, so I'm going to guess you want to store the list as a comma delimited string in a variable. the easiest way is to implode the array of ids
$ids = array();
foreach ($feed1->IdList->Id as $item1){
$ids[] = (string) $item1;
}
$RESULT_OF_FOREACH = implode(',', $ids);
$feed_url = 'http://www.whatevergoeshere'. $RESULT_OF_FOREACH . 'someothertext';
I have a PHP array that I'd like to duplicate but only copy elements from the array whose keys appear in another array.
Here are my arrays:
$data[123] = 'aaa';
$data[423] = 'bbb';
$data[543] = 'ccc';
$data[231] = 'ddd';
$data[642] = 'eee';
$data[643] = 'fff';
$data[712] = 'ggg';
$data[777] = 'hhh';
$keys_to_copy[] = '123';
$keys_to_copy[] = '231';
$keys_to_copy[] = '643';
$keys_to_copy[] = '712';
$keys_to_copy[] = '777';
$copied_data[123] = 'aaa';
$copied_data[231] = 'ddd';
$copied_data[643] = 'fff';
$copied_data[712] = 'ggg';
$copied_data[777] = 'hhh';
I could just loop through the data array like this:
foreach ($data as $key => $value) {
if ( in_array($key, $keys_to_copy)) {
$copied_data[$key] = $value;
}
}
But this will be happening inside a loop which is retrieving data from a MySQL result set. So it would be a loop nested within a MySQL data loop.
I normally try and avoid nested loops unless there's no way of using PHP's built-in array functions to get the result I'm looking for.
But I'm also weary of having a nested loop within a MySQL data loop, I don't want to keep MySQL hanging around.
I'm probably worrying about nested loop performance unnecessarily as I'll never be doing this for more than a couple of hundred rows of data and maybe 10 keys.
But I'd like to know if there's a way of doing this with built-in PHP functions.
I had a look at array_intesect_key() but that doesn't quite do it, because my $keys_to_copy array has my desired keys as array values rather than keys.
Anyone got any ideas?
Cheers, B
I worked it out - I almost had it above.I thought I'd post the answer anyway for completeness. Hope this helps someone out!
array_intersect_key($data, array_flip($keys_to_copy))
Use array_flip() to switch $keys_to_copy so it can be used within array_intersect_keys()
I'll run some tests to compare performance between the manual loop above, to this answer. I would expect the built-in functions to be faster but they might be pretty equal. I know arrays are heavily optimised so I'm sure it will be close.
EDIT:
I have run some benchmarks using PHP CLI to compare the foreach() code in my question with the code in my answer above. The results are quite astounding.
Here's the code I used to benchmark, which I think is valid:
<?php
ini_set('max_execution_time', 0);//NOT NEEDED FOR CLI
// BUILD RANDOM DATA ARRAY
$data = array();
while ( count($data) <= 200000) {
$data[rand(0, 500000)] = rand(0, 500000);
}
$keys_to_copy = array_rand($data, 100000);
// FOREACH
$timer_start = microtime(TRUE);
foreach ($data as $key => $value) {
if ( in_array($key, $keys_to_copy)) {
$copied_data[$key] = $value;
}
}
echo 'foreach: '.(microtime(TRUE) - $timer_start)."s\r\n";
// BUILT-IN ARRAY FUNCTIONS
$timer_start = microtime(TRUE);
$copied_data = array_intersect_key($data, array_flip($keys_to_copy));
echo 'built-in: '.(microtime(TRUE) - $timer_start)."s\r\n";
?>
And the results...
foreach: 662.217s
array_intersect_key: 0.099s
So it's much faster over loads of array elements to use the PHP array functions rather than foreach. I thought it would be faster but not by that much!
Why not load the entire result set into an array, then begin processing with nested loops?
$query_result = mysql_query($my_query) or die(mysql_error());
$query_rows = mysql_num_rows($query_result);
for ($i = 0; $i < $query_rows; $i++)
{
$row = mysql_fetch_assoc($query_result);
// 'key' is the name of the column containing the data key (123)
// 'value' is the name of the column containing the value (aaa)
$data[$row['key']] = $row['value'];
}
foreach ($data as $key => $value)
{
if ( in_array($key, $keys_to_copy))
{
$copied_data[$key] = $value;
}
}