The blog of roncli blog
Houston, Texas, United States
CTG Music
Trax in Space Beta
Recent Posts
Damn Hackers
NWS XML web service for VB.Net
Web Junkie
Lose That Buger Belly!
Sleep is Needed?
More on Textboxes
Making Textboxes Ain't Easy
Liquid War
#modarchive Story 2
Thursday, March 31, 2005
Updated NWS Code
Posted: 10:17:00 PM 0 comments
Now playing: Atomship - Pencil Fight (3:38)

Mikhail's code was enough to get me started on combining all of the various parameters I wanted (just the relative ones, none of this dewpoint crap) together to come up with one single variable that has all of the forecast possible for one location.

#Region "Structs"

    Private Structure WeatherTable
        Public nodTimeLayout As XmlNode
        Public nodData As XmlNode
    End Structure

    Private Structure WeatherData
        Public wtHighTemp As WeatherTable
        Public wtLowTemp As WeatherTable
        Public wtPointTemp As WeatherTable
        Public wtLiquidPrecip As WeatherTable
        Public wtSnowPrecip As WeatherTable
        Public wtPrecipProb As WeatherTable
        Public wtWindSpeed As WeatherTable
        Public wtWindDirection As WeatherTable
        Public wtCloudCover As WeatherTable
    End Structure

    Private Structure TemperatureData
        Public F As Integer
        Public ReadOnly Property C() As Integer
                Return Integer.Parse(Math.Round(((Double.Parse(F) - 32) / 9) * 5))
            End Get
        End Property
        Public dt As Date
    End Structure

    Private Structure PrecipitationData
        Public Inches As Double
        Public ReadOnly Property MM() As Double
                Return Inches * 25.4
            End Get
        End Property
        Public dt As Date
    End Structure

    Private Structure PercentData
        Public Pct As Integer
        Public dt As Date
    End Structure

    Private Structure WindData
        Public Knots As Integer
        Public ReadOnly Property MPH() As Integer
                Return Integer.Parse(Math.Round((Double.Parse(Knots) * 6076.12) / 5280))
            End Get
        End Property
        Public Degrees As Integer
        Public ReadOnly Property Dir() As String
                Select Case Degrees
                    Case 0 To 11.25, 348.75 To 360
                        Return "N"
                    Case 11.25 To 33.75
                        Return "NNE"
                    Case 33.75 To 56.25
                        Return "NE"
                    Case 56.25 To 78.75
                        Return "ENE"
                    Case 78.75 To 101.25
                        Return "E"
                    Case 101.25 To 123.75
                        Return "ESE"
                    Case 123.75 To 146.25
                        Return "SE"
                    Case 146.25 To 168.75
                        Return "SSE"
                    Case 168.75 To 191.25
                        Return "S"
                    Case 191.25 To 213.75
                        Return "SSW"
                    Case 213.75 To 236.25
                        Return "SW"
                    Case 236.25 To 258.75
                        Return "WSW"
                    Case 258.75 To 281.25
                        Return "W"
                    Case 281.25 To 303.75
                        Return "WNW"
                    Case 303.75 To 326.25
                        Return "NW"
                    Case 326.25 To 348.75
                        Return "NNW"
                End Select
            End Get
        End Property
        Public dt As Date
    End Structure

    Private Structure FormattedWeatherData
        Public HighTemp() As TemperatureData
        Public LowTemp() As TemperatureData
        Public PointTemp() As TemperatureData
        Public LiquidPrecip() As PrecipitationData
        Public SnowPrecip() As PrecipitationData
        Public PrecipProb() As PercentData
        Public Wind() As WindData
        Public CloudCover() As PercentData
    End Structure

#End Region

#Region "NWS XML Reader"

    Private Function FindLayoutTable(ByVal xmlDoc As XmlDocument, ByVal nodData As XmlNode)
        Dim nlTimeLayouts As XmlNodeList = xmlDoc.SelectNodes("/dwml/data/time-layout")
        Dim strTimeLayout As String = nodData.Attributes("time-layout").Value

        Dim node As XmlNode
        For Each node In nlTimeLayouts
            If strTimeLayout = node.SelectSingleNode("layout-key").InnerText Then
                Return node
            End If

        Return Nothing
    End Function

    Private Function ParseDateTime(ByVal str As String) As Date
        Return Date.Parse(str.Replace("T", " ").Substring(0, str.LastIndexOf("-")))
    End Function

    Private Sub FillTemperatureData(ByVal wt As WeatherTable, ByRef temp() As TemperatureData)
        Dim intCount As Integer

        Dim nlData As XmlNodeList = wt.nodData.SelectNodes("value")
        Dim nlDate As XmlNodeList = wt.nodTimeLayout.SelectNodes("start-valid-time")
        For intCount = 0 To UBound(temp) - 1
            temp(intCount) = New TemperatureData()
            temp(intCount).F = Integer.Parse(nlData(intCount).InnerText)
            temp(intCount).dt = ParseDateTime(nlDate(intCount).InnerText)
    End Sub

    Private Sub FillPrecipitationData(ByVal wt As WeatherTable, ByRef precip() As PrecipitationData)
        Dim intCount As Integer

        Dim nlData As XmlNodeList = wt.nodData.SelectNodes("value")
        Dim nlDate As XmlNodeList = wt.nodTimeLayout.SelectNodes("start-valid-time")
        For intCount = 0 To UBound(precip) - 1
            precip(intCount) = New PrecipitationData()
            If Len(nlData(intCount).InnerText) = 0 Then
                precip(intCount).Inches = 0
                precip(intCount).Inches = Double.Parse(nlData(intCount).InnerText)
            End If
            precip(intCount).dt = ParseDateTime(nlDate(intCount).InnerText)
    End Sub

    Private Sub FillPercentData(ByVal wt As WeatherTable, ByRef pct() As PercentData)
        Dim intCount As Integer

        Dim nlData As XmlNodeList = wt.nodData.SelectNodes("value")
        Dim nlDate As XmlNodeList = wt.nodTimeLayout.SelectNodes("start-valid-time")
        For intCount = 0 To UBound(pct) - 1
            pct(intCount) = New PercentData()
            pct(intCount).Pct = Integer.Parse(nlData(intCount).InnerText)
            pct(intCount).dt = ParseDateTime(nlDate(intCount).InnerText)
    End Sub

    Private Sub FillWindData(ByVal wtSpeed As WeatherTable, ByVal wtDir As WeatherTable, ByRef wind() As WindData)
        Dim intCount As Integer

        Dim nlSpeed As XmlNodeList = wtSpeed.nodData.SelectNodes("value")
        Dim nlDir As XmlNodeList = wtDir.nodData.SelectNodes("value")
        Dim nlDate As XmlNodeList = wtSpeed.nodTimeLayout.SelectNodes("start-valid-time")
        For intCount = 0 To UBound(wind) - 1
            wind(intCount) = New WindData()
            wind(intCount).Knots = Integer.Parse(nlSpeed(intCount).InnerText)
            wind(intCount).Degrees = Integer.Parse(nlDir(intCount).InnerText)
            wind(intCount).dt = ParseDateTime(nlDate(intCount).InnerText)
    End Sub

    Private Function ParseForecastXML(ByVal strXMLWeather) As FormattedWeatherData
            'Setup variables
            Dim xmlDoc As New XmlDocument()
            Dim wdData As New WeatherData()
            Dim fwdData As New FormattedWeatherData()
            wdData.wtHighTemp = New WeatherTable()
            wdData.wtLowTemp = New WeatherTable()
            wdData.wtPointTemp = New WeatherTable()
            wdData.wtLiquidPrecip = New WeatherTable()
            wdData.wtSnowPrecip = New WeatherTable()
            wdData.wtPrecipProb = New WeatherTable()
            wdData.wtWindSpeed = New WeatherTable()
            wdData.wtWindDirection = New WeatherTable()
            wdData.wtCloudCover = New WeatherTable()

            'Load XML data

            'Load data and their corresponding time nodes
            wdData.wtHighTemp.nodData = xmlDoc.SelectSingleNode("/dwml/data/parameters/temperature[@type='maximum']")
            wdData.wtLowTemp.nodData = xmlDoc.SelectSingleNode("/dwml/data/parameters/temperature[@type='minimum']")
            wdData.wtPointTemp.nodData = xmlDoc.SelectSingleNode("/dwml/data/parameters/temperature[@type='hourly']")
            wdData.wtLiquidPrecip.nodData = xmlDoc.SelectSingleNode("/dwml/data/parameters/precipitation[@type='liquid']")
            wdData.wtSnowPrecip.nodData = xmlDoc.SelectSingleNode("/dwml/data/parameters/precipitation[@type='snow']")
            wdData.wtPrecipProb.nodData = xmlDoc.SelectSingleNode("/dwml/data/parameters/probability-of-precipitation[@type='12 hour']")
            wdData.wtWindSpeed.nodData = xmlDoc.SelectSingleNode("/dwml/data/parameters/wind-speed[@type='sustained']")
            wdData.wtWindDirection.nodData = xmlDoc.SelectSingleNode("/dwml/data/parameters/direction[@type='wind']")
            wdData.wtCloudCover.nodData = xmlDoc.SelectSingleNode("/dwml/data/parameters/cloud-amount[@type='total']")

            wdData.wtHighTemp.nodTimeLayout = FindLayoutTable(xmlDoc, wdData.wtHighTemp.nodData)
            wdData.wtLowTemp.nodTimeLayout = FindLayoutTable(xmlDoc, wdData.wtLowTemp.nodData)
            wdData.wtPointTemp.nodTimeLayout = FindLayoutTable(xmlDoc, wdData.wtPointTemp.nodData)
            wdData.wtLiquidPrecip.nodTimeLayout = FindLayoutTable(xmlDoc, wdData.wtLiquidPrecip.nodData)
            wdData.wtSnowPrecip.nodTimeLayout = FindLayoutTable(xmlDoc, wdData.wtSnowPrecip.nodData)
            wdData.wtPrecipProb.nodTimeLayout = FindLayoutTable(xmlDoc, wdData.wtPrecipProb.nodData)
            wdData.wtWindSpeed.nodTimeLayout = FindLayoutTable(xmlDoc, wdData.wtWindSpeed.nodData)
            wdData.wtWindDirection.nodTimeLayout = FindLayoutTable(xmlDoc, wdData.wtWindDirection.nodData)
            wdData.wtCloudCover.nodTimeLayout = FindLayoutTable(xmlDoc, wdData.wtCloudCover.nodData)

            'Setup formatted data variables
            ReDim fwdData.HighTemp(wdData.wtHighTemp.nodTimeLayout.SelectNodes("start-valid-time").Count)
            ReDim fwdData.LowTemp(wdData.wtLowTemp.nodTimeLayout.SelectNodes("start-valid-time").Count)
            ReDim fwdData.PointTemp(wdData.wtPointTemp.nodTimeLayout.SelectNodes("start-valid-time").Count)
            ReDim fwdData.LiquidPrecip(wdData.wtLiquidPrecip.nodTimeLayout.SelectNodes("start-valid-time").Count)
            ReDim fwdData.SnowPrecip(wdData.wtSnowPrecip.nodTimeLayout.SelectNodes("start-valid-time").Count)
            ReDim fwdData.PrecipProb(wdData.wtPrecipProb.nodTimeLayout.SelectNodes("start-valid-time").Count)
            ReDim fwdData.Wind(wdData.wtWindSpeed.nodTimeLayout.SelectNodes("start-valid-time").Count)
            ReDim fwdData.CloudCover(wdData.wtCloudCover.nodTimeLayout.SelectNodes("start-valid-time").Count)

            'Fill in data
            FillTemperatureData(wdData.wtHighTemp, fwdData.HighTemp)
            FillTemperatureData(wdData.wtLowTemp, fwdData.LowTemp)
            FillTemperatureData(wdData.wtPointTemp, fwdData.PointTemp)
            FillPrecipitationData(wdData.wtLiquidPrecip, fwdData.LiquidPrecip)
            FillPrecipitationData(wdData.wtSnowPrecip, fwdData.SnowPrecip)
            FillPercentData(wdData.wtPrecipProb, fwdData.PrecipProb)
            FillWindData(wdData.wtWindSpeed, wdData.wtWindDirection, fwdData.Wind)
            FillPercentData(wdData.wtCloudCover, fwdData.CloudCover)

            Return fwdData

        Catch ex As Exception
            Return Nothing
        End Try
    End Function

#End Region

A little more complicated in some ways, a bit simpler in others, but the data is complete. To call the web service and retrieve the data:

        Dim weather As New
        Dim params As New
        params.maxt = True = True
        params.temp = True
        params.qpf = True
        params.snow = True
        params.pop12 = True
        params.wspd = True
        params.wdir = True = True
        Dim fwdWeather as FormattedWeatherData = ParseForecastXML(weather.NDFDgen(sngLatitude, sngLongitude, "time-series", Now, Now.AddDays(30), params))
        weather = Nothing
        params = Nothing

fwdWeather now has all the forecasting data you need. It also has easy functions to convert F to C, Knots to MPH, and Inches to Millimeters.

Not bad for a day of research and coding! Now if only they'd make web services for current conditions and severe weather statements, I'd be all set.

Labels: , ,


Post a Comment