State Weather Advisories available by RSS

weather

In Exploring the NOAA API I posted code for consuming the NOAA RSS feed for Atlantic storms.

I also posted weather-finding functions using the Geonames API, the WebserviceX.NET API and even a cheap formula for opening weather.com.

Now let's explore even more weather-related functions (I'm sure you're as excited as I am!). This one is an API from weather.gov that provides state-by-state weather advisories which you can use in your VBA programs.

I noticed that in addition to providing a RSS feed, the feed URL itself only differs by the state abbreviation. So all we need to do is prompt for the state abbreviation and we can return any weather advisories in any state! And if you check weather.gov for all the state abbreviations, you can also look at weather for other U.S. territories and provinces.

The GetStateAdvisories Function

The following function takes a state abbreviation and returns any weather advisories issued by weather.gov for that state. Queries are cached, so the second parameter must be True to requery the API.

Function GetStateAdvisories(state As String, _
    Optional forceRequery As Boolean = False) As String()
' see http://www.weather.gov/alerts-beta/ for list of states/provinces
Dim xml As Object ' MSXML2.XMLHTTP
Dim result As String
Dim tempFolder As String
Dim tempFile As String
Dim tempString() As String
Dim xmlDoc As Object ' MSXML2.DOMDocument
Dim xmlDocRoot As Object ' MSXML2.IXMLDOMNode
Dim feed As Object ' MSXML2.IXMLDOMNodeList
Dim i As Long, j As Long
Dim numberOfEntries As Long
Dim entry As Object ' MSXML2.IXMLDOMNodeList

Const XML_FILE_EXTENSION As String = ".xml"

  tempFolder = environ("temp")

  Set xml = CreateObject("MSXML2.XMLHTTP.6.0")

  tempFile = tempFolder & Application.PathSeparator & "stateweather_" & _
    state & XML_FILE_EXTENSION

  ' query website if cache is empty or we are forced to
  If (Len(Dir(tempFile)) = 0 Or forceRequery) Then

    With xml
      .Open "GET", "http://www.weather.gov/alerts-beta/" & _
    LCase$(state) & ".php?x=0", False
      .send
    End With

    result = ConvertAccent(xml.responseText)

    ' create XML file from result
    Call CreateXMLFile(tempFile, result)

  End If

  Set xmlDoc = CreateObject("MSXML2.DOMDocument")

  With xmlDoc
    .async = False
    .validateOnParse = False
    .Load tempFile
  End With

  ' check that the XML doc loaded
  If LoadError(xmlDoc) Then
    Exit Function
  End If

  ' get root node
  Set xmlDocRoot = GetRootNode(xmlDoc)
  ' get first level nodes
  Set feed = GetChildNodes(xmlDocRoot)

  ' count number of entries to figure out
  ' how many rows in the array
  For i = 1 To feed.Length
    If feed.item(i - 1).nodeName = "entry" Then
      numberOfEntries = numberOfEntries + 1
    End If
  Next i

  ' resize array
  ' there are four nodes of information per entry
  ReDim tempString(1 To numberOfEntries, 1 To 4)

  ' start grabbing!
  For i = 1 To feed.Length
    If feed.item(i - 1).nodeName = "entry" Then
      ' it's an entry
      Set entry = feed.item(i - 1).childNodes

      ' check for no watches
      If InStr(entry.item(3).nodeTypedValue, "There are no active watches") > 0 Then
        tempString(1, 1) = entry.item(1).nodeTypedValue
        tempString(1, 2) = entry.item(3).nodeTypedValue
        tempString(1, 3) = entry.item(4).Attributes.getNamedItem("href").nodeTypedValue
        tempString(1, 4) = entry.item(5).nodeTypedValue
      Else
        For j = 1 To numberOfEntries
          tempString(j, 1) = entry.item(1).nodeTypedValue
          tempString(j, 2) = entry.item(4).nodeTypedValue
          tempString(j, 3) = entry.item(5).Attributes.getNamedItem("href").nodeTypedValue
          tempString(j, 4) = entry.item(6).nodeTypedValue
        Next j
      End If
    End If
  Next i

  GetStateAdvisories = tempString

End Function

Because there is a series of irrelevant nodes that appear before the weather entries, we need to loop through the nodes to find out how many entries there are. After sizing the temporary array we'll use to hold the entry information, we loop again through the nodes.

If there are no active weather advisories, there will be one node and we don't really need to loop. Otherwise we loop through each entry and grab the weather advisory along with the URL from weather.gov.

Sample usage

This procedure will return and iterate through any available weather advisories for New York State.

Sub TestGetAdvisories()

Dim results() As String
Dim i As Long, j As Long

  results = GetStateAdvisories("NY")

  For i = LBound(results) To UBound(results)
    For j = LBound(results, 2) To UBound(results, 2)
      Debug.Print results(i, j)
    Next j
  Next i

End Sub

Helper Functions

The MSXML helper functions should be placed in the same project.

Related Articles:

About JP

I'm just an average guy who writes VBA code for a living. This is my personal blog. Excel and Outlook are my thing, with a sprinkle of Access and Word here and there. Follow this space to learn more about VBA. Keep Reading »

Share This Article:

Share and bookmark this articledelicious buttonfacebook buttonlinkedin buttonstumbleupon buttontwitter button
Note: Comments are subject to the Blog Comment Policy and may not appear immediately. To post VBA code in your comment, use code tags like this: [vb]your code goes here[/vb]

Add a Comment:

*

Site last updated: February 3, 2012