Importing external XML file with PHP, summing values - php

Like the title says, I'm importing an external XML file into a site. It's actually weather data from observation sites around the world. I can parse and display the data no problem. My problem is I'm trying to sum up a specific set of data.
Here's the basic code:
<?php
$xml = simplexml_load_file('https://aviationweather.gov/adds/dataserver_current/httpparam?dataSource=metars&requestType=retrieve&format=xml&stationString=kbwi&hoursBeforeNow=65');
for($i=0;$i<=60;$i++)
{
$precip[$i] = $xml->data->METAR[$i]->precip_in;
echo $precip[$i];
}
?>
This will echo all the values from 'precip_in' from the XML file, and it does work. But if I try to sum up the data in $precip or in 'precip_in' by using array_sum, I get a blank page. Using var_dump returns "NULL" a bunch of times.
Now, I could manually sum the values by doing something like:
$rainTotal = $precip[0]+$precip[1]+$precip[2];
But one thing I want to do with this is a 24 hour rainfall total. The observations aren't always updated at regular or hourly intervals; meaning that if I were to do something like this:
$rainTotal = $precip[0]+$precip[1]+$precip[2]...+$precip[23];
It would not necessarily give me the 24 hour rain total. So, I need a way to sum all the rainfall values contained within 'precip_in' or $precip.
Any ideas on how I should proceed?
EDIT: Some clarifications based on the comments below:
Echoing and var_dump-ing $precip[$i] work fine. But if I try the following:
<?php
$xml = simplexml_load_file('https://aviationweather.gov/adds/dataserver_current/httpparam?dataSource=metars&requestType=retrieve&format=xml&stationString=kbwi&hoursBeforeNow=65');
for($i=0;$i<=60;$i++)
{
$precip[$i] = $xml->data->METAR[$i]->precip_in;
echo array_sum($precip[$i]);
}
?>
I get a blank page. Doing a var_dump of array_sum($precip[$i]) results in "NULL" a bunch of times in a row.
I have tried casting the XML string as either a float or a string, but I get the same results.

the value of $xml->data->METAR[$i]->precip_in is an object ((SimpleXMLElement)#12 (1) { [0]=> string(5) "0.005" }). It's not numeric, so it has no numeric value. You can cast this to a float however and get the numeric value your were expecting.
for($i=0;$i<=60;$i++)
{
$precip[$i] = (float)$xml->data->METAR[$i]->precip_in;
echo $precip[$i];
}
These float values can be summed.

Consider an array_sum on an XPath array return:
$xml = simplexml_load_file('https://aviationweather.gov/adds/dataserver_current/httpparam?dataSource=metars&requestType=retrieve&format=xml&stationString=kbwi&hoursBeforeNow=65');
$result = array_sum(array_map("floatval", $xml->xpath('//METAR/precip_in')));
echo $result;
// 10.065
Alternatively you can use XPath's sum() which requires using DOMDocument and not SimpleXML, specifically DOMXPath::evaluate:
$dom = new DOMDocument;
$dom->load('https://aviationweather.gov/adds/dataserver_current/httpparam?dataSource=metars&requestType=retrieve&format=xml&stationString=kbwi&hoursBeforeNow=65');
$xpath = new DOMXPath($dom);
$sum = (float)$xpath->evaluate('sum(//METAR/precip_in)');
echo $sum;
// 10.065

Related

Finding titles in JSON

I currently have this large JSON file: hastebin
But just want the titles of the posts.
I've tried this...
$json = $page;
$o = json_decode($json, true);
echo($json);
$titles = $o["*"]["*"]["*"]["*"]["title"];
var_dump($titles);
But it isn't working - it's returning NULL! Sometimes it just doesn't return anything.
If anyone is wondering, yes this is from Reddit.
This should do it:
$titles = array_map(function($post) {
return $post['data']['title'];
}, $o['data']['children']);
I'm not sure what you expected using "x" indices, but you should probably read about arrays.
PHP can't use wildcards like * in array keys. Whatever string you use to reference the key, it's going to try to find a key with that exact string. So what you tried can't work because there aren't any * keys.
You can get it by iterating all the levels, or iterating the outer level and referring to the proper nested key. But if you're just looking for all instances of 'title' a recursive method may be an easier way to get them.
array_walk_recursive($o, function($value, $key) use (&$titles) {
if ($key == 'title') $result[] = $value;
});
var_dump($titles);
This will get any value of 'title' regardless of its depth in the array, so if that's not what you want, then you'll need to iterate it and specifically reference the proper ones.
It's very hard to deal directly with such a long JSON document. The returned result from the page is not a valid JSON. It contains some HTML tags, but if you take the posts data and insert it in a file you can do the following according to the structure of your JSON (You can find your JSON in an external link here):
<?php
header("Content-Type:application/json");
$posts=file_get_contents('json.php');
//decode your JSON STRING
$posts=json_decode($posts,true);
//create a title variable to store your titles
$titles=array();
foreach($posts['data']['children'] as $child)
{
array_push($titles,$child['data']['title']);
}
echo json_encode($titles);
?>
You can even use this approach using a URL but ensure that it will return a valid JSON with no html

Serialized multidimensional stored in MySQLi does not print past first array

Confusing title, the basics are that I'm saving a fully sorted and ordered multidimensional array from a script and into MySQL. I then, on another page, pull it from the database and unserialize it, and then proceed to print it out with this,
$s = "SELECT * FROM gator_historical_data WHERE channelid = '{$chanid}'";
$r = $link->query($s);
$comboarray = array();
while ($row = mysqli_fetch_assoc($r)) {
$comboarray[] = unserialize($row['dataarray']);
}
foreach ($comboarray as $item) {
$desc = $item['content']['description'];
$title = $item['content']['title'];
$datetime = $item['datetime'];
// ... ^^^ problems getting array data
}
The problem is that it doesn't take the full array from MySQL, only the first entry and thus only prints the first 'array'. So where the returned value from dataarray looks like this (var_dump): http://pastebin.com/raw.php?i=Z0jy55sM the data stored into the unserialized $comboarray only looks like this (var_dump): http://pastebin.com/raw.php?i=Ycwwa924
TL;DR: Pulling a serialized multidimensional array from a database, unserializing and it loses all arrays after the first one.
Any ideas what to do?
The string you've got is a serialized string plus something more at the end that is also a serialized string again and again:
a:3:{s:6:"source";s:25:"World news | The Guardian";s:8:"datetime ...
... story01.htm";}}a:3:{s:6:"source";s:16:"BBC News - World";
^^^
This format is not supported by PHP unserialize, it will only unserialize the first chunk and drop everything at the end.
Instead create one array, serialize it and store that result into the database.
Alternatively you can try to recover for the moment by un-chunking the string, however in case the paste was done right, there are more issues. But on the other hand the paste obvious isn't the done fully correct.

SimpleXML node casting to string not working

I am trying to get a currency rate from this XML file:
http://www.bank.lv/vk/xml.xml
I am getting a currency ID from a HTML form, after that I have to find it according currency rate.
I am using SimpleXML and XPath, my selection is as follow:
$current_rate = $rates->xpath("/CRates/Currencies/Currency[ID='" .$source_currency ."']/Rate");
$source_currency is tested and valid, however, when casting $current_rate to (string), I get the word Array.
Do I have a mistake in the XPath node selection or somewhere else?
$current_rate = $rates->xpath("/CRates/Currencies/Currency[ID='" .$source_currency ."']/Rate");
Will return an array even if just 1 result is returned, if you use print_r you can see what is returned:
print_r($current_rate);
To access it you will have to use:
if (isset($current_rate))
{
echo $current_rate[0];
}
Or if there is the possibility of having more than 1 result for that given $source_currency:
foreach ($current_rate as $rate)
{
echo $rate, "\n";
}

parse GeoJson String in PHP

I want to get polygon coordinates from below String.
{"polygon":{"type":"Feature","properties":[],"geometry":{"type":"Polygon","coordinates":[[[-7302732.4720101,6527844.6333235],[-3193477.8319711,6606116.1502766],[-5111129.9973226,5001550.0527375],[-6637424.5779086,4884142.7773079],[-7772361.5737289,5158093.0866438],[-7302732.4720101,6527844.6333235]]]},"crs":{"type":"name","properties":{"name":"urn:ogc:def:crs:OGC:1.3:CRS84"}}}}
This is GeoJson string that i decode to array with below code:
$polygon = CJSON::decode($str);
when i want to get polygon i get error!
$var= $polygon->polygon;
or with below code:
$polygon = CJSON::decode($str,true);
$var = $polygon['polygon'];
although for getting coordinates:
foreach($polygon as $key=>$value)
$coordinates = $value['coordinates'];
or
$coordinates = $value[coordinates];
how can i get coordinates from geojson that i send from javascript to php for saving on postgresql with postgis?
$polygon->polygon->geometry->coordinates[0]
or
$polygon['polygon']['geometry']['coordinates'][0]
what you have is a multidimensional array/object not sure which its being output to when decoded in your case as it appears you have a class doing it I would have just used json_decode, but anyway. Yea from the looks of it, polygon is the main object, then in it is geometry which is an object that has type and coordinates, and then coordinates has multiple objects/arrays in it.
the above samples if I typed them right will show the first set of coordinates in that object. Of course you could run it through a loop ie:
In the case that it is an object assuming your Class decodes as an object and not an array. Not exactly sure what $polygon = CJSON::decode($str,true); does. But if its anything like json_decode() then you should be all set.
This is my method of breaking down the object as you present here, its worth noting you may want to check counts, and see if the object is set first, or if the property exists in the object to prevent other means of the code breaking down the road. But what I have here is just pure example at its core, it will server its purpose though. But will not error handle which is why I say you may want to elaborate further on it doing those checks.
Anyway heres my code:
<?php
$str = '{"polygon":{"type":"Feature","properties":[],"geometry":{"type":"Polygon","coordinates":[[[-7302732.4720101,6527844.6333235],[-3193477.8319711,6606116.1502766],[-5111129.9973226,5001550.0527375],[-6637424.5779086,4884142.7773079],[-7772361.5737289,5158093.0866438],[-7302732.4720101,6527844.6333235]]]},"crs":{"type":"name","properties":{"name":"urn:ogc:def:crs:OGC:1.3:CRS84"}}}}';
$polygon = json_decode($str);
echo'<pre>';print_r($polygon);echo'</pre>';
$set = 1;
foreach($polygon->polygon->geometry->coordinates[0] as $coordinates)
{
echo 'Set '.$set.': ';$set++;
echo $coordinates[0].','.$coordinates[1].'<br>';
}
?>
see it in action http://7pz.net/geojson-parse.php (scroll to the bottom)
This should give you an array of all the coordinates and print them out line by line:
$string = '{"polygon":{"type":"Feature","properties":[],"geometry":{"type":"Polygon","coordinates":[[[-7302732.4720101,6527844.6333235],[-3193477.8319711,6606116.1502766],[-5111129.9973226,5001550.0527375],[-6637424.5779086,4884142.7773079],[-7772361.5737289,5158093.0866438],[-7302732.4720101,6527844.6333235]]]},"crs":{"type":"name","properties":{"name":"urn:ogc:def:crs:OGC:1.3:CRS84"}}}}';
$json = json_decode($string);
$coords_array = $json->polygon->geometry->coordinates[0];
foreach($coords_array as $c_a) {
echo $c_a[0] . "," .$c_a[1] . "<br>";
}
Access with:
$coords_array[0];
$coords_array[1];
$coords_array[2];
etc.
Basically you can turn the JSON string into an object and access each element with the -> notation.
I usally use a site called http://jsonviewer.stack.hu/ to decode JSON and find the path I need, then simply write them out as they appear, as in as in the above - $json->polygon->geometry->coordinates;.
Try it out yourself on the site.

XPATH - get single value returned instead of array php

I am using Xpath in PHP - I know that my query will return either 0 or 1 results.
If 1 result is returned I do not want it as an array - which is what is returned right now. I simply want the value without having to access the [0] element of the result and cast to a string.
Is this possible?
If 1 result is returned I dont want it as an array - which is what is returned. I simply want the value without having to access the [0] element of the result and cast to a string.
That is possible with XPath's string function
A node-set is converted to a string by returning the string-value of the node in the node-set that is first in document order. If the node-set is empty, an empty string is returned.
and DOMXPath's evaluate method:
Returns a typed result if possible or a DOMNodeList containing all nodes matching the given XPath expression.
Example:
$dom = new DOMDocument;
$dom->loadXML('<root foo="bar"/>');
$xp = new DOMXPath($dom);
var_dump($xp->evaluate('string(/root/#foo)')); // string(3) "bar"
If there was a built in xpath way of grabbing the first and only the first node value then that would be much more preferable over writing a function to do it
You can use the position function:
The position function returns a number equal to the context position from the expression evaluation context.
Example:
$dom = new DOMDocument;
$dom->loadXML('<root><foo xml:id="f1"/><foo xml:id="f2"/></root>');
$xp = new DOMXPath($dom);
var_dump($xp->evaluate('string(/root/foo[position() = 1]/#xml:id)')); // string(2) "f1"
or the abbreviated syntax
$dom = new DOMDocument;
$dom->loadXML('<root><foo xml:id="f1"/><foo xml:id="f2"/></root>');
$xp = new DOMXPath($dom);
var_dump($xp->evaluate('string(/root/foo[1]/#xml:id)')); // string(2) "f1"
Note that when querying for descendants with // using the position function might yield multiple result due to the way the expression is evaluated.
Using 'evaluate' instead of 'query', you can do things like casting.
DOMXPath::evaluate()
Also, if you're just annoyed with doing stuff a lot of times, just write a function that does it ... that is the whole idea behind functions, right?
probably
if ($array[0]){
$string = $array[0];
}
?
if $array[0] is an array, you can rename string to new_array
if ($array[0]){
$new_array = $array[0];
}
Your question suggests that you are using SimpleXML because you talk about an array. However long-time ago you accepted an answer giving an answer with DOMDocument. In any case other users go here looking for a solution in SimpleXML it works a little differently:
list($first) = $xml->xpath('//element') + array(NULL);
The element in $first if not NULL (for no elements) then still will be of type SimpleXMLElement (either an element node or an attribute node depending on the xpath query), however you can just cast it to string in PHP and done or you just use it in string context, like with echo:
echo $first;
You can write it most simply like this:
$string = #$array[0];
The # operator will suppress errors, making $string null if $array is empty.

Categories