Displaying Weather In App

Hi,

I am trying to create an app in which the user enters a zipcode into a text box and the local weather is displayed.

I saw a Feb. 2013 thread which had some code but I can’t seem to get it to work. The thread was located at:

http://forums.realsoftware.com/viewtopic.php?f=2&t=46966&p=262926&hilit=weather#p262926

The code was by duanemitchell was as follows:

[code]dim vXML, answerString, newRow as string
dim hsock as new HTTPSocket

txtTextOutput.Visible=false
lbXMLOutput.Visible=true

vXML = “<?xml version=""1.0"" encoding=""utf-16""?>”
vXML = vXML + “<soap:Envelope xmlns:soap=”“http://schemas.xmlsoap.org/soap/envelope/”" xmlns:xsi="“http://www.w3.org/2001/XMLSchema-instance”" xmlns:xsd="“http://www.w3.org/2001/XMLSchema”">"
vXML = vXML + “soap:Body
vXML = vXML + “<ns1:GetCityWeatherByZIP xmlns:ns1=”“http://ws.cdyne.com/WeatherWS/”">"
vXML = vXML + “ns1:ZIP”+edfTextEntry.Text+"</ns1:ZIP>"
vXML = vXML + “</ns1:GetCityWeatherByZIP>”
vXML = vXML + “</soap:Body>”
vXML = vXML + “</soap:Envelope>”

// HTTPSocket version
hsock = new HTTPSocket
hsock.yield = false
hsock.SetRequestContent vXML, “text/xml”
answerString=hsock.post(“http://wsf.cdyne.com/WeatherWS/Weather.asmx”, 10)

Dim x As New XmlDocument(answerString)
// check first node of document:
Dim n As XmlNode = x.FirstChild
// and now walk over all sub nodes, just the data sub nodes which are deep
Dim childNode As XmlNode = n.FirstChild.FirstChild.FirstChild.FirstChild 'data is 4 nodes deep
lbXMLOutput.DeleteAllRows
While childNode <> Nil
If childNode.PreviousSibling <> Nil and childNode.PreviousSibling.Name=“Pressure” then
exit
else
newRow = childNode.Name + ": " + childNode.FirstChild.Value
lbXMLOutput.addrow(newRow)
childNode = childNode.NextSibling
end if
Wend[/code]

I created a Window and placed the following controls:

Listbox called lbXMLOutput
Textbox called - txtTextOutput
Textbox called edfTextEntry

I also drag into the project a TCPSocket called TCPSocket1 and changed the Super to: HTTPSocket

I then put the above code in the Load event.

When I run the project I get and error that says that the Compilation Failed. The error also says if the application exists, please make sure that it is not currently running, otherwise make sure that the destination directory is writable

Does anyone see what I am doing wrong or have better code for getting the weather by zip code?

Any help would be greatly appreciated.

Jim

This code builds and runs fine on my system. I put the code in the Window.Open Event and only added "edfTextEntry.Text = “94089” at the start of the Open Event to provide a Zip code.

MacBook Pro
OS X 10.9
XoJo 2013r3.1

Hi Michael,
Thank you for taking the time to help me. Would you mind emailing the project you did to me ? I still can’t get this to work. I must be doing something wrong, and would like to see how you did it … if you don’t mind.

program a t knightlite d o t c o m

I am using Xojo Version 3.0
Mac OSX 10.8.5
Mac Pro

You can find the project in my dropbox public folder:

https://www.dropbox.com/s/p4gkhq77hcka0he/Weather%20Retriever.xojo_binary_project

It worked before I changed it but this version has a few changes to allow entry of ZipCodes and handling bad zip codes.

Michael.

Thank you so much. I really appreciate you taking the time to do that for me. That was just what I am looking of. Thanks again. That was really nice of you. :slight_smile:

Jim

One thing I did notice this morning is that the app does not seem to like zip codes from Hawaii. If you try 96818, 96817, 96821 the app crashes.

[code]While childNode <> Nil
If childNode.PreviousSibling <> Nil And childNode.PreviousSibling.Name = “Pressure” Then
Exit
Else

  newRow = childNode.Name + ": " + childNode.FirstChild.Value    // **********  Crashes On This line

lbXMLOutput.AddRow( newRow )
If childNode.FirstChild.Value = “false” Then
lbXMLOutput.AddRow( “No city found for this Zip Code!” )
Exit
End If
childNode = childNode.NextSibling
End If
Wend[/code]

I was wondering if there may be a way of trapping this error?

I tried

If childNode = Nil then exit

but that did not work.

It’s possible that code will raise a NilObjectException if the XML that comes back from the web service call does not exactly match what the code is expecting.

You might first look at answerString in the debugger to see its contents. If there is an obvious error, then don’t try to process the XML directly like it is doing. Or you can process the XML differently (one node at a time).

Thanks Paul,

Unfortunately, I don’t know how to do that, and I have never worked with XML.

I did put a messagebox in the code to see on what element it crashes on and it seems to be the Description element. It returns a N/A value which I think crashes the app. I just don’t know how to write the code to ignore any line that will give a nil exception.

ChildNode.FirstChild is NIL when you try to get its Value
I’ve made some improvements, check it out:

  
  Dim vXML, answerString, newRow As String
  Dim hsock As New HTTPSocket
  
  vXML = "<?xml version=""1.0"" encoding=""utf-16""?>"
  vXML = vXML + "<soap:Envelope xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"">"
  vXML = vXML + "<soap:Body>"
  vXML = vXML + "<ns1:GetCityWeatherByZIP xmlns:ns1=""http://ws.cdyne.com/WeatherWS/"">"
  vXML = vXML + "<ns1:ZIP>" + edfTextEntry.Text + "</ns1:ZIP>"
  vXML = vXML + "</ns1:GetCityWeatherByZIP>"
  vXML = vXML + "</soap:Body>"
  vXML = vXML + "</soap:Envelope>"
  
  try
    
    // HTTPSocket version
    hsock = New HTTPSocket
    hsock.yield = False
    hsock.SetRequestContent vXML, "text/xml"
    answerString = DefineEncoding(hsock.post( "http://wsf.cdyne.com/WeatherWS/Weather.asmx", 10), Encodings.UTF8)
    
    Dim x As New XmlDocument( answerString )
    Dim n As XmlNode = x.FirstChild
    Dim childNode As XmlNode = n.FirstChild.FirstChild.FirstChild.FirstChild 
    
    lbXMLOutput.DeleteAllRows
    
    While childNode <> Nil
      
      If childNode.PreviousSibling <> Nil And childNode.PreviousSibling.Name = "Pressure" Then
        Exit
        
      Else
        
        if childNode.FirstChild <> nil then
          newRow = DefineEncoding(childNode.Name, Encodings.UTF8) + ": " + DefineEncoding( childNode.FirstChild.Value, Encodings.UTF8)
        else
          Exit
        end if
        
        lbXMLOutput.AddRow( newRow )
        If childNode.FirstChild.Value = "false" Then 
          lbXMLOutput.AddRow( "No city found for this Zip Code!" )
          Exit
        End If
        childNode = childNode.NextSibling
        
      End If
      
    Wend
    
  catch
    
  Finally
    
  end try

Now it should work even with Hawaii but…

  1. Never use alien Strings without Encoding and
  2. always use try - end try for everything when communicating with the world…

Hi Tomas,

Thanks for your help. I appreciate you taking the time to trap the error. That code did stop the app from crashing, although it does stop the entire process. The weather code sends back 11 elements.

  1. Success.
  2. Response Text
  3. State
  4. City
  5. Weather Station City
  6. Weather ID
  7. Description.
  8. Temperature
  9. Humidity
  10. Wind
  11. Pressure

The code stops working for the Hawaii zip codes at 7) Description. I wish there was a way to skip over the element that gives the error and still load valid data after 7) Description. Sort of like the old Visual Basic command. “On error resume next.”

Is there a better way to get the current weather from a zip code into a Xojo app? I am looking at the Yahoo Weather example but it requires the WOEID for the city. Since the customer will not know that, it would be better to go by zip code.

I just took the code Tomas posted and ran it and it works fine with the zip codes for Hawaii that were posted

Hi Norman,

The zip codes I used were 96818, 96817, and 96821.

It runs and does not crash, but it does not return any data after the 6) Weather ID. The crash happens on 7) Description because the value returned is “N/A”. The “try” code traps that error but the whole operation stops and you can’t get the other weather data"

Temperature
Humidity
Wind
Pressure

In the case of 96821 there is nothing more (at least when I try things right now)

<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:soap="http://schemas.xmlsoap.org/soap/envelope/" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema">
<soap:Body>
<GetCityWeatherByZIPResponse xmlns="http://ws.cdyne.com/WeatherWS/">
  <GetCityWeatherByZIPResult>
    <Success>true</Success>
    <ResponseText>City Found</ResponseText>
    <State>HI</State>
    <City>Honolulu</City>
    <WeatherStationCity>Honolulu</WeatherStationCity>
    <WeatherID>15</WeatherID>
    <Description>N/A</Description>
    <Temperature ></Temperature>
    <RelativeHumidity ></RelativeHumidity>
    <Wind ></Wind>
    <Pressure ></Pressure>
    <Visibility ></Visibility>
    <WindChill ></WindChill>
    <Remarks ></Remarks>
  </GetCityWeatherByZIPResult>
</GetCityWeatherByZIPResponse>
</soap:Body>
</soap:Envelope>

FWIW I commented the try catch OUT of the code & reran it - the try has no impact on how the code runs & there’s no exception being thrown. There just isn’t any data for these.

I altered the code slightly so all the returned items get a row - whether they have a value or not

  Dim vXML, answerString, newRow As String
  Dim hsock As New HTTPSocket
  
  vXML = "<?xml version=""1.0"" encoding=""utf-16""?>"
  vXML = vXML + "<soap:Envelope xmlns:soap=""http://schemas.xmlsoap.org/soap/envelope/"" xmlns:xsi=""http://www.w3.org/2001/XMLSchema-instance"" xmlns:xsd=""http://www.w3.org/2001/XMLSchema"">"
  vXML = vXML + "<soap:Body>"
  vXML = vXML + "<ns1:GetCityWeatherByZIP xmlns:ns1=""http://ws.cdyne.com/WeatherWS/"">"
  vXML = vXML + "<ns1:ZIP>" + edfTextEntry.Text + "</ns1:ZIP>"
  vXML = vXML + "</ns1:GetCityWeatherByZIP>"
  vXML = vXML + "</soap:Body>"
  vXML = vXML + "</soap:Envelope>"
  
  try
    
    // HTTPSocket version
    hsock = New HTTPSocket
    hsock.yield = False
    hsock.SetRequestContent vXML, "text/xml"
    answerString = DefineEncoding(hsock.post( "http://wsf.cdyne.com/WeatherWS/Weather.asmx", 10), Encodings.UTF8)
    
    Dim x As New XmlDocument( answerString )
    Dim n As XmlNode = x.FirstChild
    Dim childNode As XmlNode = n.FirstChild.FirstChild.FirstChild.FirstChild
    
    lbXMLOutput.DeleteAllRows
    
    While childNode <> Nil
      
      If childNode <> nil and childNode.FirstChild <> nil and childNode.FirstChild.Value = "false" Then
        lbXMLOutput.AddRow( "No city found for this Zip Code!" )
        Exit
      End If
      
      newRow = DefineEncoding(childNode.Name, Encodings.UTF8) + ": "
      
      if childNode.FirstChild <> nil then
        newRow = newRow + DefineEncoding( childNode.FirstChild.Value, Encodings.UTF8)
      else
        
      end if
      
      lbXMLOutput.AddRow( newRow )
      
      childNode = childNode.NextSibling
      
    Wend
    
  catch
    
  Finally
    
  end try

Thats too bad. I thought there may be more after description, and it was just crashing on that Description element. I guess this just won’t work for some of the zip codes in Hawaii. Some zip codes in Hawaii do work.

I also see above you have listed 3 more elements. Visibility, Windchill, and Remarks. Is there a way of adding those to the code?

If not I guess I will use what we have.

Thank you once again Michael, Paul, Tomas, and Norman . I really appreciate you taking the time to help.

Hi Norman,

I did not see you last post, before I posted my above post. Thats great. Thanks for your help. I think that will work out pretty well.

Sorry to beat a dead horse here, but after trying to get the code straightened out for this, it appears that the weather site the app accesses does not give the correct weather information. After playing with this for some time, I finally realized that the weather information never updates. Its the same weather and temperature hour after hour. Kind of useless if it does not update.

So, again has anyone had any luck using web services to get the weather into a desktop app?

In the Yahoo example you need the WOEID. I don’t want the customer to have to go to a third party site and look up their WOEID number. It would be nice if there was an SQLite database that you can download where I could create my own code to look up the WOEID from a zip code.

Also the Yahoo Weather example only gives you the last updated time, the sky conditions and temperature. It does not list any of the other data in the app found above. Kind of frustrating.

This looks like it might do what you want: a web service from the US National Weather Service