Skip to content

Instantly share code, notes, and snippets.

@0xTenable
Created August 25, 2016 22:18
Show Gist options
  • Save 0xTenable/6eca558cf40bccf9628a5d9057c8cadf to your computer and use it in GitHub Desktop.
Save 0xTenable/6eca558cf40bccf9628a5d9057c8cadf to your computer and use it in GitHub Desktop.
Removes all error functions
'********************************************************************
'
' NewVideoPlayer -- Example Multi-Level Roku Channel
'
' Copyright (c) 2015, belltown. All rights reserved. See LICENSE.txt
'
'*********************************************************************
'
' Read and parse an Xml document
' There are two types of Xml document supported: <categories> and <feed>
'
Function parseXmlDocument (xmlPath As String) As Object
contentItem = {}
' Convert the Xml text into an roXMLElement component object
xml = readXml (xmlPath)
' Return an empty content item if the Xml text parsing fails, otherwise parse the Xml document
If Type (xml) = "roXMLElement"
' Get the Xml document's root element name (case-insensitive)
xmlName = LCase (xml.GetName ())
If xmlName = "categories" Or xmlName = "category"
' <categories> and <category> documents are handled identically
contentItem = parseCategoryXml (xmlPath, xml)
Else
' Assume we have a <feed> document
contentItem = parseFeedXml (xml)
End If
End If
Return contentItem
End Function
'
' Read an Xml document from a path (local file or remote url) and return an roXMLElement object
'
Function readXml (xmlPath As String) As Object
' Return an roXMLElement by parsing an Xml text file
xml = CreateObject ("roXMLElement")
' Read the Xml document from either a local file or a remote url
xmlString = _getPathToString (xmlPath)
'_debug ("xmlString: " + xmlString) ' un-comment to dump Xml file contents
If xmlString <> ""
If Not xml.Parse (xmlString)
'uiFatalError ("readXml", LINE_NUM, "Unable to parse Xml document: " + xmlPath)
xml = Invalid
return xml
End If
Else
'uiFatalError ("readXml", LINE_NUM, "Unable to read Xml document: " + xmlPath)
return xml
End If
Return xml
End Function
'
' Parse a <categories> Xml document or <category> element, returning a content item that will contain a list of child content items.
' No separate data structures are used to represent the hierarchical content tree.
' All data is contained in Content Meta-Data objects.
' For a given node in the tree, the Content Meta-Data fields are filled in with whatever is needed to render a representation
' of that node on a screen (Title, Description, SDPosterUrl, etc.)
' Additional custom Content Meta-Data fields (prefixed with "xx") are used to contain the node's child nodes (xxChildContentList),
' and to indicate what type of nodes those children represent (xxFeedPath).
' <feed> elements may either be located within a category's Xml document, or read from an external Xml document (xxFeedPath contains its location).
' External Xml documents are not read until they need to be displayed. After that, they remain in memory (xxIsCached set to True).
'
Function parseCategoryXml (xmlPath As String, categoryXml As Object) As Object
' Return a single content item for the <categories> or <category> element that will include a list of any child items in xxChildContentList
contentItem = {}
' A category may have a "feed" attribute, in which case it should not have any subordinate <category> or <categoryLeaf> elements
feedPath = _getXmlAttrString (categoryXml, "feed") ' Our child content list corresponds to a <feed> element
' Get the immediate child nodes, ignoring anything other than <category> or <categoryLeaf> nodes
categoryChildList = categoryXml.GetNamedElementsCI ("category")
leafChildList = categoryXml.GetNamedElementsCI ("categoryLeaf")
feedChildList = categoryXml.GetNamedElementsCI ("feed")
' Recursively parse any child <category> elements or <categoryLeaf> elements
' There should be ONLY a "feed" attribute, or ONLY a single <feed> element, or ONLY <category> elements, or ONLY <categoryLeaf> elements
' A single <feed> element - feed located in the category's Xml file
If feedChildList.Count () = 1 And feedPath = "" And categoryChildList.Count () = 0 And leafChildList.Count () = 0
' Get <category> attributes that will be applied to the in-line feed
title = _getXmlAttrString (categoryXml, "title")
description = _getXmlAttrString (categoryXml, "description")
sdImg = _getXmlAttrString (categoryXml, "sd_img")
hdImg = _getXmlAttrString (categoryXml, "hd_img")
' If one image field is missing, use the other
If sdImg <> "" And hdImg = "" Then hdImg = sdImg
If hdImg <> "" And sdImg = "" Then sdImg = hdImg
' Set up the Content Meta-Data
contentItem.Title = title
contentItem.Description = description
contentItem.ShortDescriptionLine1 = title
contentItem.ShortDescriptionLine2 = description
contentItem.SDPosterUrl = sdImg
contentItem.HDPosterUrl = hdImg
contentItem.xxChildContentList = parseFeedXml (feedChildList [0]) ' The <feed> is located in the same document as the <category>
contentItem.xxIsCached = True
contentItem.xxFeedType = "feed" ' Our child content list corresponds to a single <feed> element
' A "feed" attribute - feed located in a separate Xml file
Else If feedChildList.Count () = 0 And feedPath <> "" And categoryChildList.Count () = 0 And leafChildList.Count () = 0
' Get <category> attributes that will be applied to the referenced feed
title = _getXmlAttrString (categoryXml, "title")
description = _getXmlAttrString (categoryXml, "description")
sdImg = _getXmlAttrString (categoryXml, "sd_img")
hdImg = _getXmlAttrString (categoryXml, "hd_img")
' If one image field is missing, use the other
If sdImg <> "" And hdImg = "" Then hdImg = sdImg
If hdImg <> "" And sdImg = "" Then sdImg = hdImg
' Set up this node's Content Meta-Data
contentItem.Title = title
contentItem.Description = description
contentItem.ShortDescriptionLine1 = title
contentItem.ShortDescriptionLine2 = description
contentItem.SDPosterUrl = sdImg
contentItem.HDPosterUrl = hdImg
' Don't read the feed document until it is required to be displayed
contentItem.xxIsCached = False
contentItem.xxFeedPath = feedPath
contentItem.xxFeedType = "feed" ' Our child content list corresponds to a single <feed> element
' Only <categories> or <category> elements
Else If feedChildList.Count () = 0 And feedPath = "" And categoryChildList.Count () > 0 And leafChildList.Count () = 0
childContentList = []
' Get <category> attributes
title = _getXmlAttrString (categoryXml, "title")
description = _getXmlAttrString (categoryXml, "description")
sdImg = _getXmlAttrString (categoryXml, "sd_img")
hdImg = _getXmlAttrString (categoryXml, "hd_img")
' If one image field is missing, use the other
If sdImg <> "" And hdImg = "" Then hdImg = sdImg
If hdImg <> "" And sdImg = "" Then sdImg = hdImg
' Recursively parse child <category> elements
For Each child In categoryChildList
childContentList.Push (parseCategoryXml (xmlPath, child))
End For
' Set up the Content Meta-Data
contentItem.Title = title
contentItem.Description = description
contentItem.ShortDescriptionLine1 = title
contentItem.ShortDescriptionLine2 = description
contentItem.SDPosterUrl = sdImg
contentItem.HDPosterUrl = hdImg
' Use a fixed-size array for the child content item list, and store in a custom content meta-data field
contentItem.xxChildContentList = CreateObject ("roArray", childContentList.Count (), False)
For Each child In childContentList
contentItem.xxChildContentList.Push (child)
End For
contentItem.xxIsCached = True
contentItem.xxFeedType = "category" ' The child content items are a list of <category> elements
' Only <categoryLeaf> elements
Else If feedChildList.Count () = 0 And feedPath = "" And categoryChildList.Count () = 0 And leafChildList.Count () > 0
' Get <category> attributes - Used for content items for the roPosterScreen item representing this <category> element
title = _getXmlAttrString (categoryXml, "title") ' Title (breadcrumb) and ShortDescriptionLine1
description = _getXmlAttrString (categoryXml, "description") ' ShortDescriptionLine2
sdImg = _getXmlAttrString (categoryXml, "sd_img") ' SDPosterUrl
hdImg = _getXmlAttrString (categoryXml, "hd_img") ' HDPosterUrl
' If one image field is missing, use the other
If sdImg <> "" And hdImg = "" Then hdImg = sdImg
If hdImg <> "" And sdImg = "" Then sdImg = hdImg
' Set up the Content Meta-Data
contentItem.Title = title ' Used for breadcrumb
contentItem.Description = description ' Only used if SetListStyle ("flat-episodic..") used [Need to test]
contentItem.ShortDescriptionLine1 = title ' First line of poster screen description
contentItem.ShortDescriptionLine2 = description ' Second line of poster screen description
contentItem.SDPosterUrl = sdImg ' Poster screen image (SD)
contentItem.HDPosterUrl = hdImg ' Poster screen image (HD)
' Parse child <categoryLeaf> elements
leafList = []
For Each child In leafChildList
' Get <categoryLeaf> attributes
leafTitle = _getXmlAttrString (child, "title") ' Used for roPosterScreen list name
leafDescription = _getXmlAttrString (child, "description") ' Not currently used in the roPosterScreen with filter banner implementation
leafFeedPath = _getXmlAttrString (child, "feed") ' Location of the <feed> element
If leafFeedPath = ""
uiFatalError ("parseCategoryXml", LINE_NUM, "A <categoryLeaf> has no feed attribute in Xml document: " + xmlPath)
End If
' Don't read the leaf document until it is required to be displayed
leafList.Push ({leafName: leafTitle, feedPath: leafFeedPath})
End For
' Use fixed-length arrays of custom meta-data items for storing filter banner names and content item lists
contentItem.xxChildNamesList = CreateObject ("roArray", leafList.Count (), False)
contentItem.xxChildContentList = CreateObject ("roArray", leafList.Count (), False)
' Store names and content item lists in custom meta-data fields
For Each leaf In leafList
contentItem.xxChildNamesList.Push (leaf.leafName)
' Don't actually read in the leaf feed until the item is selected for display by the user
contentItem.xxChildContentList.Push ({xxIsCached: False, xxFeedPath: leaf.feedPath})
End For
contentItem.xxIsCached = True ' The <category> has been read into memory, even though its children have not
contentItem.xxFeedType = "leaf" ' The child content items are a list of <categoryLeaf> elements
' More than one <feed> element specified - invalid
Else If feedChildList.Count () > 0
contentItem.xxChildContentList = []
contentItem.xxFeedType = "error"
uiFatalError ("parseCategoryXml", LINE_NUM, "Cannot have more than one <feed> element for a <category> or <categoryleaf> in Xml document: " + xmlPath)
' <category> "feed" attribute specified with subordinate <category> or <categoryLeaf> elements - invalid
Else If feedPath <> ""
contentItem.xxChildContentList = []
contentItem.xxFeedType = "error"
uiFatalError ("parseCategoryXml", LINE_NUM, "Cannot have a <category> feed attribute with subordinate <category> or <categoryLeaf> elements in Xml document: " + xmlPath)
' Both <category> and <categoryLeaf> elements - invalid
Else If categoryChildList.Count () > 0 And leafChildList.Count () > 0
contentItem.xxChildContentList = []
contentItem.xxFeedType = "error"
uiFatalError ("parseCategoryXml", LINE_NUM, "Cannot have both <category> and <categoryLeaf> elements at the same level in Xml document: " + xmlPath)
' Neither <category> nor <categoryLeaf> elements - invalid
Else
contentItem.xxChildContentList = []
contentItem.xxFeedType = "error"
uiFatalError ("parseCategoryXml", LINE_NUM, "A <categories> or <category> is empty in Xml document: " + xmlPath)
End If
Return contentItem
End Function
'
' Parse a feed Xml document.
' The same function is called to parse a <feed> regardless of whether it is located
' in the same file as its category, or in a separate file.
' It's even possible for there to be no <categories> or <category> to display a <feed>;
' simply pass the feed file's path name into parseXmlDocument in Main ().
' Currently, only Roku-type feeds (as in the videoplayer SDK example) and RSS feeds
' are supported. Atom feeds are not currently supported and Atom meta-data elements are ignored.
' RSS feeds may have standard RSS 2.0 tags, MRSS extensions and iTunes extensions.
' The extensions that seem appropriate for a Roku implementation have been implemented.
'
Function parseFeedXml (xml As Object) As Object
contentItem = {}
'
' Determine the feed type:
' - Roku : Root element is <feed> with no "xmlns" attribute specified (supported)
' - Atom : Root element is <feed> with "xmlns:atom" attribute specified (not supported)
' - RSS/MRSS/iTunes : Root element is <rss> (supported)
'
rootElementName = LCase (xml.GetName ())
If rootElementName = "rss"
' RSS/MRSS/iTunes feed [may also have atom: tags, which we don't currently support]
contentItem = getRssContent (xml)
Else If rootElementName = "feed"
attrAA = xml.GetAttributes ()
hasXmlns = False
For Each key In attrAA
xmlns = "xmlns"
If LCase (Left (key, Len (xmlns))) = xmlns
hasXmlns = True
End If
End For
If Not hasXmlns
' Roku feed
contentItem = getRokuContent (xml)
Else If xml.HasAttribute ("xmlns:atom")
' Atom Feed
contentItem = getAtomContent (xml)
Else
' Unsupported feed xmlns
'uiSoftError ("parseFeedXml", LINE_NUM, "Unsupported Feed Type: Feed: " + rootElementName + ". xmlns: " + xmlNs)
End If
Else
' Unsupported feed type
'uiSoftError ("parseFeedXml", LINE_NUM, "Unsupported Feed Type: " + rootElementName)
End If
Return contentItem
End Function
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment