Getting Specific Data from XML

Chris Hobbs

I 'm kind of new to VB and .NET, and I'm having trouble especially with trying to setup a weather widget. I'm pulling from Yahoos RSS feeds, storing to an XML file, and then reading from that XML file. The first couple of things pull in fine, but Yahoo's feed sends back basically a LIST of days/temps/highs/lows. (see below)

<rss xmlns:yweather="http://xml.weather.yahoo.com/ns/rss/1.0" xmlns:geo="http://www.w3.org/2003/01/geo/wgs84_pos#" version="2.0">
<channel>
<title>Yahoo! Weather - Lincoln, NE</title>
<link>...</link>
<description>Yahoo! Weather for Lincoln, NE</description>
<language>en-us</language>
<lastBuildDate>Fri, 31 Jan 2014 12:53 pm CST</lastBuildDate>
<ttl>60</ttl>
<yweather:location city="Lincoln" region="NE" country="US"/>
<yweather:units temperature="F" distance="mi" pressure="in" speed="mph"/>
<yweather:wind chill="13" direction="80" speed="7"/>
<yweather:atmosphere humidity="43" visibility="10" pressure="30.08" rising="2"/>
<yweather:astronomy sunrise="7:37 am" sunset="5:43 pm"/>
<image>...</image>
<item>
<title>Conditions for Lincoln, NE at 12:53 pm CST</title>
<geo:lat>40.8</geo:lat>
<geo:long>-96.67</geo:long>
<link>
http://us.rd.yahoo.com/dailynews/rss/weather/Lincoln__NE/*http://weather.yahoo.com/forecast/USNE0283_f.html
</link>
<pubDate>Fri, 31 Jan 2014 12:53 pm CST</pubDate>
<yweather:condition text="Cloudy" code="26" temp="22" date="Fri, 31 Jan 2014 12:53 pm CST"/>
<description>
<![CDATA[...]]>
</description>
<yweather:forecast day="Fri" date="31 Jan 2014" low="18" high="25" text="Few Snow Showers" code="14"/>
<yweather:forecast day="Sat" date="1 Feb 2014" low="5" high="31" text="AM Clouds/PM Sun" code="30"/>
<yweather:forecast day="Sun" date="2 Feb 2014" low="11" high="27" text="Sunny" code="32"/>
<yweather:forecast day="Mon" date="3 Feb 2014" low="18" high="36" text="Partly Cloudy" code="30"/>
<yweather:forecast day="Tue" date="4 Feb 2014" low="-3" high="21" text="Snow Showers" code="14"/>
<guid isPermaLink="false">USNE0283_2014_02_04_7_00_CST</guid>
</item>
</channel>
</rss>

The area I'm having trouble is this

<yweather:forecast day="Fri" date="31 Jan 2014" low="18" high="25" text="Few Snow Showers" code="14"/>
<yweather:forecast day="Sat" date="1 Feb 2014" low="5" high="31" text="AM Clouds/PM Sun" code="30"/>
<yweather:forecast day="Sun" date="2 Feb 2014" low="11" high="27" text="Sunny" code="32"/>
<yweather:forecast day="Mon" date="3 Feb 2014" low="18" high="36" text="Partly Cloudy" code="30"/>
<yweather:forecast day="Tue" date="4 Feb 2014" low="-3" high="21" text="Snow Showers" code="14"/>

As you can see, it gives a list of dates and values back. I'm having trouble reading those values into variables/labels. For example I've been trying

MyDoc.SelectSingleNode("/rss/channel/item/yweather:forecast[day='" + _dayOfweek + "']/@low", nsmgr).InnerText

To try and get the low for each _dayOfWeek -- but I keep getting back XPathExceptions, unclosed strings, so it sounds like the path I take HAS to be a full string with no ' + _dayOfWeek ' - Am I gonig to have to create subroutines for each different day of the week???

Please let me know if you can see anything dumb that I'm doing, here's my code for reference

Public Class CtrlWeatherWidget
    ReadOnly _zip = 68508
    'In the future, may want to include options to view multiple locations, in which case this won't be read only
    Dim _conditions
    Dim _dayOfWeek As String

    Public Sub Update()

        Dim rssurl = "http://xml.weather.yahoo.com/forecastrss?p=" + _zip.ToString()
        Dim rssrequest As Net.WebRequest = Net.WebRequest.Create(rssurl)

        Dim rssresponse As Net.WebResponse = rssrequest.GetResponse()
        Dim rssstream As IO.Stream = rssresponse.GetResponseStream()

        Dim rssdoc As New Xml.XmlDocument
        rssdoc.Load(rssstream)

        Dim nodes As Xml.XmlNodeList
        nodes = rssdoc.SelectNodes("/rss/channel")

        lblCityState.Text = Replace(nodes.Item(0).SelectSingleNode("title").InnerText, "Yahoo! Weather - ", "")

        Dim nsmgr = New Xml.XmlNamespaceManager(rssdoc.NameTable)
        nsmgr.AddNamespace("yweather", "http://xml.weather.yahoo.com/ns/rss/1.0")

        'find the conditions and display the correct image for the current weather

        _conditions = rssdoc.SelectSingleNode("/rss/channel/item/yweather:condition/@code", nsmgr).InnerText

        picConditions.BackgroundImage = GetConditions()

        'get the current days highs and lows and picture

        lblCurrentTemp.Text = rssdoc.SelectSingleNode("rss/channel/item/yweather:condition/@temp", nsmgr).InnerText

        lblLowNow.Text = rssdoc.SelectSingleNode("/rss/channel/item/yweather:forecast[day='" + _dayOfWeek + "']'/@low", nsmgr).InnerText
        'Tabel/Member[Naam='Ghostbullet93']/Kills"
        lblHighNow.Text = rssdoc.SelectSingleNode("/rss/channel/item/yweather:forecast[day='" + _dayOfWeek + "']'/@high", nsmgr).InnerText

        'set the 3 days in the future information below, and get lows highs, picture

        GetDay(1)
        lblDayOne.Text = _dayOfWeek
        _conditions = rssdoc.SelectSingleNode("rss/channel/yweather:condition/@temp", nsmgr).InnerText
        picDayOne.BackgroundImage = GetConditions()
        lblHighOne.Text = String.Format("H: {0}", rssdoc.SelectSingleNode("rss/channel/yweather:atmosphere/@humidity", nsmgr).InnerText)
        lblLowOne.Text = String.Format("L: {0}", rssdoc.SelectSingleNode("rss/channel/yweather:atmosphere/@humidity", nsmgr).InnerText)

        GetDay(2)
        lblDayTwo.Text = _dayOfWeek
        _conditions = rssdoc.SelectSingleNode("rss/channel/yweather:condition/@temp", nsmgr).InnerText
        picDayTwo.BackgroundImage = GetConditions()
        lblHighTwo.Text = String.Format("H: {0}", rssdoc.SelectSingleNode("rss/channel/yweather:atmosphere/@humidity", nsmgr).InnerText)
        lblLowTwo.Text = String.Format("L: {0}", rssdoc.SelectSingleNode("rss/channel/yweather:atmosphere/@humidity", nsmgr).InnerText)

        GetDay(3)
        lblDayThree.Text = _dayOfWeek
        _conditions = rssdoc.SelectSingleNode("rss/channel/yweather:condition/@temp", nsmgr).InnerText
        picDayThree.BackgroundImage = GetConditions()
        lblHighThree.Text = String.Format("H: {0}", rssdoc.SelectSingleNode("rss/channel/yweather:atmosphere/@humidity", nsmgr).InnerText)
        lblLowThree.Text = String.Format("L: {0}", rssdoc.SelectSingleNode("rss/channel/yweather:atmosphere/@humidity", nsmgr).InnerText)

        lblUpdated.Text = String.Format("Last Updated {0}", Replace(nodes.Item(0).SelectSingleNode("rss/channel/item/title").InnerText, "Conditions for ", ""))

    End Sub

    Public Sub GetDay(ByVal offset As Integer)
        Dim day As Integer

        day = Date.Now.DayOfWeek

        If (day + offset) > 7 Then
            day = day + offset
            day = day - 7
        End If

        Select Case day
            Case 1
                _dayOfWeek = "Mon"
            Case 2
                _dayOfWeek = "Tue"
            Case 3
                _dayOfWeek = "Wed"
            Case 4
                _dayOfWeek = "Thu"
            Case 5
                _dayOfWeek = "Fri"
            Case 6
                _dayOfWeek = "Sat"
            Case 7
                _dayOfWeek = "Sun"
        End Select
    End Sub

    Public Function GetConditions() As Image
        If (_conditions >= 0 AndAlso _conditions <= 4) Or (_conditions >= 9 AndAlso _conditions <= 12) Or (_conditions >= 37 AndAlso _conditions <= 40) Or _conditions = 45 Or _conditions = 47 Then
            Return My.Resources.raining
        ElseIf (_conditions >= 5 AndAlso _conditions <= 8) Or (_conditions >= 13 AndAlso _conditions <= 16) Or (_conditions >= 41 AndAlso _conditions <= 43) Or _conditions = 46 Then
            Return My.Resources.snow
        ElseIf _conditions = 26 Then
            Return My.Resources.overcast_sky
        ElseIf _conditions = 27 Or _conditions = 29 Then
            Return My.Resources.night_partlycloudy
        ElseIf _conditions = 28 Or _conditions = 30 Or _conditions = 44 Then
            Return My.Resources.day_partlyCloudy
        ElseIf _conditions = 31 Or _conditions = 33 Then
            Return My.Resources.moon
        ElseIf _conditions = 32 Or _conditions = 34 Or _conditions = 36 Then
            Return My.Resources.day_clear
        Else
            Return My.Resources.overcast_sky
        End If
    End Function

    Private Sub btnUpdate_Click(sender As System.Object, e As EventArgs) Handles btnUpdate.Click
        Update()
    End Sub

End Class
Chris Hobbs

I found a different way to do it since I'm always looking for just the next 3 days rather than a random/variable number of days

So instead of

MyDoc.SelectSingleNode("/rss/channel/item/yweather:forecast[day='" + _dayOfweek + "']/@low", nsmgr).InnerText

and incrementing the _dayOfWeek, you can skip incrementing, get rid of _dayOfWeek entirely you can actually use

MyDoc.SelectSingleNode("//item/yweather:forecast[1]/@low", nsmgr).InnerText) 

and that will allow you to get the low for the 0th day (I guess XML nodes start at 1, not 0)- then you can just iterate over and get the low/high/code for the 1st, 2nd, and third days.

It took me about a day to get this Yahoo RSS feed weather widget running, if anyone wants to see the final code for it, here you go.

 Public Sub Update()

        Dim rssurl = "http://xml.weather.yahoo.com/forecastrss?p=" + _zip.ToString()
        Dim rssrequest As Net.WebRequest = Net.WebRequest.Create(rssurl)

        Dim rssresponse As Net.WebResponse = rssrequest.GetResponse()
        Dim rssstream As IO.Stream = rssresponse.GetResponseStream()

        Dim rssdoc As New Xml.XmlDocument
        rssdoc.Load(rssstream)

        Dim nodes As Xml.XmlNodeList
        nodes = rssdoc.SelectNodes("/rss/channel")

        lblCityState.Text = Replace(nodes.Item(0).SelectSingleNode("title").InnerText, "Yahoo! Weather - ", "")

        Dim nsmgr = New Xml.XmlNamespaceManager(rssdoc.NameTable)
        nsmgr.AddNamespace("yweather", "http://xml.weather.yahoo.com/ns/rss/1.0")

        'find the conditions and display the correct image for the current weather

        _conditions = rssdoc.SelectSingleNode("/rss/channel/item/yweather:condition/@code", nsmgr).InnerText

        picConditions.BackgroundImage = GetConditions()

        'get the current days highs and lows and picture

        lblCurrentTemp.Text = rssdoc.SelectSingleNode("//item/yweather:condition/@temp", nsmgr).InnerText
        lblLowNow.Text = String.Format("L: {0}", rssdoc.SelectSingleNode("//item/yweather:forecast[1]/@low", nsmgr).InnerText)
        lblHighNow.Text = String.Format("H: {0}", rssdoc.SelectSingleNode("//item/yweather:forecast[1]/@high", nsmgr).InnerText)
        'set the 3 days in the future information below, and get lows highs, picture

        lblDayOne.Text = rssdoc.SelectSingleNode("//item/yweather:forecast[2]/@day", nsmgr).InnerText
        _conditions = rssdoc.SelectSingleNode("//item/yweather:forecast[2]/@code", nsmgr).InnerText
        picDayOne.BackgroundImage = GetConditions()
        lblHighOne.Text = String.Format("H: {0}", rssdoc.SelectSingleNode("//item/yweather:forecast[2]/@low", nsmgr).InnerText)
        lblLowOne.Text = String.Format("L: {0}", rssdoc.SelectSingleNode("//item/yweather:forecast[2]/@high", nsmgr).InnerText)

        lblDayTwo.Text = rssdoc.SelectSingleNode("//item/yweather:forecast[3]/@day", nsmgr).InnerText
        _conditions = rssdoc.SelectSingleNode("//item/yweather:forecast[3]/@code", nsmgr).InnerText
        picDayTwo.BackgroundImage = GetConditions()
        lblHighTwo.Text = String.Format("H: {0}", rssdoc.SelectSingleNode("//item/yweather:forecast[3]/@high", nsmgr).InnerText)
        lblLowTwo.Text = String.Format("L: {0}", rssdoc.SelectSingleNode("//item/yweather:forecast[3]/@low", nsmgr).InnerText)

        lblDayThree.Text = rssdoc.SelectSingleNode("//item/yweather:forecast[4]/@day", nsmgr).InnerText
        _conditions = rssdoc.SelectSingleNode("//item/yweather:forecast[4]/@code", nsmgr).InnerText
        picDayThree.BackgroundImage = GetConditions()
        lblHighThree.Text = String.Format("H: {0}", rssdoc.SelectSingleNode("//item/yweather:forecast[4]/@high", nsmgr).InnerText)
        lblLowThree.Text = String.Format("L: {0}", rssdoc.SelectSingleNode("//item/yweather:forecast[4]/@low", nsmgr).InnerText)

        lblUpdated.Text = String.Format("Updated {0}", rssdoc.SelectSingleNode("//item/yweather:condition/@date", nsmgr).InnerText)

    End Sub

    Public Function GetConditions() As Image
        If (_conditions >= 0 AndAlso _conditions <= 4) Or (_conditions >= 9 AndAlso _conditions <= 12) Or (_conditions >= 37 AndAlso _conditions <= 40) Or _conditions = 45 Or _conditions = 47 Then
            Return My.Resources.raining
        ElseIf (_conditions >= 5 AndAlso _conditions <= 8) Or (_conditions >= 13 AndAlso _conditions <= 16) Or (_conditions >= 41 AndAlso _conditions <= 43) Or _conditions = 46 Then
            Return My.Resources.snow
        ElseIf _conditions = 26 Then
            Return My.Resources.overcast_sky
        ElseIf _conditions = 27 Or _conditions = 29 Then
            Return My.Resources.night_partlycloudy
        ElseIf _conditions = 28 Or _conditions = 30 Or _conditions = 44 Then
            Return My.Resources.day_partlyCloudy
        ElseIf _conditions = 31 Or _conditions = 33 Then
            Return My.Resources.moon
        ElseIf _conditions = 32 Or _conditions = 34 Or _conditions = 36 Then
            Return My.Resources.day_clear
        Else
            Return My.Resources.overcast_sky
        End If
    End Function

    Private Sub btnUpdate_Click(sender As System.Object, e As EventArgs) Handles btnUpdate.Click
        Update()
    End Sub

    Private Sub CtrlWeatherWidget_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
        Update()
        sleepTimer.Start()
    End Sub

    Private Sub sleepTimer_Tick(sender As System.Object, e As System.EventArgs) Handles sleepTimer.Tick
        Update()
    End Sub

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related