I am REALLY not getting arrays at all, I have read many examples, most plagiarized and amended, am an yet to find help that I understand I do hope someone can walk me through this, so I understand fully.
I have an XML file, which I need to read and display with options to sort using PHP, then output the required fields into my page(s). I have managed to retreive the XML file and rehouse locally and check the age of the file (milestone) and using the code (below) have managed to read the XML file and output as an array, but I can get no further and after two days I turn to you the community for assistance:
<?php
function std_class_object_to_array($stdclassobject) {
$_array = is_object($stdclassobject) ? get_object_vars($stdclassobject) : $stdclassobject;
foreach ($_array as $key => $value) {
$value = (is_array($value) || is_object($value)) ? std_class_object_to_array($value) : $value;
$array[$key] = $value;
}
return $array;
}
$request = $domain.$filename;
$API_results = file_get_contents($request);
$xml = new SimpleXMLElement($API_results);
$Details = std_class_object_to_array($xml);
echo "<pre>";
print_r($Details[hotel]);
echo "</pre>"; ?>
The Output looks like this (shortened)
Array
(
[0] => Array
(
[hotel_ref] => 157258
[hotel_name] => Hotel Kong Arthur
continued
[1] => Array
(
[hotel_ref] => 98813
[hotel_name] => Hotel Lautruppark
Firstly is the code I have used for reading the XML good? Is there a better way that could be used? How do I sort the results? How do I output the individual fields?
Your help, examples and direction would be greatly appreciated,
Stu
//----------------------- UPDATE ----------------------- \
OK, so this is where I am at now with the suggestion to use SimpleXML, but its still not right and I am not really a great deal further on:
$request = $domain.$filename;
$xmlobj = simplexml_load_file($request);
$xml = simplexml_load_file($request) or die("NO XML");
foreach($xml as $hotels)
echo $hotels->hotel_name." (".$hotels->hotel_ref.")<br/>";
The code you have written for reading the XML is absolutely fine.
However, you are unnecessarily converting from a SimpleXMLElement object to an array, as SimpleXMLElement is already iterable. You can access the <hotel> element of the XML as simply as:
$Details->hotel[0]
You can iterate through the child elements of <hotel> by the following:
<?php
// Loop through the elements, and with each...
foreach($Details->hotel[0] as $index => $hotel) {
// ...output the name of the hotel:
echo $hotel->hotel_name;
}
?>
Here, $index will be the numeric index, and $hotel will be another SimpleXMLElement.
N.B. In terms of sorting the results, it might actually be worth doing the object-to-array conversion. All of the sorting functions in PHP work on arrays, not objects.
Hope this helps!
Related
Any idea on how to restructure the json below:
$jsonArray = [{"Level":"77.2023%","Product":"Milk","Temperature":"4"},
{"Level":"399.2023%","Product":"Coffee","Temperature":"34"},
{"Level":"109.2023%","Product":"Chocolate","Temperature":"14"}]
Expected outcome:
$expected = {"Milk":{"Level":"77.2023%","Temperature":"4"},
"Coffee":{"Level":"399.2023%","Temperature":"34"},
"Chocolate":{"Level":"109.2023%","Temperature":"14"}
}
I'm new and my thinking is get the product value in array and again use foreach loop to find the others value? .
Here's one possibility:
$jsonArray = '[{"Level":"77.2023%","Product":"Milk","Temperature":"4"},
{"Level":"399.2023%","Product":"Coffee","Temperature":"34"},
{"Level":"109.2023%","Product":"Chocolate","Temperature":"14"}]';
$output = array();
foreach (json_decode($jsonArray, true) as $row) {
$product = $row['Product'];
$output[$product] = $row;
unset($output[$product]['Product']);
}
echo json_encode($output);
Output:
{"Milk":{"Level":"77.2023%","Temperature":"4"},
"Coffee":{"Level":"399.2023%","Temperature":"34"},
"Chocolate":{"Level":"109.2023%","Temperature":"14"}
}
Demo on 3v4l.org
This made some trick
$a = '[{"Level":"77.2023%","Product":"Milk","Temperature":"4"},
{"Level":"399.2023%","Product":"Coffee","Temperature":"34"},
{"Level":"109.2023%","Product":"Chocolate","Temperature":"14"}]';
$newAr = array();
foreach(json_decode($a,true) as $key=>$value)
{
$newAr[$value['Product']] = array(
'Level' => $value['Level'],
'Temperature' => $value['Temperature'],
);
}
There are many ways to perform this with Loops in PHP. Other answers demonstrate it accurately. I would also suggest to integrate some form of Error handling, data validation/filtering/restriction in your code to avoid unexpected results down the road.
For instance, json_decode(), either assigned to a variable pre-foreach or straight in the foreach() 1st argument will just raise a warning if the original json is not valid-json, and just skip over the foreach used to construct your final goal. Then if you pass the result (that may have failed) directly to your next logic construct, it could create some iffy-behavior.
Also, on the concept of data-validation & filtering, you could restrict the foreach(), or any other looping mechanism, to check against a Product_List_Array[Milk,Coffee,Chocolate], using if(in_array() ...) so the final/goal object only contains the expected Products, this, in the case the original json has other artifacts. Filtering the values can also increase stability in restricting, for example, Temperature to Float.
Here is a fairly big object dumped using print_r.
https://docs.google.com/document/d/175RLhWlMQcyhGR6ffGSsoJGS3RyloEqo4EEHCL2H2vg/edit?usp=sharing
I am trying to change the values of the uploaded_files.
Towards the end of that object you'll see something like
[uploaded_files] => Array
(
[attachment] => /home2/magician/public_html/development/testing/wp-content/uploads/wpcf7_uploads/Central-Coast-Montessori-logo.jpg
[attachment2] => /home2/magician/public_html/development/testing/wp-content/uploads/wpcf7_uploads/Andrew.jpg )
My code
// move the attachments to wpcf7ev temp folder
foreach ($cf7ev_object['uploaded_files'] as $key => $uploaded_file_path) {
$new_filepath = WPCF7EV_UPLOADS_DIR . '/' . basename($uploaded_file_path);
wpcf7ev_debug("New file path is {$new_filepath}");
rename($uploaded_file_path, $new_filepath);
wpcf7ev_debug("'{$key}'is the KEY for {$uploaded_file_path}");
wpcf7ev_debug($cf7ev_object['uploaded_files']);
$cf7ev_object['uploaded_files'][$key] = $new_filepath; // this is not updating
}
To loop through it I have been using
foreach ($cf7ev_object->uploaded_files as $key => $uploaded_file_path) {
and this has worked.
But shouldn't it be
foreach ($cf7ev_object['uploaded_files'] as $key => $uploaded_file_path) {
? As '->' is for accessing methods?
And specifically I want to update the values of those uploaded_files, so to do that I need to do
$cf7ev_object['uploaded_files'][$key] = $new_filepath; // this is not updating
? But this doesn't seem to be working.
I think I need to be clear on how to access values in an object.
Thanks.
First of all, regarding the single arrow "->" that is how you reference an objects values. But I won't get into that. Since you say it works, $cf7ev_object is obviously an object.
You say you want to "access the values in the object".
var_dump($cf7ev_object);
This will spit out what is in that object. I gather you are a bit of a newbie, so I will try to help you out best I can with the limited data you provided (you may want to expand your question.
Looping is not a one-shot deal. You can have nested loops and nested loops inside of those. However, it is a resource hog if you're not careful. Here is an exercise that might help you.
$new_array = array();
foreach($cf7ev_object->uploaded_files as $key => $value) {
$new_value = $value;//do something to the $value here
$new_array[$key] = $new_value;
}
//take a look at your work now:
print_r($new_array);
I hope this helps. Note: your google doc is restricted, public can't see it.. And your question is too vague. Let me know if I can help more.
If you want to change the object array values instantly you just set it equal to the above loop result:
$cf7ev_object->uploaded_files = $new_array;
So I used JSON to obtain a multidimensional array. What I'm trying to do is for each listing in the main part of the array (not sure what the technical term is) access the part of the array that is below. I would then like to echo each one of these links.
As you can probably see I'm trying to scrape the images. How do I go about doing this? I love to learn so some hints at first would be greatly appreciated. Thanks guys!
[url] => http://imgur.com/0q4G4qP
Json code
<?php
$jsonurl = "http://www.reddit.com/r/pics.json";
$data = file_get_contents($jsonurl);
$array = json_decode($data, true);
echo "<pre>";
print_r($array);
echo "</pre>";
I am not entirely sure how to do this. I referenced the php manual on how to access these types of arrays, but I'm a bit lost. Basically for everyone of those children.
You can do this:
foreach ($multi_d_array['data']['children'] as $item) {
echo $item['data']['url'].'<br/>';
}
Use foreach in loops foreach($data as $d) { echo $d['url'] ;}
I need help moving through the large array returned by the Facebook PHP SDK. I am trying to find all posts from the user, then also check if the post does/doesn't contain the 'link' key. I have read that it is inefficient to use the foreach loop on arrays of this size due to the copying of the 1MB+ of data to process it. How should I traverse through the information effectively?
The array is structured like this, where 'x' is the number of each post:
Array
(
[data] => Array
(
[x] => Array
(
[from] => Array
(
[name] => james
)
[message] => Thanks for the great interview!
[link] => http://example.com/link.html
[description] => Description here
[etc] => Various other keys possible
)
)
)
Then my current code looks like this where $feed is the array from the Facebook API:
for ($x=0, $y=0; $x<=1000, $y<=19; $x++) {
if (array_key_exists('james', $feed['data'][$x]['from']['name'])) {
if (!array_key_exists('link', $feed['data'][$x])) {
echo "<div>" . $feed['data'][$x]['message'] . "<hr>" . $feed['data'][$x]['description'] . "</div>";
$y++;
};
};
};
I have read about the various iterators but I wouldn't know which to use! Hope you can help me out, cheers, Joe
Speaking about foreach performance
and using array_key_exists in actual fact it's a non sense
imho it's far better like
foreach($feed['data'] as $post){
if($post['from']['name']==='youruser'){
//has user
}
if(isset($post['link'])){
//has link
}
}
put it in the cillosis way
and it should be faster.
You are correct in the fact that foreach can be slow when iterating over large arrays because by default it uses a copy of the value and like you mentioned, that copying can consume memory and take a bit of a time hit.
But, another way to use foreach is by reference which does not create a copy. It works with the original value. This means no matter what size the array is, it won't be placed into memory again. Here is an example of a foreach by reference as shared by another StackOverflow user:
$a = array('hello', 'world');
$asRef =& $a;
$ontime = 0;
foreach($asRef as $i => $v)
{
if (!$ontime++) $a = array('hash', 'the cat');
echo " $i: $v\n";
}
You have the option of using the ArrayIterator from the SPL which is written in C and is pretty fast. Just a quick example of how that would work:
// This would be your large facebook array
$big_array = array(1,2,3,...,10000,10001);
// Get the iterator object
$array_iterator = new ArrayIterator($big_array);
foreach($array_iterator as $item)
{
//Do something with $item here
}
I've not done any benchmarking but I would imagine passing the array by reference and using the ArrayIterator would probably be a good solution.
foreach doesn't always copy. when it does copy, it copies only the immediate data structure being iterated; it doesn't copy any values. for example, if you did
foreach ($arr['data'] as $k => $v) ....
if there were 100 sub elements (you abbreviated one as [x] ), then it would make an array, copy those 100 keys, but would not copy the values that the keys point to, the values being the sub arrays/trees. internally it just stores a pointer and has it point to the subarray's memory address, without copying.
I think you're making a big deal for nothing, as the amount of data that actually gets copied is very little. foreach is almost always very very fast...
if you want to glimpse, look at memory_get_usage() and memory_get_peak_usage() before and after your loop.
I want to convert a xml script into a associative array in PHP. The XML script is :
<ages>
<Peter>
<Peterchild>4</Peterchild>
<Peterchild>6</Peterchild>
</Peter>
<Quagmire>30</Quagmire>
<Joe>34</Joe>
</ages>
and the code i wrote for converting it to an array is
${$xml->getName()} = array();
foreach($xml->children() as $child){
$ages[$child->getName()] = (string)$child;
}
which gives the output as
Array
(
[Peter] =>
[Quagmire] => 30
[Joe] => 34
)
The problem is that I am unable to figure out a condition to recursively traverse through the children of children (children of Peter in this example). How to I change this code to consider those nodes as well?
You'll need to create a function that parses one level, then have the function call itself when it finds a node inside the current level. It's pretty complex and can get messy. Out of curiosity, why would you do this when you can access all the information you need in object format using a SimpleXML object?
${$xml->getName()} = array();
foreach($xml->children() as $child)
{
if (count($child->children() > 0)
{
foreach ($child->children as $childnode)
{
$ages[$childnode->getName()] = (string)$childnode;
}
}
else {
$ages[$child->getName()] = (string)$child;
}
}
This will only work if it is 1 level deep, if it is going to be more levels you should write a function, that will cycle through it level by level.