Adding up the TOTAL number of XML Items with PHP - php

I am trying to get the total number of bikes available in a bike share system. I am using php and simpleXML to filter the XML data.
I have successfully retrieved the number of bikes at each station.
foreach ($xml->station as $items) {
print $items->nbBikes;
}
But I want the total number of bikes available at all stations. I tried this to declare a variable ($totalBikes) that added to itself each time through the foreach statement, but it did not work.
foreach ($xml->station as $items) {
print $items->nbBikes;
$numberOfBikes = $items->nbBikes;
$totalBikes= $numberOfBikes += $numberOfBikes;
}
print $totalBikes;
Can anyone please suggest a way to get the total number of bikes?
Thanks!

You want to add $numberofbikes to $totalbikes, not to itself:
$totalBikes += $numberOfBikes;
which is a shortcut version of
$totalBikes = $totalbikes + $numberOfBikes;
Be sure you're declaring '$totalbikes' before your foreach loop though so it doesn't get reset on each iteration.

You declared $totalBikes within the loop, so it is getting reset every time you iterate. Also, you're not adding $numberOfBikes to $totalBikes properly. Try this:
$totalBikes = 0;
foreach ($xml->station as $items) {
$numberOfBikes = $items->nbBikes;
$totalBikes += $numberOfBikes;
}
print $totalBikes;

Instead of iterating, use xpath:
$bikes = $xml->xpath("/stations/station/nbBikes");
$sum = array_sum(array_map("intval", $bikes));
line 1 will select all <nbBikes> into an array, but as SimpleXml objects
line 2 will first transform all elements to Integer, then add them up.
Note: For a one-liner, there's a sum-function in xpath, but I couldn't get it to work. Any ideas why?
$sum = $xml->xpath("sum(/stations/station/nbBikes)")[0];

Related

How to get the value of a $total before the code calculated?

I want to show a content of variable whom been calculate in a foreach loop. The problem is that I want to echo it before the loop.
<?php
echo $total; // note this line I want to appear the total count of loop. the problem is it cannot appear because it is in the above of foreach loop. I want to appear it in this above before foreach loop.
$total = 0;
foreach($pathList as $item) {
$fileInfo = pathinfo($item);
if(preg_match(strtolower('/\b'.$_POST['song'].'\b/'), strtolower($filename))) {
$total = $total + 1; // the total count of foreach loop I want to appear in echo $total
}
// some code
}
?>
I do want to echo it inside the loop but only once after completed the loop.
Any idea how do I solve this problem? I tried global $total but not working...
Thanks in advance!
Generally - NO. You cannot echo variable that not been calculate yet (synchronization in PHP).
If all you do in the for-loop regarding $total is increasing by 1 then you actually count the number of element in the array so you can just do:
echo count($pathList);
Before the for-loop. Documentation in here
Updated:
If $total is affected in the loop (as you updated the question) then I believe best practice will be to counting array element first (without executing any more code), then echo the $total, afterward, loop on the original data and execute the rest of your code.
$total = 0;
foreach($pathList as $item) {
$fileInfo = pathinfo($item);
if(preg_match(strtolower('/\b'.$_POST['song'].'\b/'), strtolower($filename))) // or what ever condition you have to check for total
$total = $total + 1;
}
echo count($total); // give you the count you need
foreach($pathList as $item) {
// exec the rest of your code
}
This may run at O(2*n) but its not worse
It is not possible. Lines are executed in the order in which they appear in the script.
The value of $total at the end of the loop is equal to the value of count($pathList)
If you need the value of the last iterated element of the $pathList before the execution of the loop, then it can be echoed as
echo $pathList[count($pathList)-1];

PHP Loop for, and simplexml_load_file

How can I use a loop for with simplexml_load_file to get all data?
$meteo = simplexml_load_file('hxxp://dzmeteo.com/weather.xml');
for($i=1;$i<$jours;$i++) {
$d1_icon_d = $meteo->dayf->day[$i]->part[0]->icon;
$d1_icon_n = $meteo->dayf->day[$i]->part[1]->icon;
echo $d1_icon_d;
$i++;
}
You are quite close:
$meteo = simplexml_load_file('hxxp://dzmeteo.com/weather.xml');
foreach ($meteo->dayf->day as $day) {
$d1_icon_d = $day->part[0]->icon;
$d1_icon_n = $day->part[1]->icon;
echo $d1_icon_d;
}
Any time you want to access the content on an entire array use foreach. It provides for a reliable way to ensure you have actually seen all the elements of the array and makes your code readable to yourself and others.
Remove $i++; at the end of the loop. The for loop will increment the index for you so as of now you are getting rows 1,3,5,7 and so on instead of 1,2,3,4,5,6. Also I'm not sure if this is deliberate but typically indexes start at 0 and yours starts at 1.

Having Trouble with PHP foreach loop

I'm having trouble working with a foreach loop in my PHP script. I have retrieved an array of records from a database search and I now want to get the total for one of the fields in the found set of records. Here's my code so far:
foreach($result->getRecords() as $record){
$recordTotal = $record->getField('products_total');
$salesToday = $salesToday + $recordTotal;
}
If 5 records were found and the value of the 'products_total' field was:
1
2
3
4
5
I want to get the total of these (15) and store that in the $salesToday variable. The $salesToday variable doesn't exist prior to this foreach loop.
Can anyone spot the error in my code? If I echo $salesToday after the loop I get 0 instead of 15.
Check if $recordTotal has values in all the iterations. Maybe is always 0.
$recordTotal = 0;
foreach($result->getRecords() as $record){
$recordTotal = $record->getField('products_total');
$salesToday += $recordTotal;
}
You can try that code, but is the same code that you are using, with the $recordTotal var initialized.
Maybe initialize the $salesToday variable before the for each loop?
$salesToday = 0;
EDIT:
$salesToday = 0;
foreach($result->getRecords() as $record){
$salesToday += $record->getField('products_total');
}
$salesToday=0;
foreach($result->getRecords() as $record){
$salesToday += $record->getField('products_total');
}
echo 'Today sales:'.$salesToday.'<br/>';
Declare the $salesToday before the loop. Each loop iteration won't remember the value before.
The reason for this is a form of automatic memory management called garbage collection. In it's simplest form, the garbage collector will free up memory that isn't being used anymore.
In this example the $salesToday variable is only declared within the loop so it expects the variable to only ever be used in that loop. Say for example you had another loop surrounding everything you had there. If you declared the variable in the 2nd loop, it would only be available in the 2nd and 3rd loops and not the 1st. The same goes for functions/method, if statements etc.
Turns out to be an issue with my access privileges and not being able to view some of the values from the database record. These posts helped me locate the issue and correct the syntax issue with my loop.

Accounting for missing array keys, within PHP foreach loop

I'm parsing a document for several different values, with PHP and Xpath. I'm throwing the results/matches of my Xpath queries into an array. So for example, I build my $prices array like this:
$prices = array();
$result = $xpath->query("//div[#class='the-price']");
foreach ($result as $object) {
$prices[] = $object->nodeValue; }
Once I have my array built, I loop through and throw the values into some HTML like this:
$i = 0;
foreach ($links as $link) {
echo <<<EOF
<div class="the-product">
<div class="the-name"><a title="{$names[$i]}" href="{$link}" target="blank">{$names[$i]}</a></div>
<br />
<div class="the-image"><a title="{$names[$i]}" href="{$link}" target="blank"><img src="{$images[$i]}" /></a></div>
<br />
<div class="the-current-price">Price is: <br> {$prices[$i]}</div>
</div>
EOF;
$i++; }
The problem is, some items in the original document that I'm parsing don't have a price, as in, they don't even contain <div class='the-price'>, so my Xpath isn't finding a value, and isn't inserting a value into the $prices array. I end up returning 20 products, and an array which contains only 17 keys/values, leading to Notice: Undefined offset errors all over the place.
So my question is, how can I account for items that are missing key values and throwing off my arrays? Can I insert dummy values into the array for these items? I've tried as many different solutions as I can think of. Mainly, IF statements within my foreach loops, but nothing seems to work.
Thank you
I suggest you look for an element inside your html which is always present in your "price"-loop. After you find this object you start looking for the "price" element, if there is none, you insert an empty string, etc. into your array.
Instead of directly looking for the the-price elements, look for the containing the-product. Loop on those, then do a subquery using those nodes as the starting context. That way you get all of the the-product nodes, plus the prices for those that have them.
e.g.
$products = array();
$products = $xpath->query("//div[#class='the-product']");
$found = 0 ;
foreach ($products as $product) {
$products[$found] = array();
$price = $xpath->query("//div[#class='the-price']", $product);
if ($price->length > 0) {
$products[$found] = $price->item(0)->nodeValue;
}
$found++;
}
If you don't want to show the products that don't have a price attached to them you could check if $prices[$i] is set first.
foreach($links AS $link){
if(isset($prices[$i])){
// echo content
}
}
Or if you wanted to fill it will dummy values you could say
$prices = array_merge($prices,
array_fill(count($prices), count($links)-count($prices),0));
And that would insert 0 as a dummy value for any remaining values. array_fill starts off by taking the first index of the array (so we start one after the amount of keys in $prices), then how many we need to fill, so we subtract how many are in $prices from how many are in $links, then we fill it with the dummy value 0.
Alternatively you could use the same logic in the first example and just apply that by saying:
echo isset($prices[$i]) ? $prices[$i] : '0';
Hard to understand the relation between $links and $prices with the code shown. Since you are building the $prices array without any relation to the $links array, I don't see how you would do this.
Is $links also built via xpath? If so, is 'the-price' div always nested within the DOM element used to populate $links?
If it is you could nest your xpath query to find the price within the query used to find the links and use a counter to match the two.
i.e.
$links_result = $xpath->query('path-to-link')
$i = 0
foreach ($links_result as $link_object) {
$links[$i] = $link_object->nodeValue;
// pass $link_object as context reference to xpath query looking for price
$price_result = $xpath->query('path-to-price-within-link-node', $link_object);
if (false !== $price_result) {
$prices[$i] = $price_result->nodeValue;
} else {
$prices[$i] = 0; // or whatever value you want to show to indicate that no price was available.
}
$i++;
}
Obviously, there could be additional handling in there to verify that only one price value exists per link node and so forth, but that is basic idea.

How can I find out how many times a foreach construct loops in PHP, without using a "counter" variable?

If I have a foreach construct, like this one:
foreach ($items as $item) {
echo $item . "<br />";
}
I know I can keep track of how many times the construct loops by using a counter variable, like this:
$counter = 0;
$foreach ($items as $item) {
echo $item.' is item #'.$counter. "<br />";
$counter++;
}
But is it possible to do the above without using a "counter" variable?
That is, is it possible to know the iteration count within the foreach loop, without needing a "counter" variable?
Note: I'm totally okay with using counters in my loops, but I'm just curious to see if there is a provision for this built directly into PHP... It's like the awesome foreach construct that simplified certain operations which are clunkier when doing the same thing using a for construct.
No it's not possible unless your $items is an array having contiguous indexes (keys) starting with the 0 key.
If it have contiguous indexes do:
foreach ($items as $k => $v)
{
echo $k, ' = ', $v, '<br />', PHP_EOL;
}
But as others have stated, there is nothing wrong using a counter variable.
There's no easier way - that's kinda what count variables are for.
I'm assuming that you want to know the current count during the loop. If you just need to know it after, use count($items) as others have suggested.
You could tell how many time it WILL loop or SHOULD have looped by doing a
$loops = count($items);
However that will only work if your code does not skip an iteration in any way.
foreach loops N times, where N is just the size of the array. So you can use count($items) to know it.
EDIT
Of course, as noticed by Bulk, your loop should not break (or maybe continue, but I would count a continue as a loop, though shorter...)

Categories