+ parse_results = map read_either_int elements
+
+
+
+-- | Extract the \"XML_File_ID\" element from a document. If we fail
+-- to parse an XML_File_ID, we return an appropriate 'ParseError'
+-- wrapped in a 'Left' constructor. The reason should be one of two
+-- things:
+--
+-- 1. No XML_File_ID elements were found.
+--
+-- 2. An XML_File_ID element was found, but it could not be read
+-- into an Int.
+--
+-- In general we expect some non-integer XML_File_IDs, because they
+-- appear on the feed. But the htsn daemon refuses to save them at
+-- the moment, so if we ever see an XML_File_ID that we can't parse,
+-- it's truly an error.
+--
+parse_xmlfid :: XmlTree -> Either ParseError Int
+parse_xmlfid = parse_message_int "XML_File_ID"
+
+
+
+-- | Extract the \<game_id\> element from within the top-level
+-- \<message\> of a document. These appear in the "TSN.XML.GameInfo"
+-- documents. Unlike the \<schedule_id\> and \<XML_File_ID\>
+-- elements, the \<game_id\> can be missing from GameInfo
+-- documents. So even the 'Right' value of the 'Either' can be
+-- \"missing\". There are two reasons that the parse might fail.
+--
+-- 1. No such elements were found. This is expected sometimes, and
+-- should be returned as a 'Right' 'Nothing'.
+--
+-- 2. An element was found, but it could not be read into an
+-- 'Int'. This is NOT expected, and will be returned as a
+-- 'ParseError', wrapped in a 'Left'.
+--
+-- Most of implementation for this ('parse_message_int') is shared,
+-- but to handle the fact that game_id is optional, we pattern match
+-- on the 'ParseError' that comes back in case of failure. If we
+-- didn't find any game_id elements, we turn that into a
+-- \"successful nothing\". But if we find a game_id and it can't be
+-- parsed, we let the error propagate, because that shouldn't
+-- happen. Of course, if the parse worked, that's nice too: we wrap
+-- the parsed value in a 'Just' and return that wrapped in a 'Right'
+--
+parse_game_id :: XmlTree -> Either ParseError (Maybe Int)
+parse_game_id xml =
+ case (parse_message_int "game_id" xml) of
+ Left (ParseNotFound _) -> Right Nothing
+ Left pm@(ParseMismatch {}) -> Left pm
+ Right whatever -> Right (Just whatever)
+
+
+
+-- | Extract the \<schedule_id\> element from within the top-level
+-- \<message\> of a document. These appear in the
+-- "TSN.XML.GameInfo" documents. If we fail to parse a schedule_id,
+-- we return the reason wrapped in an appropriate 'ParseError'. The reason
+-- should be one of two things:
+--
+-- 1. No such elements were found.
+--
+-- 2. An element was found, but it could not be read
+-- into an Int.
+--
+-- Both of these are truly errors in the case of schedule_id. The
+-- implementation for this ('parse_message_int') is shared among a
+-- few functions.
+--
+parse_schedule_id :: XmlTree -> Either ParseError Int
+parse_schedule_id = parse_message_int "schedule_id"