Jump to content

Order filtered values from XML


Texan78

Recommended Posts

Hello, I have been struggling with this for months and please be gentle as I am not a coder. Just a hobbyist trying to build a site for my brand. I know just enough to try to do what I need to do so I certainly do not know the best logic. I have been search for months and months for how to do this. I have three events I need to show in a certain order when they display. 

 

1.) Tornado Warning

2.) Severe Thunderstorm Warning

3.) Flash Flood Warning

 

I have them filtered but I am probably not using the best logic for this approach. Is there anyone who could offer some assistance and help me out with ordering these by severity as I have posted above so I can mark this little section as completed. 

 

-Thanks hugely!!!

ini_set('display_errors','1');



## Start Configurable data ##


//Set message to display if there were not report
$noStormMessage = 'There are currently no active severe weather alerts';


//Set path to data file
#$data = "http://alerts.weather.gov/cap/".$zone.".php?x=0";
$data = "../xml/nat_warnings.xml";


## End Configurable data ##


// get path info & protect for cross-site scripting vulnerability
$sri = ($_SERVER['REQUEST_URI']) ? str_replace('#SA', '', htmlspecialchars(strip_tags($_SERVER['REQUEST_URI']))) : '';


$error = false;


//Set initial output to false
$AlertData = false;
$entries = simplexml_load_file($data);
if(count($entries)):
    //Registering NameSpace
    $entries->registerXPathNamespace('prefix', 'http://www.w3.org/2005/Atom');
    $result = $entries->xpath("//prefix:entry");
if(!$result){
$error = true;
}
    foreach ($result as $entry):
        $updated = $entry->updated;
if($updated == ''){
$error = true;
}
        $Updated = date("D, M d, g:i a", strtotime($updated));
        $summary = $entry->summary;
if($summary == ''){
$error = true;
}


  // Replaces all triple periods with single periods
        $summary = trim(str_replace('...', '.', $summary), '.') . '.';




  //now capitalize every letter after a . ? and ! followed by space
        $Summary = preg_replace_callback('/([.!?*])\s*(\w)/', function ($matches) {
            return strtoupper($matches[1] . ' ' . $matches[2]);
            }, ucfirst(strtolower($summary)));
        $event = $entry->children("cap", true)->event;
          if ($event == ''){
        $error = true;
        }
        $url = $entry->id;       
        $updated = $entry->updated;
        $link = $entry->link;
        $effective = $entry->children("cap", true)->effective;
        $expires = $entry->children("cap", true)->expires;
        $updated = date("l M jS, g:i A", strtotime($updated));
        $effectiveDate = date("l M jS, g:i A", strtotime($effective));
        $expiresDate = date("D M jS, g:i A", strtotime($expires));
        $status = $entry->children("cap", true)->status;
        $severity = $entry->children("cap", true)->severity;
        $urgency = $entry->children("cap", true)->urgency;
        $area = $entry->children("cap", true)->areaDesc;
   
        include ('alertColors.php');
        
  // Let's assign the table some styles
     $divNoStorms = "padding:5px; width:45%; margin:auto; margin-top:5px; margin-bottom:5px";


  // If no storms were in the source, set no storm message
if($error) {
     $AlertData .= "<div style='{$divNoStorms}' class='alert alert-info' role='alert' data-toggle='tooltip' data-placement='top' title='There are currently no active severe weather alerts.'>\n";
     $AlertData .= "{$noStormMessage}\n";
     $AlertData .= "</div>\n";                                                                                
} elseif ($event == 'Tornado Warning' || $event == 'Severe Thunderstorm Warning' || $event == 'Flash Flood Warning') {
    $AlertData .= "<div>\n";
    $AlertData .= "<div id='{$alertID}' class='individualAlert'>\n";
    $AlertData .= "<div class='text_alert'>\n";
    $AlertData .= "<span class='title {$alertClass}'><i class='fa fa-exclamation-triangle severe-icon__tornado'></i>{$event}</span>\n";
    $AlertData .= "<span class='state'>{$stateShort}</span>\n";
    $AlertData .= "<span class='counties'>{$area}</span>\n";
    $AlertData .= "<span class='expires'>Expires: {$expiresDate}</span>\n";
    $AlertData .= "</div>\n";
    $AlertData .= "<div class='alert__view'>\n";
    $AlertData .= "<a href='{$url}'><span class='fa fa-eye'></span></a>\n";
    $AlertData .= "</div>\n";
    $AlertData .= "</div>\n";
}
    $AlertData .= "</div>\n";


       endforeach;
endif;


echo $AlertData;
Link to comment
Share on other sites

If I can offer some unsolicited advice first:

1.  While PHP can parse conditionals in both the "Shell Script Style" and the "Curly Brace" style, mixing them is "Not Good Style".

2.  A better way to concatenate strings:

// instead of this
$foo = "Text";
$foo .= " and more text";
$foo .= " and still more text";

// try this
$foo = "Text"
       . " and more text"
       . " and still more text";

As for the main question, I wonder if the sections for displaying an error and displaying a warning could be placed in custom functions, say, "show_error()" and "show_warning($warning_data)".

You could then loop through the XML, placing the data in arrays and sorting them by "warning type" prior to output.  That might even allow you to separate the logic of the program from the display of the information more fully, a concept that falls under the grand title "Separation of Concerns", and is fairly common practice among well-engineered software projects.  By the same token, anyone who says they've never had logic and output mixed in the same area before is either lying, has a bad memory, or was privileged to be both a freakin' genius and working on a large team of similarly-brained individuals.

Not that this idea/design might not scale if you're doing a large geographical area or a large time window, but for one local region and current or fairly recent data, that shouldn't be a big problem.  Hope that this helps you a little.

Link to comment
Share on other sites

Thanks, I am not worried about the other right now. Each their own. 

 

Main focus is getting these sorted by priority and I have no idea how to do this and cannot find any examples. I have even been willing to PAY someone to do this since last November for what is probably less than 5 mins of work but can't find anyone. Is what I am asking that difficult? I didn't think it was that difficult, I see sites doing it all the time everyday. I have already tried the array approach and got shot down on here with it and could never get it working. 

Link to comment
Share on other sites

These are just some ideas.  I'm a low hours PHP pilot so I'm sure I'll get nuked. It's been sitting here awhile so no one can call me presumptuous.

 

These are the 'weather events' you are looking to report, correct?

Tornado Warning
Severe Thunderstorm Warning
Flash Flood Warning

These are contained in an XML structure and each 'weather event' has a lot information; things like: location,links,status...blah blah.  You want to order this data in a report ($AlertData) based on different things.

You could create weather event objects as you parse the XML and then sort the objects based on any parameter(s) you wish.
Take that object sort, iterate and build your $AlertData string.  If you've never done object stuff, this may be an adventure.

If you don't want to use objects, dump it in a database and use sql to fetch it.  You could even write a db procedure to do
it for you.

 

In my old language I'd build a couple structures but I don't think I'd do that in PHP.

PHP may have some container objects ready for you to use.  Like I said,  don't know PHP that well so you'll have to look around.


Good luck.
 

Link to comment
Share on other sites

fatkatie has the right idea: process the XML into temporary structures first, be those objects or arrays (I think arrays would be sufficient), sort those how you want, and then display them in order.

 

1. Start with $warnings = empty

2. Go through all the warnings in the XML

3. Process each one into an array, with the data you want from it, then add it to $warnings

4. Sort the final array with usort

5. Loop over the array and display the results

 

Code looks something like

$warnings = [];

// list of prioritized event types
$priorities = [
	"Tornado Warning" => 9,
	"Severe Thunderstorm Warning" => 8,
	"Flash Flood Warning" => 7
];

// for each $entry {
	$warning = [
		"entry" => $entry, // <id> is $warning["entry"]->id
		"cap" => $entry->children("cap", true) // <cap:effective> is $warning["cap"]->effective
		// other things?
	];

	// add priority
	$p = (string)$warning["cap"]->event;
	// php 5:
	if (isset($priorities[$p])) {
		$warning["priority"] = $p;
	} else {
		$warning["priority"] = 0; // lower than anything in $priorities
	}
	// php 7 (you should have this by now):
	//$warning["priority"] = ($priorities[$p] ?? 0);

	// maybe more data...?

	// finally add to list
	$warnings[] = $warning;
// }

// sort by comparing pairs of elements from the array
usort($warnings, function($a, $b) {
	// return <0 if $a before $b, 0 if $a same rank as $b (try to avoid this), >0 if $a after $b
	// usort trick: get numeric values then use subtraction to "compare" them and end up with something that follows the above rule

	// first sort by priority
	if ($a["priority"] != $b["priority"]) {
		return $b["priority"] - $a["priority"]; // try the math in your head to see how this works
	}

	// sort by something else. effective date, earliest first?
	return strtotime($a["cap"]->effective) - strtotime($b["cap"]->effective);
});

// now display
foreach ($warnings as $warning) {
	// ...
}
Link to comment
Share on other sites

For everyone's reference, each looks like

	<entry>
	<id>https://alerts.weather.gov/cap/wwacapget.php?x=AR12585024B610.SpecialWeatherStatement.125850256ED4AR.SHVSPSSHV.c94c6bdfd6f158c4839211f689a70233</id>
	<updated>2017-05-10T19:52:00-05:00</updated>
	<published>2017-05-10T19:52:00-05:00</published>
	<author>
	<name>w-nws.webmaster@noaa.gov</name>
	</author>
	<title>Special Weather Statement issued May 10 at 7:52PM CDT until further notice by NWS</title>
	<link href='https://alerts.weather.gov/cap/wwacapget.php?x=AR12585024B610.SpecialWeatherStatement.125850256ED4AR.SHVSPSSHV.c94c6bdfd6f158c4839211f689a70233'/>
	<summary>...SIGNIFICANT WEATHER ADVISORY FOR SOUTH CENTRAL LITTLE RIVER... SOUTHERN MILLER...CENTRAL CASS AND SOUTHEASTERN BOWIE COUNTIES UNTIL 815 PM CDT... At 752 PM CDT, Doppler radar was tracking a strong thunderstorm 7 miles north of Linden, or 12 miles west of Atlanta, moving northeast at 55 mph.</summary>
	<cap:event>Special Weather Statement</cap:event>
	<cap:effective>2017-05-10T19:52:00-05:00</cap:effective>
	<cap:expires>2017-05-11T00:25:00-05:00</cap:expires>
	<cap:status>Actual</cap:status>
	<cap:msgType>Alert</cap:msgType>
	<cap:category>Met</cap:category>
	<cap:urgency>Expected</cap:urgency>
	<cap:severity>Minor</cap:severity>
	<cap:certainty>Observed</cap:certainty>
	<cap:areaDesc>Little River; Miller</cap:areaDesc>
	<cap:polygon>33.25,-93.7 33.24,-93.73 33.23,-93.73 33.23,-93.7 33.22,-93.71 33.21,-93.74 32.97,-94.38 33.11,-94.53 33.63,-94.27 33.25,-93.7</cap:polygon>
	<cap:geocode>
	<valueName>FIPS6</valueName>
	<value>005081 005091</value>
	<valueName>UGC</valueName>
	<value>ARZ059 ARZ070</value>
	</cap:geocode>
	<cap:parameter>
	<valueName>VTEC</valueName>
	<value></value>
	</cap:parameter>
	</entry>
Link to comment
Share on other sites

Archived

This topic is now archived and is closed to further replies.

×
×
  • Create New...

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue.