Forum Discussion

jitendragaurgkv's avatar
9 years ago

Difficulties Parsing XML

How Can i parse this XML in My code

<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE tv SYSTEM "xmltv.dtd">

<tv source-info-url="http://www.schedulesdirect.org/" source-info-name="Schedules Direct" generator-info-name="XMLTV/$Id: tv_grab_na_dd.in,v 1.70 2008/03/03 15:21:41 rmeden Exp $" generator-info-url="http://www.xmltv.org/">
 <channel id="I10436.labs.zap2it.com">
   <display-name>13 KERA</display-name>
   <display-name>13 KERA TX42822:-</display-name>
   <display-name>13</display-name>
   <display-name>13 KERA fcc</display-name>
   <display-name>KERA</display-name>
   <display-name>KERA</display-name>
   <display-name>PBS Affiliate</display-name>
   <icon src="file://C:\Perl\site/share/xmltv/icons/KERA.gif" />
 </channel>
 <channel id="I10759.labs.zap2it.com">
   <display-name>11 KTVT</display-name>
   <display-name>11 KTVT TX42822:-</display-name>
   <display-name>11</display-name>
   <display-name>11 KTVT fcc</display-name>
   <display-name>KTVT</display-name>
   <display-name>KTVT</display-name>
   <display-name>CBS Affiliate</display-name>
   <icon src="file://C:\Perl\site/share/xmltv/icons/KTVT.gif" />
 </channel>
 <programme start="20080715003000 -0600" stop="20080715010000 -0600" channel="I10436.labs.zap2it.com">
   <title lang="en">NOW on PBS</title>
   <desc lang="en">Jordan's Queen Rania has made job creation a priority to help curb the staggering unemployment rates among youths in the Middle East.</desc>
   <date>20080711</date>
   <category lang="en">Newsmagazine</category>
   <category lang="en">Interview</category>
   <category lang="en">Public affairs</category>
   <category lang="en">Series</category>
   <episode-num system="dd_progid">EP01006886.0028</episode-num>
   <episode-num system="onscreen">427</episode-num>
   <audio>
     <stereo>stereo</stereo>
   </audio>
   <previously-shown start="20080711000000" />
   <subtitles type="teletext" />
 </programme>
 <programme start="20080715010000 -0600" stop="20080715023000 -0600" channel="I10436.labs.zap2it.com">
   <title lang="en">Mystery!</title>
   <sub-title lang="en">Foyle's War, Series IV: Bleak Midwinter</sub-title>
   <desc lang="en">Foyle investigates an explosion at a munitions factory, which he comes to believe may have been premeditated.</desc>
   <date>20070701</date>
   <category lang="en">Anthology</category>
   <category lang="en">Mystery</category>
   <category lang="en">Series</category>
   <episode-num system="dd_progid">EP00003026.0665</episode-num>
   <episode-num system="onscreen">2705</episode-num>
   <audio>
     <stereo>stereo</stereo>
   </audio>
   <previously-shown start="20070701000000" />
   <subtitles type="teletext" />
 </programme>
 <programme start="20080715023000 -0600" stop="20080715040000 -0600" channel="I10436.labs.zap2it.com">
   <title lang="en">Mystery!</title>
   <sub-title lang="en">Foyle's War, Series IV: Casualties of War</sub-title>
   <desc lang="en">The murder of a prominent scientist may have been due to a gambling debt.</desc>
   <date>20070708</date>
   <category lang="en">Anthology</category>
   <category lang="en">Mystery</category>
   <category lang="en">Series</category>
   <episode-num system="dd_progid">EP00003026.0666</episode-num>
   <episode-num system="onscreen">2706</episode-num>
   <audio>
     <stereo>stereo</stereo>
   </audio>
   <previously-shown start="20070708000000" />
   <subtitles type="teletext" />
 </programme>
 <programme start="20080715040000 -0600" stop="20080715043000 -0600" channel="I10436.labs.zap2it.com">
   <title lang="en">BBC World News</title>
   <desc lang="en">International issues.</desc>
   <category lang="en">News</category>
   <category lang="en">Series</category>
   <episode-num system="dd_progid">SH00315789.0000</episode-num>
   <previously-shown />
   <subtitles type="teletext" />
 </programme>
 <programme start="20080715043000 -0600" stop="20080715050000 -0600" channel="I10436.labs.zap2it.com">
   <title lang="en">Sit and Be Fit</title>
   <date>20070924</date>
   <category lang="en">Exercise</category>
   <category lang="en">Series</category>
   <episode-num system="dd_progid">EP00003847.0074</episode-num>
   <episode-num system="onscreen">901</episode-num>
   <audio>
     <stereo>stereo</stereo>
   </audio>
   <previously-shown start="20070924000000" />
   <subtitles type="teletext" />
 </programme>
 <programme start="20080715060000 -0600" stop="20080715080000 -0600" channel="I10759.labs.zap2it.com">
   <title lang="en">The Early Show</title>
   <desc lang="en">Republican candidate John McCain; premiere of the film "The Dark Knight."</desc>
   <date>20080715</date>
   <category lang="en">Talk</category>
   <category lang="en">News</category>
   <category lang="en">Series</category>
   <episode-num system="dd_progid">EP00337003.2361</episode-num>
   <audio>
     <stereo>stereo</stereo>
   </audio>
   <subtitles type="teletext" />
 </programme>
 <programme start="20080715080000 -0600" stop="20080715090000 -0600" channel="I10759.labs.zap2it.com">
   <title lang="en">Rachael Ray</title>
   <desc lang="en">Actresses Kim Raver, Brooke Shields and Lindsay Price ("Lipstick Jungle"); women in their 40s tell why they got breast implants; a 30-minute meal.</desc>
   <credits>
     <presenter>Rachael Ray</presenter>
   </credits>
   <date>20080306</date>
   <category lang="en">Talk</category>
   <category lang="en">Series</category>
   <episode-num system="dd_progid">EP00847333.0303</episode-num>
   <episode-num system="onscreen">2119</episode-num>
   <audio>
     <stereo>stereo</stereo>
   </audio>
   <previously-shown start="20080306000000" />
   <subtitles type="teletext" />
 </programme>
 <programme start="20080715090000 -0600" stop="20080715100000 -0600" channel="I10759.labs.zap2it.com">
   <title lang="en">The Price Is Right</title>
   <desc lang="en">Contestants bid for prizes then compete for fabulous showcases.</desc>
   <credits>
     <director>Bart Eskander</director>
     <producer>Roger Dobkowitz</producer>
     <presenter>Drew Carey</presenter>
   </credits>
   <category lang="en">Game show</category>
   <category lang="en">Series</category>
   <episode-num system="dd_progid">SH00004372.0000</episode-num>
   <audio>
     <stereo>stereo</stereo>
   </audio>
   <subtitles type="teletext" />
   <rating system="VCHIP">
     <value>TV-G</value>
   </rating>
 </programme>
 <programme start="20080715100000 -0600" stop="20080715103000 -0600" channel="I10759.labs.zap2it.com">
   <title lang="en">Jeopardy!</title>
   <credits>
     <presenter>Alex Trebek</presenter>
   </credits>
   <date>20080715</date>
   <category lang="en">Game show</category>
   <category lang="en">Series</category>
   <episode-num system="dd_progid">EP00002348.1700</episode-num>
   <episode-num system="onscreen">5507</episode-num>
   <subtitles type="teletext" />
   <rating system="VCHIP">
     <value>TV-G</value>
   </rating>
 </programme>
 <programme start="20080715103000 -0600" stop="20080715113000 -0600" channel="I10759.labs.zap2it.com">
   <title lang="en">The Young and the Restless</title>
   <sub-title lang="en">Sabrina Offers Victoria a Truce</sub-title>
   <desc lang="en">Jeff thinks Kyon stole the face cream; Nikki asks Nick to give David a chance; Amber begs Adrian to go to Australia.</desc>
   <credits>
     <actor>Peter Bergman</actor>
     <actor>Eric Braeden</actor>
     <actor>Jeanne Cooper</actor>
     <actor>Melody Thomas Scott</actor>
   </credits>
   <date>20080715</date>
   <category lang="en">Soap</category>
   <category lang="en">Series</category>
   <episode-num system="dd_progid">EP00004422.1359</episode-num>
   <episode-num system="onscreen">8937</episode-num>
   <audio>
     <stereo>stereo</stereo>
   </audio>
   <subtitles type="teletext" />
   <rating system="VCHIP">
     <value>TV-14</value>
   </rating>
 </programme>
</tv>


My Code
sub Main ()
    displayTVListingsScreen (getSettings ())
end sub

'
' Get application-wide settings
'
function getSettings () as object

    settings = {}
    
    settings.numGridRows        = 6                      ' Supports 4 to 8 channel rows per page
    settings.newDisplayFormat   = true                   ' Use grid display format rather than single-program display. ['*' key toggles between display formats]
    
    settings.colorBG            = "#FF101010"            ' Black [Roku R, G, B color values should not be less than 16]
    settings.colorHeaderBG      = "#FF3A3A3A"            ' Very dark grey
    settings.colorFooter        = "#FF3F3F3F"            ' Medium grey
    settings.colorEven          = "#FF7F7F7F"            ' Light grey
    settings.colorOdd           = "#FF5F5F5F"            ' Darker grey
    settings.colorText          = "#FFEBEBEB"            ' White [Roku R, G, B color values should not be greater than 235]
    
    settings.deviceInfo = getDeviceInfo ()
    settings.font = getFont (settings.deviceInfo.sd, settings.newDisplayFormat, settings.numGridRows)
    settings.dimensions = getDimensions (settings.newDisplayFormat, settings.numGridRows, settings.deviceInfo, settings.font)
    
    return settings
    
end function

'
' Get device-specific settings (fixed for the life of the program)
'
function getDeviceInfo () as object

    deviceInfo = {}

    ' Get Roku's device info
    deviceInfo.di = CreateObject ("roDeviceInfo")
    
    ' Get the TV's display size
    deviceInfo.displaySize = deviceInfo.di.GetDisplaySize ()
    deviceInfo.displayMode = deviceInfo.di.GetDisplayMode ()
    
    ' Get the TV's display mode (true=SD, false=HD)
    if deviceInfo.displayMode = "480i"
        deviceInfo.sd = true
    else
        deviceInfo.sd = false
    endif

    ' Get the current time zone
    tz = deviceInfo.di.GetTimeZone ()
    
    ' Use 7 pm as prime time for Mountain/Central time zones, otherwise 8 pm
    ' Don't adjust time for Canada/Mountain time as they often broadcast on US Pacific time slots
    if tz = "US/Mountain" or tz = "US/Central" or tz = "Canada/Central"
        deviceInfo.primeTime = 19
    else
        deviceInfo.primeTime = 20
    endif
    
    return deviceInfo

end function

'
' Load the font required depending on the number of TV grid rows selected
'
function getFont (sd as boolean, newDisplayFormat as boolean, numGridRows as integer) as object

    font = {}

    minRows = 4
    maxRows = 8

    if numGridRows < minRows
        numGridRows = minRows
    else if numGridRows > maxRows
        numGridRows = maxRows
    endif

    rowIndex = numGridRows - minRows

    ' Font used: http://www.dafont.com/liberation-sans.font
    ' (GNU General Public License v.2)
    fontFile = "pkg:/fonts/Font.ttf"
    fontName = "Liberation Sans"

    ' The font size varies with the number of grid rows
    ' yOffset is a fine-tuning mechanism to center the text vertically within each grid row
    
    if sd
        '                                  4,  5,  6,  7,  8                4,  5,  6,  7,  8
        if newDisplayFormat
            mediumFont =    { fontSize: [ 28, 24, 21, 19, 17 ], yOffset: [ +0, +0, -2, -2, -2 ] }
            smallFont =     { fontSize: [ 22, 20, 18, 16, 15 ], yOffset: [ +0, +6, -1, +0, +0 ] }
        else
            mediumFont =    { fontSize: [ 28, 24, 21, 19, 17 ], yOffset: [ +0, +0, -2, -2, -2 ] }
            smallFont =     { fontSize: [ 22, 19, 17, 16, 14 ], yOffset: [ +0, +2, -1, -3, -2 ] }
        endif
    else ' hd
        if newDisplayFormat
            mediumFont =    { fontSize: [ 42, 37, 33, 29, 24 ], yOffset: [ -1, +0, -2, +0, +0 ] }
            smallFont =     { fontSize: [ 34, 32, 27, 23, 20 ], yOffset: [ -3, +3, +2, +3, +0 ] }
        else
            mediumFont =    { fontSize: [ 42, 37, 33, 29, 24 ], yOffset: [ -1, +0, -2, -2, +0 ] }
            smallFont =     { fontSize: [ 36, 30, 27, 24, 20 ], yOffset: [ +1, +0, -1, -4, -1 ] }
        endif
    endif

    font.fontRegistry = CreateObject ("roFontRegistry")
    font.fontRegistry.Register (fontFile)

    font.mediumFont = {}
    font.mediumFont.yOffset = mediumFont.yOffset [rowIndex]
    font.mediumFont.family = font.fontRegistry.Get (fontName, mediumFont.fontSize [rowIndex], 50, false)
    font.mediumFont.metrics = CreateObject ("roFontMetrics", font.mediumFont.family)

    font.smallFont = {}
    font.smallFont.yOffset = smallFont.yOffset [rowIndex]
    font.smallFont.family = font.fontRegistry.Get (fontName, smallFont.fontSize [rowIndex], 50, false)
    font.smallFont.metrics = CreateObject ("roFontMetrics", font.smallFont.family)
    
    return font
    
end function

'
' Calculate TV grid program display dimensions
'
function getDimensions (newDisplayFormat as boolean, numGridRows as integer, deviceInfo as object, font as object) as object
    
    ' Make use of the 'Action Safe Zone' for display dimensions
    '    HD->1150x646 starting at (64, 35)
    '    SD->648x432, starting at (36, 24)
    if deviceInfo.displayMode = "720p"                                        ' 720 x 1280 display (HD)
        displayH% = 646                                                       ' (720 - 2) * 0.9
        displayW% = 1150                                                      ' (1280 - 2) * 0.9
        displayX% = 64                                                        ' 64 + 1150 + 64 = (1280 - 2)
        displayY% = 35                                                        ' 35 + 646 + 35 = (720 - 4)
    else if deviceInfo.displayMode = "480i"                                   ' 480 x 720 display (SD)
        displayH% = 432                                                       ' 0.9 x 480
        displayW% = 648                                                       ' 0.9 x 720
        displayX% = 36                                                        ' 36 + 432 + 36 = 480
        displayY% = 24                                                        ' 24 + 648 + 24 = 720
    else                                                                      ' Unknown display type
        displayH% = deviceInfo.displaySize.H * 0.9                            ' Set the height to 90% of available screen height
        displayW% = deviceInfo.displaySize.W * 0.9                            ' Scale width to 90% of available screen width
        displayX% = (deviceInfo.displaySize.W - displayW%) / 2                ' Center horizontally
        displayY% = (deviceInfo.displaySize.H - displayH%) / 2                ' Center vertically
    endif

    ' Calculate dimensions of program grid rows
    gridRowH% = (displayH% * 0.93) / numGridRows                              ' Grid row height [reserve 7% of display height for header row]
    gridRowW% = displayW%                                                     ' Program grid occupies entire width of display area
    gridRowX% = displayX%                                                     ' Program grid starts at beginning of display width
    gridRowY% = displayY% + displayH% - (gridRowH% * numGridRows)             ' For first row only, program grid starts at end of header row.
        
    ' Calculate dimensions of header area
    headerRowX% = displayX%                                                   ' Header row starts at beginning of display width
    headerRowY% = displayY%                                                   ' Header row starts at beginning if display height
    headerRowW% = displayW%                                                   ' Header row occupies entire display width
    headerRowH% = displayH% - (gridRowH% * numGridRows)                       ' Header row occupies portion of display height not occupied by program grid rows

    ' Determine the pixel widths for program display
    channelLogoX% = gridRowX% + 10                                            ' Allow some space to the left of the logo
    channelNameW% = font.smallFont.metrics.Size ("WWWWWWW").W * 0.8           ' Only used on single program display
    channelLogoW% = gridRowH%                                                 ' Width occupied by channel logo/channel number
    channelLogoH% = gridRowH% * 2 / 3                                         ' Logo height
    channelLogoImgX% = channelLogoX% + (channelLogoW% - channelLogoH%) / 2    ' Center logo image
    channelNumberH% = gridRowH% - channelLogoH%                               ' Channel number height
    channelNameX% = channelLogoX% + channelLogoW% + 10                        ' Only used for old display mode
    
    if newDisplayFormat
    '
    ' New display format
    '
        programDetailsX% = channelLogoX% + channelLogoW% + 10
        SMALLINTERVAL = 60                                                    ' How much to advance through listings if > key pressed
        LARGEINTERVAL = 180                                                   ' How much to advance through listings if >> key pressed
        SMALLDECREMENT = 60                                                   ' How much to back up through listings if < key pressed
        LARGEDECREMENT = 180                                                  ' How much to back up through listings if << key pressed
        DISPLAYWINDOW = 180                                                   ' When paging forward through listings, to determine if we'll exceed the end of the listings window
    else
    '
    ' Old display format
    '
        programDetailsX% = channelNameX% + channelNameW%                      ' Start of program details area
        SMALLINTERVAL = 30                                                    ' How much to advance through listings if > key pressed
        LARGEINTERVAL = 60                                                    ' How much to advance through listings if >> key pressed
        SMALLDECREMENT = 120                                                  ' How much to back up through listings if < key pressed
        LARGEDECREMENT = 120                                                  ' How much to back up through listings if << key pressed
        DISPLAYWINDOW = 0                                                     ' When paging forward through listings, to determine if we'll exceed the end of the listings window
    endif
    
    programDetailsW% = gridRowW% - programDetailsX%                           ' Width of program details area
    
    dimensions = {
                    displaySizeW: deviceInfo.displaySize.W,
                    displaySizeH: deviceInfo.displaySize.H,
                    displayH: displayH%,
                    displayW: displayW%,
                    displayX: displayX%,
                    displayY: displayY%,
                    headerRowX: headerRowX%,
                    headerRowY: headerRowY%,
                    headerRowW: headerRowW%,
                    headerRowH: headerRowH%,
                    gridRowX: gridRowX%,
                    gridRowY: gridRowY%,
                    gridRowW: gridRowW%,
                    gridRowH: gridRowH%,
                    channelLogoImgX: channelLogoImgX%,
                    channelLogoX: channelLogoX%,
                    channelLogoW: channelLogoW%,
                    channelLogoH: channelLogoH%,
                    channelNameX: channelNameX%,
                    channelNameW: channelNameW%,
                    channelNumberH: channelNumberH%,
                    programDetailsX: programDetailsX%,
                    programDetailsW: programDetailsW%,
                    SMALLINTERVAL: SMALLINTERVAL,
                    LARGEINTERVAL: LARGEINTERVAL,
                    SMALLDECREMENT: SMALLDECREMENT,
                    LARGEDECREMENT: LARGEDECREMENT,
                    DISPLAYWINDOW: DISPLAYWINDOW,
                }

    return dimensions
    
end function

'*******************************
' Display the TV Listings screen
'*******************************
sub displayTVListingsScreen (settings as object)

    primeTime = settings.deviceInfo.primeTime
    numGridRows = settings.numGridRows
    dimensions = settings.dimensions

    port = CreateObject ("roMessagePort")
    
    ' Use an roImageCanvas object that occupies the whole screen for the channel listings grid
    canvas = CreateObject ("roImageCanvas")
    canvas.SetMessagePort (port)
    canvas.AllowUpdates (false)
    
    staticLayer = []

    ' Background
    staticLayer.Push ({Color: settings.colorBG, CompositionMode: "Source"})

    ' Timespan header background
    staticLayer.Push ({
                        TargetRect: {X: 0, Y: dimensions.headerRowY, W: dimensions.displaySizeW, H: dimensions.headerRowH},
                        Color: settings.colorHeaderBG,
                        CompositionMode: "Source"
                    })

    ' Channel background
    nextGridRowY = dimensions.gridRowY
    for row = 0 to numGridRows - 1
        if row mod 2 = 0
            channelBackgroundColor = settings.colorEven
        else
            channelBackgroundColor = settings.colorOdd
        endif
        staticLayer.Push ({
                            TargetRect: {X: 0, Y: nextGridRowY, W: dimensions.displaySizeW, H: dimensions.gridRowH},
                            Color: channelBackgroundColor,
                            CompositionMode: "Source"
                        })
        nextGridRowY = nextGridRowY + dimensions.gridRowH
    end for

    ' Add the static background layer
    canvas.SetLayer (0, staticLayer)
    
    canvas.Show ()

    ' Get the TV Listings
    xml = getTVListings ()
    if xml = Invalid
        displayMessageDialog (["TV Listings Error", "Unable to Retrieve TV Listings"])
        return
    endif
    
    channelCount = xml.Channel.Count ()
    if channelCount = 0
        displayMessageDialog (["TV Listings Error", "No TV Listings found"])
        return
    endif
    
    ' All ...Time fields handle UTC time in seconds
    startTime = getXmlUTCInSecs (xml.TimeInfo.StartTimeUTC)
    endTime = getXmlUTCInSecs (xml.TimeInfo.EndTimeUTC)
    currentTime = startTime
    currentTimeStr = timeToStr (currentTime)
    
    ' Channel details layer
    canvas.SetLayer (1, getChannelLayer (settings, xml, 0, currentTime, currentTimeStr, startTime))
    canvas.AllowUpdates (true)
    
    channelIndex = 0
    
    while true
        msg = Wait (0, port)
        if type (msg) = "roImageCanvasEvent"
            if msg.IsScreenClosed ()
                exit while
            else if msg.IsRemoteKeyPressed ()
                key = msg.GetIndex ()
                
                ' <DOWN> Next Channel Group
                if key = 3
                    if channelCount > numGridRows        ' No change if only one page of channels
                        channelIndex = channelIndex + numGridRows
                        if channelIndex >= channelCount
                            channelIndex = 0
                            if channelIndex >= channelCount then channelIndex = channelCount - 1
                        endif
                        canvas.SetLayer (1, getChannelLayer (settings, xml, channelIndex, currentTime, currentTimeStr, startTime))
                    endif
                    
                ' <UP> Previous Channel Group
                else if key = 2
                    if channelCount > numGridRows        ' No change if only one page of channels
                        if channelIndex > 0 and channelIndex < numGridRows
                            channelIndex = 0
                        else
                            channelIndex = channelIndex - numGridRows
                            if channelIndex < 0
                                channelIndex = channelCount - numGridRows
                                if channelIndex < 0 then channelIndex = 0
                            endif
                        endif
                        canvas.SetLayer (1, getChannelLayer (settings, xml, channelIndex, currentTime, currentTimeStr, startTime))
                    endif
                    
                ' <RIGHT> Next Time Period (+30 mins)
                else if key = 5
                    currentTime = currentTime + (dimensions.SMALLINTERVAL * 60)
                    currentTimeStr = timeToStr (currentTime)
                    if currentTime + dimensions.DISPLAYWINDOW * 60 >= endTime
                        ' We've reached the end of the time period for the current grid
                        tvListings = getTVListings (currentTime.ToStr ())
                        if tvListings = Invalid
                            return
                        endif
                        channelCount = xml.Channel.Count ()
                        startTime = getXmlUTCInSecs (xml.TimeInfo.StartTimeUTC, currentTime)
                        endTime = getXmlUTCInSecs (xml.TimeInfo.EndTimeUTC, currentTime)
                        ' Allow for case when TV listings returned for a different time from what was requested
                        if (startTime > currentTime and endTime > currentTime) or (startTime < currentTime and endTime < currentTime)
                            currentTime = startTime
                            currentTimeStr = timeToStr (currentTime)
                        endif
                        if channelCount = 0
                            displayMessageDialog (["TV Listings Error", "No TV Listings found"])
                            canvas.Close ()
                            return
                        endif
                    endif
                    canvas.SetLayer (1, getChannelLayer (settings, xml, channelIndex, currentTime, currentTimeStr, startTime))
                    
                ' <LEFT> Previous Time Period (-30 mins)
                else if key = 4
                    currentTime = currentTime - (dimensions.SMALLINTERVAL * 60)
                    currentTimeStr = timeToStr (currentTime)
                    if currentTime < startTime
                        tvListings = getTVListings ((startTime - (dimensions.SMALLDECREMENT * 60)).ToStr ())
                        if tvListings = Invalid
                            return
                        endif
                        channelCount = xml.Channel.Count ()
                        startTime = getXmlUTCInSecs (xml.TimeInfo.StartTimeUTC, currentTime)
                        endTime = getXmlUTCInSecs (xml.TimeInfo.EndTimeUTC, currentTime)
                        if (startTime > currentTime and endTime > currentTime) or (startTime < currentTime and endTime < currentTime)
                            currentTime = startTime
                            currentTimeStr = timeToStr (currentTime)
                        endif
                        if channelCount = 0
                            displayMessageDialog (["TV Listings Error", "No TV Listings found"])
                            canvas.Close ()
                            return
                        endif
                    endif
                    canvas.SetLayer (1, getChannelLayer (settings, xml, channelIndex, currentTime, currentTimeStr, startTime))
                    
                ' <REW> Previous Time Period (-60 mins)
                else if key = 8
                    currentTime = currentTime - (dimensions.LARGEINTERVAL * 60)
                    currentTimeStr = timeToStr (currentTime)
                    if currentTime < startTime
                        tvListings = getTVListings ((startTime - (dimensions.LARGEDECREMENT * 60)).ToStr ())
                        if tvListings = Invalid
                            return
                        endif
                        channelCount = xml.Channel.Count ()
                        startTime = getXmlUTCInSecs (xml.TimeInfo.StartTimeUTC, currentTime)
                        endTime = getXmlUTCInSecs (xml.TimeInfo.EndTimeUTC, currentTime)
                        if (startTime > currentTime and endTime > currentTime) or (startTime < currentTime and endTime < currentTime)
                            currentTime = startTime
                            currentTimeStr = timeToStr (currentTime)
                        endif
                        if channelCount = 0
                            displayMessageDialog (["TV Listings Error", "No TV Listings found"])
                            canvas.Close ()
                            return
                        endif
                    endif
                    canvas.SetLayer (1, getChannelLayer (settings, xml, channelIndex, currentTime, currentTimeStr, startTime))
                    
                ' <FF> Next Time Period (+60 mins)
                else if key = 9
                    currentTime = currentTime + (dimensions.LARGEINTERVAL * 60)
                    currentTimeStr = timeToStr (currentTime)
                    if currentTime + dimensions.DISPLAYWINDOW * 60 >= endTime
                        ' We've reached the end of the time period for the current grid
                        tvListings = getTVListings (currentTime.ToStr ())
                        if tvListings = Invalid
                            return
                        endif
                        channelCount = xml.Channel.Count ()
                        startTime = getXmlUTCInSecs (xml.TimeInfo.StartTimeUTC, currentTime)
                        endTime = getXmlUTCInSecs (xml.TimeInfo.EndTimeUTC, currentTime)
                        if (startTime > currentTime and endTime > currentTime) or (startTime < currentTime and endTime < currentTime)
                            currentTime = startTime
                            currentTimeStr = timeToStr (currentTime)
                        endif
                        if channelCount = 0
                            displayMessageDialog (["TV Listings Error", "No TV Listings found"])
                            canvas.Close ()
                            return
                        endif
                    endif
                    canvas.SetLayer (1, getChannelLayer (settings, xml, channelIndex, currentTime, currentTimeStr, startTime))
                    
                ' <Play/Pause> Go to Prime Time
                else if key = 13
                    ' Prime Time is considered to be the next occurence of 8pm (2000 hrs local time) after the current time
                    dt = CreateObject ("roDateTime")
                    dt.FromSeconds (currentTime)
                    dt.ToLocalTime ()
                    hh = dt.GetHours ()
                    mm = dt.GetMinutes ()
                    ss = dt.GetSeconds ()
                    if hh < primeTime
                        secsFromMidnight = ((hh * 60) + mm) * 60 + ss
                        nextPrimeTime = currentTime - secsFromMidnight + (primeTime * 60 * 60)
                    else
                        secsFromPrimeTime = (((hh - primeTime) * 60) + mm) * 60 + ss
                        nextPrimeTime = currentTime - secsFromPrimeTime + (24 * 60 * 60)
                    endif
                    currentTime = nextPrimeTime
                    currentTimeStr = timeToStr (currentTime)
                    tvListings = getTVListings (currentTime.ToStr ())
                    if tvListings = Invalid
                        return
                    endif
                    channelCount = xml.Channel.Count ()
                    startTime = getXmlUTCInSecs (xml.TimeInfo.StartTimeUTC, currentTime)
                    endTime = getXmlUTCInSecs (xml.TimeInfo.EndTimeUTC, currentTime)
                    if (startTime > currentTime and endTime > currentTime) or (startTime < currentTime and endTime < currentTime)
                        currentTime = startTime
                        currentTimeStr = timeToStr (currentTime)
                    endif
                    if channelCount = 0
                        displayMessageDialog (["TV Listings Error", "No TV Listings found"])
                        canvas.Close ()
                        return
                    endif
                    canvas.SetLayer (1, getChannelLayer (settings, xml, channelIndex, currentTime, currentTimeStr, startTime))
                
                ' <OK> or <BACK> Back to Main Screen    
                else if key = 6    or key = 0
                    canvas.Close ()
                    
                ' * - Change display format
                else if key = 10
                    toggleDisplayFormat (settings)
                    dimensions = settings.dimensions
                    ' If switching to the new display format, set the current time to the start of the listings window
                    if settings.newDisplayFormat
                        startTime = getXmlUTCInSecs (xml.TimeInfo.StartTimeUTC)
                        endTime = getXmlUTCInSecs (xml.TimeInfo.EndTimeUTC)
                        currentTime = startTime
                        currentTimeStr = timeToStr (currentTime)
                    endif
                    canvas.SetLayer (1, getChannelLayer (settings, xml, channelIndex, currentTime, currentTimeStr, startTime))
                endif
                
            endif
        endif
    end while

end sub

'****************
' Get TV listings
'****************
function getTVListings (timeInSecs = "" as string) as object

    loadingDialog = displayLoadingDialog ()
    
    xmlData = ReadAsciiFile ("pkg:/xml/example.xml")
    xml = CreateObject ("roXMLElement")
    if not xml.Parse (xmlData)
        xml = Invalid
    endif
    
    closeLoadingDialog (loadingDialog)
    
    return xml

end function

function timeToStr (displayTime as integer) as string

    ' Get the present time
    dtNow = CreateObject ("roDateTime")
    dtNow.Mark ()
    dtNow.ToLocalTime ()

    ' Calculate the start time for the time span of the displayed time
    dt = CreateObject ("roDateTime")
    dt.FromSeconds (displayTime)
    dt.ToLocalTime ()
    h = dt.GetHours ()
    mm = dt.GetMinutes () : mmStr = Right ("0" + mm.ToStr (), 2)
    if h = 0 and mm = 0
        timeStr = "Midnight"
    else if h = 12 and mm = 0
        timeStr = "Noon"
    else
        if h >= 12
            ap = "pm"
            if h > 12 then h = h - 12
        else
            ap = "am"
        endif
        timeStr = h.ToStr () + ":" + mmStr + " " + ap
    endif

    ' If the date of the displayed time is not the current date then display the date as well as the displayed time
    if dtNow.AsDateString ("short-date") <> dt.AsDateString ("short-date")
        monthList = ["", "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"]
        timeStr = Left (dt.GetWeekday (), 3) + " " + monthList [dt.GetMonth ()] + " " + dt.GetDayOfMonth ().ToStr () +  " - " + timeStr
    endif

    return timeStr

end function

function getChannelLayer (settings as object, xml as object, channelIndex as integer, currentTime as integer, currentTimeStr as string, startTime as integer) as object

    dimensions = settings.dimensions
    font = settings.font
    
    ' Duration is the total time span for program results returned in this XML response (should be 3 hours)
    duration = getXmlUTCInSecs (xml.TimeInfo.EndTimeUTC) - getXmlUTCInSecs (xml.TimeInfo.StartTimeUTC)

    layer = []

    ' Header containing timespan
    if not settings.newDisplayFormat
    '
    ' Old display format
    '
        layer.Push ({
                        TargetRect: {X: dimensions.headerRowX, Y: dimensions.headerRowY, W: dimensions.headerRowW, H: dimensions.headerRowH},
                        Text: currentTimeStr,
                        TextAttrs: {Color: settings.colorText, Font: font.mediumFont.family, HAlign: "Center", VAlign: "Middle"}
                    })
    else
    '
    ' New display format
    '
        ' Display the day and the start time
        startDay = timeToDay (startTime)
        layer.Push ({
                        TargetRect: {X: dimensions.headerRowX, Y: dimensions.headerRowY, W: dimensions.programDetailsX - dimensions.headerRowX, H: dimensions.headerRowH},
                        Text: startDay,
                        TextAttrs: {Color: settings.colorText, Font: font.mediumFont.family, HAlign: "Left", VAlign: "Middle"}
                    })
        startHMMA = timeToHMMA2 (startTime)
        timeX% = dimensions.programDetailsX
        timeW% = dimensions.programDetailsW * 60 * 60 / duration
        layer.Push ({
                        TargetRect: {X: timeX%, Y: dimensions.headerRowY, W: timeW%, H: dimensions.headerRowH},
                        Text: startHMMA,
                        TextAttrs: {Color: settings.colorText, Font: font.mediumFont.family, HAlign: "Left", VAlign: "Middle"}
                    })
        
        ' Display the start time + 60 mins if there is at least 2 hours' worth of listings
        if duration >= 120 * 60
            startHMMA = timeToHMMA2 (startTime + 60 * 60)
            timeStr = startHMMA
            timeX% = dimensions.programDetailsX + timeW%
            timeW% = dimensions.programDetailsW * 120 * 60 / duration
            layer.Push ({
                            TargetRect: {X: timeX%, Y: dimensions.headerRowY, W: timeW%, H: dimensions.headerRowH},
                            Text: timeStr,
                            TextAttrs: {Color: settings.colorText, Font: font.mediumFont.family, HAlign: "Left", VAlign: "Middle"}
                        })
        endif
        
        ' Display the start time + 120  if there is at least 3 hours' worth of listings
        if duration >= 180 * 60
            startHMMA = timeToHMMA2 (startTime + 120 * 60)
            timeStr = startHMMA
            timeX% = dimensions.programDetailsX + timeW%
            timeW% = dimensions.programDetailsW * 180 * 60 / duration
            layer.Push ({
                            TargetRect: {X: timeX%, Y: dimensions.headerRowY, W: timeW%, H: dimensions.headerRowH},
                            Text: timeStr,
                            TextAttrs: {Color: settings.colorText, Font: font.mediumFont.family, HAlign: "Left", VAlign: "Middle"}
                        })
        endif
        
        ' Don't attempt to display more that 3 hours' worth of listings
        if duration > 180 * 60
            duration = 180 * 60
        endif
        
    endif
    
    nextGridRowY = dimensions.gridRowY
    
    '
    ' Display each row of channel information
    '
    for row = 0 to settings.numGridRows - 1
        channel = xml.Channel [channelIndex]
        logoUrl = ""
        
        ' Channel background
        if row mod 2 = 0
            channelBackgroundColor = settings.colorEven
        else
            channelBackgroundColor = settings.colorOdd
        endif
        layer.Push ({
                        TargetRect: {X: 0, Y: nextGridRowY, W: dimensions.displayW, H: dimensions.gridRowH},
                        Color: channelBackgroundColor,
                        CompositionMode: "Source"
                    })
        
        if not settings.newDisplayFormat
        '
        ' Single Program display format
        '
            ' Channel Logo
            logoUrl = getXmlString (channel.ChannelData.ChannelLogo)
            if logoUrl <> ""
                layer.Push ({
                                TargetRect: {X: dimensions.channelLogoImgX, Y: nextGridRowY, W: dimensions.channelLogoH, H: dimensions.channelLogoH},
                                Url: logoUrl
                            })
            endif

            ' Channel Number
            channelNumber = getXmlString (channel.ChannelData.ChannelNumber)
            channelNumberBox = textBoxCreate (dimensions.channelLogoX, nextGridRowY + dimensions.channelLogoH, dimensions.channelLogoW, dimensions.channelNumberH, settings.colorText, "Center")
            channelNumberBox.addLine (channelNumber, font.mediumFont, dimensions.channelLogoW)
            channelNumberBox.addToLayer (layer)

            ' Channel Name
            channelName = getXmlString (channel.ChannelData.ChannelName)
            channelNameBox = textBoxCreate (dimensions.channelNameX, nextGridRowY + 3, dimensions.channelNameW, dimensions.gridRowH, settings.colorText)
            channelNameBox.addLine (channelName, font.smallFont)
            channelNameBox.addToLayer (layer)

            ' Program Details
            currentProgram = Invalid
            program = Invalid
            ' Loop for each program for this channel
            for programIndex = 0 to channel.ProgramList.Program.Count () - 1
                program = channel.ProgramList.Program [programIndex]
                startTimeSecs = getXmlInteger (program.StartSecs) + startTime
                endTimeSecs = getXmlInteger (program.EndSecs) + startTime
                ' Display the first program having an end time greater than the current display time (or the last program)
                if endTimeSecs > currentTime and currentProgram = Invalid
                    currentProgram = program
                endif
                ' Give preferential display to programs that are less than 30 minutes long and don't start on or span a half-hour boundary
                if startTimeSecs > currentTime and endTimeSecs <= (currentTime + 30 * 60)
                    currentProgram = program
                endif
            end for
            
            ' If a program was found then use it, otherwise use the last program encountered
            if currentProgram <> Invalid
                program = currentProgram
            endif

            if program <> Invalid
                programName = getXmlString (program.ProgramName)
                programYear = getXmlString (program.ProgramYear)
                programDesc = getXmlString (program.ProgramDescription)
                startTimeSecs =  getXmlInteger (program.StartSecs) + startTime        ' program.StartSecs is start time (secs) relative to start of XML
                endTimeSecs =  getXmlInteger (program.EndSecs) + startTime        ' program.EndSecs is end time (secs) relative to start of XML
                if startTimeSecs <> 0 then startTimeStr = timeToHMMA (startTimeSecs) else startTimeStr = ""
                if endTimeSecs <> 0 then endTimeStr = timeToHMMA (endTimeSecs) else endTimeStr = ""
                runTime = getXmlString (program.RuntimeMins)                            ' program.RuntimeMins is total duration (mins) of the program
                attributesConcat = getXmlString (program.ProgramAttributes)
                displayTime = startTimeStr + "-" + endTimeStr + "  (" + runTime + " mins)" + "    " + attributesConcat            
                programDetailsBox = textBoxCreate (dimensions.programDetailsX, nextGridRowY + 0, dimensions.programDetailsW, dimensions.gridRowH - 2, settings.colorText)
                programDetailsBox.addLine (programName + "  " + programYear,  font.mediumFont)
                programDetailsBox.addLine (programDesc, font.smallFont)
                programDetailsBox.addLine (displayTime, font.smallFont)
                programDetailsBox.addToLayer (layer)
            endif
            
        else
        '
        ' Grid display format
        '    
            ' Channel Logo
            logoUrl = getXmlString (channel.ChannelData.ChannelLogo)
            if logoUrl <> ""
                layer.Push ({
                                TargetRect: {X: dimensions.channelLogoImgX, Y: nextGridRowY, W: dimensions.channelLogoH, H: dimensions.channelLogoH},
                                Url: logoUrl
                            })
            endif

            ' Channel Number
            channelNumber = getXmlString (channel.ChannelData.ChannelNumber)
            channelNumberBox = textBoxCreate (dimensions.channelLogoX, nextGridRowY + dimensions.channelLogoH, dimensions.channelLogoW, dimensions.channelNumberH, settings.colorText, "Center")
            channelNumberBox.addLine (channelNumber, font.mediumFont, dimensions.channelLogoW)
            channelNumberBox.addToLayer (layer)

            '
            ' Loop for each program in this channel
            '
            for programIndex = 0 to channel.ProgramList.Program.Count () - 1
            
                ' Get the next program
                program = channel.ProgramList.Program [programIndex]
                
                ' startRel and endRel are the number of seconds relative to the start of the current listings window
                startRel = getXmlInteger (program.StartSecs)
                endRel = getXmlInteger (program.EndSecs)
                
                ' Don't attempt to display programs that start more than 15 minutes before the end of the 3-hour maximum display duration
                if startRel <= duration - (15 * 60)
                
                    ' Don't attempt to display any portion of the program that exceeds the end of the 3-hour maximum display duration
                    if endRel > duration then endRel = duration
                    
                    ' Determine the proportion of the display width to be occupied by this program
                    programDuration = endRel - startRel
                    
                    ' Get width in pixels of current program display box
                    programWidth% = dimensions.programDetailsW * programDuration / duration
                    
                    ' Get X-coordinate of start of current program display box
                    programStart% = dimensions.programDetailsX + dimensions.programDetailsW * startRel / duration
                    
                    programName = getXmlString (program.ProgramName)
                    programDetailsBox = textBoxCreate (programStart%, nextGridRowY + 0, programWidth%, dimensions.gridRowH - 2, settings.colorText)
                    programDetailsBox.addText (programName,  font.smallFont, programWidth%, dimensions.gridRowH, channelBackgroundColor)
                    programDetailsBox.addToLayer (layer)
                endif
            end for
            '
            ' If there are no programs listed for this channel, write in a blank program
            '
            if channel.ProgramList.Program.Count () = 0
                programName = "No Listings"
                programWidth% = dimensions.programDetailsW
                programStart% = dimensions.programDetailsX
                programDetailsBox = textBoxCreate (programStart%, nextGridRowY + 0, programWidth%, dimensions.gridRowH - 2, settings.colorText)
                programDetailsBox.addText (programName,  font.smallFont, programWidth%, dimensions.gridRowH, channelBackgroundColor)
                programDetailsBox.addToLayer (layer)
            endif
        endif

        nextGridRowY = nextGridRowY + dimensions.gridRowH
        
        ' Go to the next channel
        channelIndex = channelIndex + 1
        
        ' No wraparound. Once the last channel is reached, don't display any more channels past it on this screen
        if channelIndex >= xml.Channel.Count ()
            exit for
        endif
        
    end for
    
    '
    ' Write a blank layer under the program grid to cover up any text that overflowed its box
    '
    layer.Push ({TargetRect: {X: 0, Y: nextGridRowY, W: dimensions.displaySizeW, H: dimensions.displaySizeH - nextGridRowY}, Color: settings.colorFooter, CompositionMode: "Source"})
    
    return layer
    
end function

function textBoxCreate (xParam as integer, yParam as integer, wParam as integer, hParam as integer, colorParam as string, hAlignParam = "Left" as string) as object

    textBox = {}
    
    textBox.x = xParam
    textBox.y = yParam
    textBox.w = wParam
    textBox.h = hParam
    textBox.textColor = colorParam
    textBox.hAlign = hAlignParam

    textBox.outputBox = []
    textBox.numLines = 0
    textBox.nextY = textBox.y
    
    ' Add a single line of text
    textBox.addLine = function (textParam as string, fontParam as object, maxWidth = -1 as integer)
        if textParam <> ""
            size = fontParam.metrics.Size (textParam)
            if maxWidth = -1
                width = size.W
            else
                width = maxWidth
            endif
            yOffset = fontParam.yOffset

            m.outputBox.Push ({
                                TargetRect: {X: m.x, Y: m.nextY + yOffset, W: width, H: size.H},
                                Text: textParam,
                                TextAttrs: {Color: m.textColor, Font: fontParam.family, HAlign: m.hAlign, VAlign: "Top"}
                                })
            m.nextY = m.nextY + size.H
            m.numLines = m.numLines + 1
        endif

    end function
    
    ' Fill the box with text, drawing the background to overwrite any text that might overlap from a previous operation
    textBox.addText = function (textParam as string, fontParam as object, boxWidth as integer, boxHeight as integer, channelBackgroundColor as string)
        if textParam <> ""
            size = fontParam.metrics.Size (textParam)
            yOffset = fontParam.yOffset
            ' Background rectangle. Allow it to extend into the rectangle on the LHS so as to allow padding between programs
            m.outputBox.Push ({TargetRect: {X: m.x - 1, Y: m.nextY + yOffset, W: boxWidth + 1, H: boxHeight}, Color: channelBackgroundColor, CompositionMode: "Source"})
            ' Vertical line between programs
            m.outputBox.Push ({TargetRect: {X: m.x, Y: m.nextY + yOffset, W: 1, H: boxHeight}, Color: m.textColor, CompositionMode: "Source"})
            ' Program details
            m.outputBox.Push ({
                                TargetRect: {X: m.x + 2, Y: m.nextY + yOffset, W: boxWidth - 3, H: size.H},
                                Text: textParam,
                                TextAttrs: {Color: m.textColor, Font: fontParam.family, HAlign: m.hAlign, VAlign: "Top"}
                            })
            m.nextY = m.nextY + size.H
            m.numLines = m.numLines + 1
        endif

    end function
    
    textBox.addToLayer = function (layer as object)

        for each item in m.outputBox
            layer.Push (item)
        end for
        
    end function
    
    return textBox

end function

'
' Switch from old display format to new display format or vice-versa
'
function toggleDisplayFormat (settings as object)

    if settings.newDisplayFormat = true
        settings.newDisplayFormat = false
    else
        settings.newDisplayFormat = true
    endif

    settings.font = getFont (settings.deviceInfo.sd, settings.newDisplayFormat, settings.numGridRows)
    settings.dimensions = getDimensions (settings.newDisplayFormat, settings.numGridRows, settings.deviceInfo, settings.font)
    
end function

function timeToHMMA (timeSecs as integer) as string

    dt = CreateObject ("roDateTime")
    dt.FromSeconds (timeSecs)
    dt.ToLocalTime ()

    h = dt.GetHours ()
    mm = dt.GetMinutes () : mmStr = Right ("0" + mm.ToStr (), 2)
    if h < 12
        ap = "am"
    else
        if h > 12 then h = h - 12
        ap = "pm"
    endif
    
    return h.ToStr () + ":" + mmStr + " " + ap

end function

function timeToHMMA2 (timeSecs as integer) as string

    dt = CreateObject ("roDateTime")
    dt.FromSeconds (timeSecs)
    dt.ToLocalTime ()

    h = dt.GetHours ()
    mm = dt.GetMinutes () : mmStr = Right ("0" + mm.ToStr (), 2)

    if h = 0 and mm = 0
        timeStr = "Midnight"
    else if h = 12 and mm = 0
        timeStr = "Noon"
    else
        if h >= 12
            ap = "pm"
            if h > 12 then h = h - 12
        else
            ap = "am"
        endif
        timeStr = h.ToStr () + ":" + mmStr + " " + ap
    endif
    
    return timeStr

end function

function timeToDay (timeSecs as integer) as string

    dt = CreateObject ("roDateTime")
    dt.FromSeconds (timeSecs)
    dt.ToLocalTime ()

    return Left (dt.GetWeekday (), 3)

end function

'
' Get a string from an XML field
'
function getXmlString (field as object, defaultField = "" as string) as string

    for each item in field
        return field.GetText ()
    end for

    return defaultField

end function

'
' Get an integer from an XML field
'
function getXmlInteger (field as object, defaultField = 0 as integer) as integer

    for each item in field
        return field.GetText ().ToInt ()
    end for

    return defaultField

end function

'
' Get an ISO8601 UTC time from an XML field and convert to time in seconds
'
function getXmlUTCInSecs (field as object, defaultField = 0 as integer) as integer

    utcString = ""
    for each item in field
        utcString = field.GetText ()
        exit for
    end for
    
    dt = CreateObject ("roDateTime")
    dt.FromISO8601String (utcString)
    secs = dt.AsSeconds ()
    
    if secs > 1300000000 and secs < 1500000000
        timeSecs = secs
    else
        timeSecs = defaultField
    endif
    
    return timeSecs

end function

'*************************
' Display a message dialog
'*************************
sub displayMessageDialog (messageList as object)

    port = CreateObject ("roMessagePort")

    messageDialog = CreateObject ("roMessageDialog")
    messageDialog.SetMessagePort (port)
    messageDialog.EnableOverlay (true)    ' Do not dim background screen
    messageDialog.SetTitle (messageList [0])
    for i = 1 to messageList.Count () - 1
        messageDialog.SetText (messageList [i])
    end for
    messageDialog.AddButton (1, "OK")
    messageDialog.Show ()

    while true
        msg = Wait (0, port)
        if type (msg) = "roMessageDialogEvent"
            if msg.IsScreenClosed ()
                exit while
            else if msg.IsButtonPressed ()
                if msg.GetIndex () = 1
                    messageDialog.Close ()
                endif
            endif
        endif
    end while

end sub

'*******************************
' Display a one-line busy dialog
'*******************************
function displayLoadingDialog () as object

    port = CreateObject ("roMessagePort")

    oneLineDialog = CreateObject ("roOneLineDialog")
    oneLineDialog.SetMessagePort (port)
    oneLineDialog.ShowBusyAnimation ()
    oneLineDialog.SetTitle ("Loading ...")
    oneLineDialog.Show ()
    
    return oneLineDialog
    
end function

'*****************************
' Close a one-line busy dialog
'*****************************
function closeLoadingDialog (dialog as object) as object

    dialog.Close ()
    while true
        msg = Wait (0, dialog.GetMessagePort ())
        if msg.IsScreenClosed ()
            exit while
        endif
    end while

end function


Plz Help
  • Knowing how to "parse this XML" isn't going to help you. You need to re-write the code that makes use of the parsed XML so it uses the data structure you're providing, versus the data structure expected by the code you're copying; or write a converter that converts the XML data from one form to the other. I doubt you'd get that kind of help here.
  • btpoole's avatar
    btpoole
    Channel Surfer
    jitendragaurgkv here's a little info that might help. To keep the load off the roku I parsed the schedules direct on the server using php creating a json array. The parse organizes the data my app needs when it loads. So basically the Roku is not doing a lot of work, just loading the array.