[SOLVED] XML and parsing National Weather Service Data

PHP programming forum. Ask questions or help people concerning PHP code. Don't understand a function? Need help implementing a class? Don't understand a class? Here is where to ask. Remember to do your homework!

Moderator: General Moderators

Post Reply
jredman
Forum Newbie
Posts: 2
Joined: Tue Feb 08, 2005 1:23 pm

[SOLVED] XML and parsing National Weather Service Data

Post by jredman »

I am parsing XML from the National Weather service:

http://www.nws.noaa.gov/data/current_obs/KMSN.xml

I have had to code around some things in the character data handler because it seems to call it twice for each occurance of character data. The first time I get the data that I want, but then it calls the character data handler a second time with a short bit of something that I don't want and that will overlay the good data. I've had to include checks in the function handleCharacterData() on length or check if my variable was already initialized or not. I get this behaviour from other XML document as well using this same code. Any ideas?

thanks in advance,
jredman

Code: Select all

<?php

# GLOBAL Variables #####
$currentTag = "currentTag";
$obTime = "obTime";
$weather = "weather";
$tempStr = "tempStr";
$windStr = "windStr";  
$rhStr = "rhStr";
$presStr = "presStr";
$wcStr = "wcStr";
########################

# Read Current Conditions XML document
$handle = fopen("http://www.nws.noaa.gov/data/current_obs/KMSN.xml", "rb");
$contents = '';
while (!feof($handle)) 
&#123;
  $contents .= fread($handle, 4096);
&#125;
fclose($handle);

#echo $contents;

# Parse $contents
$xmlParser = createParser();
setOptions($xmlParser);
setHandlers($xmlParser);
parse($xmlParser, $contents);
freeParser($xmlParser);

# Write out a document
outputHTML();


# *********************************************************
# ***                Start of functions                 ***
# *********************************************************

function createParser()
&#123;
   $xmlParser = xml_parser_create();
   if ($xmlParser == false)
   &#123;
      die('Cannot create an XML parser handle.');
   &#125;
   return $xmlParser;
&#125;

function setOptions($xmlParser)
&#123;
   xml_parser_set_option($xmlParser, XML_OPTION_CASE_FOLDING, false);
&#125;

function setHandlers($xmlParser)
&#123;
   xml_set_element_handler($xmlParser, 'handleBeginTag', 'handleEndTag');
   xml_set_character_data_handler($xmlParser, 'handleCharacterData');
&#125;

function parse($xmlParser, $xmlOut)
&#123;
   $parsedOkay = xml_parse($xmlParser, $xmlOut);

   if ( ! $parsedOkay && xml_get_error_code($xmlParser) != XML_ERROR_NONE)
   &#123;
      die('xmlParse error: ' . xml_error_string(xml_get_error_code($xmlParser)) .
          ' at line ' . xml_get_current_line_number($xmlParser));
   &#125;
&#125;

function freeParser($xmlParser)
&#123;
   $freeOkay = xml_parser_free($xmlParser);

   if( ! $freeOkay)
   &#123;
      die('You did not pass a proper XML pareser to this function.');
   &#125;
&#125;

function handleBeginTag($parser, $name, $attribs)
&#123;
   global $obTime;
   global $currentTag;

   $currentTag = $name;
&#125;

function handleCharacterData($xmlParser, $data)
&#123;

   global $currentTag;
   global $obTime;
   global $weather;
   global $tempStr;
   global $windStr;   
   global $rhStr;
   global $presStr;
   global $wcStr;
 
   # For some weird reason, this function gets called a second time
   # for each set of character data.  The first call is the data we 
   # want, but the second call contains a short bit of something that 
   # we throw out....
 
    switch($currentTag)
   &#123;

      case "observation_time" :
         if ($obTime == 'obTime')
           $obTime = $data;
         break;

      case "weather" :
         if (strlen($data) > 2)
           $weather = $data;
         break;

      case "temperature_string" :
         if (strlen($data) > 2)
           $tempStr = $data;
         break;
         
      case "wind_string" :
         if (strlen($data) > 2)
           $windStr = $data;
         break; 
         
      case "relative_humidity" :
         if ($rhStr == 'rhStr')
	   $rhStr = $data;
         break;
         
      case "pressure_in" :
         if (strlen($data) > 3)
      	   $presStr = $data;
         break;   
               
      case "windchill_f" :
         if ($wcStr == 'wcStr')
      	   $wcStr = $data;
         break;           

      default :
         break;

   &#125;

&#125;

function handleEndTag($xmlParser, $name)
&#123;
  return;
&#125;

function outputHTML()
&#123;
  
  global $obTime;
  global $weather;
  global $tempStr;
  global $windStr;
  global $rhStr;
  global $presStr;
  global $wcStr;
  
  echo "<html>\n";
  echo "  <head>\n";
  echo "    <link rel='stylesheet' href='NWS.css' type='text/css' />\n";
  echo "    <title>Madison Weather</title>\n";
  echo "  </head>\n";
  echo "<body>\n";

  echo "  <h1>Madison Current Weather</h1>";

  echo "  <table>";
  echo "    <tr><th colspan='2'>Current Conditions</th><th /><th /></tr>\n";
  echo "    <tr><td>Sky:</td><td>$weather</td><td style='border-left:1px solid'>Relative Humidity:</td><td>$rhStr %</td></tr>\n";
  echo "    <tr><td>Temp:</td><td>$tempStr</td><td style='border-left:1px solid'>Barometric Pressure:</td><td>$presStr in</td></tr>\n";
  echo "    <tr><td>Wind:</td><td>$windStr</td><td style='border-left:1px solid'>Wind Chill:</td><td>$wcStr F</td></tr>\n";
  echo "    <tr class='fstrip'><td style='font-size:60%' colspan='2'>$obTime</td><td /><td />\n";
  echo "  </table>\n";
  echo "  <p>Above data is from: <a href='http://www.nws.noaa.gov/data/current_obs/KMSN.xml'>http://www.nws.noaa.gov/data/current_obs/KMSN.xml</a></p>\n";
  echo "  <br />\n";
  echo "  <p style='text-align:left; font-size:14pt; margin-left:100px'><a href='NWS.html'>Return</a></p>";  
  echo "</body>\n";
  echo "</html>\n";
&#125;

?>

feyd | :roll:
timvw
DevNet Master
Posts: 4897
Joined: Mon Jan 19, 2004 11:11 pm
Location: Leuven, Belgium

Post by timvw »

you should unset current tag in handleEndTag.....

the 'second' time handleCharacterData is called is between </tag> and <tag>



there is some option to avoid this too, i just forgot it's name :(
jredman
Forum Newbie
Posts: 2
Joined: Tue Feb 08, 2005 1:23 pm

Post by jredman »

Thank you! - that works :D
Post Reply