+readXMLFile file = do
+ content <- readFile file
+ let Just root = parseXMLDoc content
+ return $
+ foldl (\acc elem ->
+ case elementXMLToMovie elem of
+ Nothing -> acc
+ Just movie -> movie : acc)
+ []
+ (elChildren root)
+
+elementXMLToMovie :: Element -> Maybe Movie
+elementXMLToMovie elem =
+ Just (emptyMovie, C.fromElement elem) >>?
+ (\(m, c) ->
+ case C.current c of
+ Elem elem ->
+ case findAttr (simpleQName "id") elem of
+ Nothing -> Nothing
+ Just id -> Just (m { movieId = read id :: Int }, c)
+ otherwise -> Nothing) >>?
+ (\(m, c) ->
+ case firstChildElement c of
+ Just (elem, c') -> Just (m { movieTitle = strContent elem }, c')
+ otherwise -> Nothing) >>?
+ (\(m, c) ->
+ case nextSibilingElement c of
+ Just (elem, c') -> Just m { movieYear = intElement elem }
+ otherwise -> Nothing)
+
+-- A bit naive
+(>>?) :: Maybe alpha -> (alpha -> Maybe beta) -> Maybe beta
+Nothing >>? _ = Nothing
+Just v >>? f = f v
+
+-- Some XML helper functions
+simpleQName name = QName name Nothing Nothing
+firstChildElement :: C.Cursor -> Maybe (Element, C.Cursor)
+firstChildElement c =
+ case C.firstChild c of
+ Just c' ->
+ case C.current c' of
+ Elem elem -> Just (elem, c')
+ otherwise -> nextSibilingElement c'
+ otherwise -> Nothing
+
+nextSibilingElement :: C.Cursor -> Maybe (Element, C.Cursor)
+nextSibilingElement c =
+ case C.right c of
+ Just c' ->
+ case C.current c' of
+ Elem elem -> Just (elem, c')
+ otherwise -> nextSibilingElement c'
+ Nothing -> Nothing
+
+-- Try to cast an element content to an Int.
+intElement :: Element -> Maybe Int
+intElement elem =
+ if content == []
+ then Nothing
+ else Just (read content :: Int)
+ where content = strContent elem