+-- | Parse an optional 'Int' from a direct descendent of the
+-- (top-level) \<message\> element in an XmlTree. This is just like
+-- 'parse_message_int', except we expect the element/value to be
+-- missing sometimes.
+--
+-- To handle the fact that the element/value is optional, we pattern
+-- match on the 'ParseError' that comes back in case of failure. If
+-- we didn't find anything, we turn that into a \"successful
+-- nothing\". But if we find a value 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_message_int_optional :: String
+ -> XmlTree
+ -> Either ParseError (Maybe Int)
+parse_message_int_optional child xmltree =
+ case (parse_message_int child xmltree) of
+ Left (ParseNotFound _) -> Right Nothing
+ Left pm@(ParseMismatch {}) -> Left pm
+ Right whatever -> Right (Just whatever)
+
+
+
-- | 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
-- | 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'
+-- documents. Unlike the \<XML_File_ID\> elements, the \<game_id\>
+-- can be missing from GameInfo documents, so for our implementation
+-- we use 'parse_message_int_optional' instead.
--
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)
+parse_game_id = parse_message_int_optional "game_id"
-- | 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.
+-- \<message\> of a document. Identical to 'parse_game_id' except
+-- for the element name.
--
-parse_schedule_id :: XmlTree -> Either ParseError Int
-parse_schedule_id = parse_message_int "schedule_id"
+parse_schedule_id :: XmlTree -> Either ParseError (Maybe Int)
+parse_schedule_id = parse_message_int_optional "schedule_id"
"TSN.Parse tests"
[ test_parse_game_id,
test_parse_missing_game_id,
+ test_parse_missing_schedule_id,
test_parse_schedule_id,
test_parse_xmlfid ]
where
let actual = parse_game_id xmltree
let expected = Right Nothing
actual @?= expected
+
+
+-- | The schedule_id element can be missing, so we test that too.
+--
+test_parse_missing_schedule_id :: TestTree
+test_parse_missing_schedule_id =
+ testCase "missing schedule_id is not an error" $ do
+ let path = "test/xml/gameinfo/recapxml-no-game-schedule-ids.xml"
+ xmltree <- unsafe_read_document path
+ let actual = parse_schedule_id xmltree
+ let expected = Right Nothing
+ actual @?= expected