PHP Loop for, and simplexml_load_file - php

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.

Related

take one in foreach loop instead of all

I use the code below to iterate all div's on a page with id = news using PHPScraper. Is it possible to only take the first div it find so that the array only contains one entry? I was thinking of maybe (if possible) only take one in the foreach loop like you can do in c# (myList.Take(1))
$dom = file_get_html('http://localhost/test.html');
//collect all news entries into an array
$myArray = array();
if(!empty($dom)) {
$divClass = $title = '';
foreach($dom->find("div[id*=news]") as $divClass) {
You can use break to stop the loop from continuing after you've added the first div.
Something like this:
foreach($dom->find("div[id*=news]") as $divClass) {
$myArray[] = $divClass; // Just assuming you're doing something like this
break;
}
Side note: The code $divClass = $title = ''; before the loop doesn't serve any purpose in your posted code. The variable $divClass will be completely overwritten on each iteration of your foreach.
I'm guessing you're using PHP Simple HTML DOM Parser.
To grab only one element, you can simply pass 0 as the second argument of find:
$firstDiv = $dom->find('div[id*=news]', 0);
foreach($dom->find("div[id*=news]") as $divClass) {
/// work here
break;
}
break; statement is used to stop loop from further processing. So if you use it directly then loop would only execute once.

PHP while inside while

Let's say I'm trying to combine items from two lists, and I want to get this result:
A7
A8
B7
B8
This is my code:
<?php
$list1_array = array('A', 'B');
$list2_array = array('7', '8');
while(list( , $item1) = each($list1_array)) {
while(list( , $item2) = each($list2_array)) {
echo $item1.$item2."<br />";
}
}
?>
I get this result:
A7
A8
I seems like outside 'while' doesn't make the second loop?
What am I doing wrong?
While it might be better to use a slightly more common (perhaps more readable) approach (e.g. by using foreach loops as shown by GolezTrol,) in answer to your original questions:
The problem is most likely happening because the internal "cursor" (or "pointer") for your array is not being reset... so it never gets back to the start of the original array.
Instead, what if you try something like this:
<?php
$list1_array = array('A', 'B');
$list2_array = array('7', '8');
while(list(,$item1) = each($list1_array)) {
while(list(,$item2) = each($list2_array)) {
echo $item1.$item2."<br />";
}
reset($list2_array);
}
?>
Why not use foreach?
foreach ($list1_array as $item1)
{
foreach ($list2_array as $item2)
{
echo $item1.$item2."<br />";
}
}
Using a while loop with each makes the loop depend on the array pointer. An array has a pointer that tells you which item is the 'current' one. You can use functions like current to get the current item in the array. each is also such a function. It returns the current item (or actually an array with the key and value of the current item).
And therein lies the problem. The inner while loop stops when you are at the end of the array. So for the first item of the outer array (array1), the inner while loop (array2) runs fine. But the second time, the pointer is still at the end of the array and each returns false right away.
So, the solution could be to reset the array pointer, using the reset function as sharply pointed out by #summea. Or you can use a foreach loop, which is not affected by this fenomenon, because it resets the array pointer itself when it starts. Also, I this it's more readable, especially due to the weird list construct. Nevertheless, it might be good to know how the internals work, and your while loop works more low-level than foreach.

Adding up the TOTAL number of XML Items with 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];

Pushing values from a $_Get query to a value using implode

I am attempting to use a for loop or for each loop to push the values from a get query to another variable. May I have some help with this approach?
Ok here is where I am:
for ($i = 0 ; i < $_GET['delete']; i++) {
$_jid [] = $_GET['delete'];
}
You don't actually need a loop here. If $_jid already is an array containing some values, consider just merging it with $_GET['delete'].
if (is_array($_jid)) {
$_jid = array_merge($_jid, $_GET['delete']);
}
If $_jid is not an array and doesn't exist except as a container for $_GET['delete'] you do can just assign the array. There is no need to loop at all.
$_jid = $_GET['delete'];
Of course in that case, you don't even need to copy it. You can just use $_GET['delete'] directly, in any context you planned to read from $_jid.
Update:
If the contents of $_GET['delete'] are originally 923,936, that is not an array to begin with, but rather a string. If you want an array out of it, you need to explode() it on assignment:
$_jid = explode(',', $_GET['delete']);
But if you intend to implode() it in the end anyway, there's obviously no need to do that. You already have exactly the comma-delimited string you want.
As you can see if you do a var_dump($_GET), the variable $_GET is a hashmap.
You can easily use a foreach loop to look through every member of it :
foreach($_GET as $get) // $get will successively take the values of $_GET
{
echo $get."<br />\n"; // We print these values
}
The code above will print the value of the $_GET members (you can try it with a blank page and dull $_GET values, as "http://yoursite.usa/?get1=stuff&get2=morestuff")
Instead of a echo, you can put the $_GET values into an array (or other variables) :
$array = array(); // Creating an empty array
$i = 0; // Counter
foreach($_GET as $get)
{
$array[$i] = $get; // Each $_GET value is store in a $array slot
$i++;
}
In PHP, foreach is quite useful and very easy to use.
However, you can't use a for for $_GET because it's a hashmap, not an array (in fact, you can, but it's much more complicated).
Hope I helped

PHP While loop only echoes once

this is the PHP code i have:
while($row1 = mysql_fetch_object($query1)) {
echo "*".$row1->id."*";
while ($row2 = mysql_fetch_object($query2)) {
echo "%".$row2->id."%";
}
}
I want it to output for example: *1*%1%%2%%3%%4%*2*%1%%2%%3%%4%*3*%1%%2%%3%%4%
But what this loop outputs is: *1*%1%%2%%3%%4%*2**3*
(It only outputs the $row2 values in the first loop of $row1.
How can I fix this? Thanks.
A few things to note about mysql_fetch_object(). From the PHP document:
Warning: This extension is deprecated as of PHP 5.5.0
Please note above.
returns an object with properties that correspond to the fetched row and moves the internal data pointer ahead.
Please note what I bolded.
The $result object (in your code this would be $query2) is an iterative object that has a pointer pointing to the current item.
Current Item
|
v
[1][2][3][4]
When your first loop hits your second loop, it iterates over the whole thing, such that at the end, the object now looks something like this:
Current Item
|
v
[1][2][3][4]
For each iteration of the first loop, after the first time, the mysql_fetch_object() function basically goes like this:
mysql_fetch_object() ~
1. Get the next time
2. Uh, there are no more objects because we're at item [4]. Return done.
So, how do you get it to work? You could simply save the results into an array and then iterate over that array or you can reset the pointer with mysql_data_seek() (which is also deprecated as of 5.5).
To reset the data pointer, it would be something like this:
while($row1 = mysql_fetch_object($query1)) {
echo "*".$row1->id."*";
while ($row2 = mysql_fetch_object($query2)) {
echo "%".$row2->id."%";
}
// put the result pointer back to the front
mysql_data_seek($query2, 0)
}
Note1, This SO question/answer helped me find the function to use to reset the pointer.
Note, the downside is that you're calling a function that's creating an object, which creates processing overhead every time it runs.
The other option would be save the results into an array and just loop through the array every time:
$secondary_result = array();
while ($row2 = mysql_fetch_object($query2)) {
$secondary_result[] = $row2;
}
while($row1 = mysql_fetch_object($query1)) {
echo "*".$row1->id."*";
foreach($secondary_result as $row2) {
echo "%".$row2->id."%";
}
}
Note, this method will be creating extra memory usage of storing the objects in an array, but it would save on CPU processing as you're not re-creating the objects over and over again, as well as calling a function.
If you just print output, you can consider just saving the result first. No matter now many times you loop over $secondary_result, the final result will always be the same (as per your code, the first loop shows no signs of being directly influencing the second result).
In that case, this makes much more sense
$buffer = '';
while ($row2 = mysql_fetch_object($query2)) {
$buffer .= "%".$row2->id."%";
}
while($row1 = mysql_fetch_object($query1)) {
echo "*".$row1->id."*";
echo $buffer;
}
but I really don't know why you'd do that. If you're doing a nested loop, usually it's because the result of the first loop is affecting the second loop.
But I hope that helps!
Cheers!
EDIT
Per #Blazemonger's comment about looking ahead, the PDO equivalent would be: MySqli:Fetch-Object
When you have a result object from using the PDO function, you would loop like this:
while($row1 = $query1->fetch_object()) {
echo "*".$row1->id."*";
while ($row2 = $query1->fetch_object()) {
echo "%".$row2->id."%";
}
// put the result pointer back to the front
$query2->data_seek(0);
}
The above example shows both the fetch Object and pointer reset versions of MySqli.
The problem is that once you iterate fully through $query2, that's the end of your results. The next time through your $row1 loop, you're still at the end of $query2 and have no results left. Try using mysql_data_seek to go back to the start of your results:
while($row1 = mysql_fetch_object($query1)) {
echo "*".$row1->id."*";
mysql_data_seek($query2, 0);
while ($row2 = mysql_fetch_object($query2)) {
echo "%".$row2->id."%";
}
}
if you really need to repeat your second query data many times, get it into array first, and loop over this array as many times as you need.
First of all: The mysql_* functions are deprecated and will be removed in PHP 5.5. Consider using mysqli or PDO instead.
That being said; back to your question:
Each result set contains an internal pointer to one of the records in the result set. Initially, this pointer points to the first record, and is advanced with each call to mysql_fetch_object.
After your first inner loop, the internal pointer of the $query2 result set will already be at the end of the list, so subsequent calls to mysql_fetch_object will only return FALSE.
If your inner query depends on values from $row1, you will need to re-execute the second query within your outer loop. Otherwise, you can reset the result pointer with mysql_data_seek.
Perhaps you're not getting anything when you call $row2 = mysql_fetch_object($query2) which would give you the output you're getting.
After the first loop there are no more results for query2 to return. So the while is false in each additional loop. You would want to reset the query with mysqli_data_seek or storing all the data in a separate array and looping through that instead.
Please also note:
Per the documentation http://us2.php.net/manual/en/function.mysql-fetch-object.php
The mysql extension is deprecated as of PHP 5.5.0, and will be removed
in the future. Instead, the MySQLi or PDO_MySQL extension should be
used

Categories