    --------------------------------------------------------------------
    -- |
    -- Module    : Text.RSS.Import
    -- Copyright : (c) Galois, Inc. 2008,
    --             (c) Sigbjorn Finne 2009-
    -- License   : BSD3
    --
    -- Maintainer: Sigbjorn Finne <sof@forkIO.com>
    -- Stability : provisional
    --
    -- Converting from XML to RSS
    --
    --------------------------------------------------------------------
    module Text.RSS.Import
      ( pNodes
      , pQNodes
      , pNode
      , pQNode
      , pLeaf
      , pQLeaf
      , pAttr
      , pMany
      , children
      , qualName
      , dcName
      , elementToRSS
      , elementToChannel
      , elementToImage
      , elementToCategory
      , elementToCloud
      , elementToItem
      , elementToSource
      , elementToEnclosure
      , elementToGuid
      , elementToTextInput
      , elementToSkipHours
      , elementToSkipDays
      , readInt
      , readBool
      ) where

    import Prelude.Compat

    import Data.XML.Compat
    import Data.XML.Types as XML

    import Text.RSS.Syntax
    import Text.RSS1.Utils (dcNS, dcPrefix)

    import Control.Monad.Compat (guard, mplus)
    import Data.Char (isSpace)
    import Data.Maybe (fromMaybe, listToMaybe, mapMaybe)
    import Data.Text (Text, dropWhile)
    import Data.Text.Util

    pNodes :: Text -> [XML.Element] -> [XML.Element]
    pNodes :: Text -> [Element] -> [Element]
    pNodes Text
    x = (Element -> Bool) -> [Element] -> [Element]
    forall a. (a -> Bool) -> [a] -> [a]
    filter ((Text -> Name
    qualName Text
    x Name -> Name -> Bool
    forall a. Eq a => a -> a -> Bool
    ==) (Name -> Bool) -> (Element -> Name) -> Element -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Element -> Name
    elementName)

    pQNodes :: Name -> [XML.Element] -> [XML.Element]
    pQNodes :: Name -> [Element] -> [Element]
    pQNodes Name
    x = (Element -> Bool) -> [Element] -> [Element]
    forall a. (a -> Bool) -> [a] -> [a]
    filter ((Name
    x Name -> Name -> Bool
    forall a. Eq a => a -> a -> Bool
    ==) (Name -> Bool) -> (Element -> Name) -> Element -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Element -> Name
    elementName)

    pNode :: Text -> [XML.Element] -> Maybe XML.Element
    pNode :: Text -> [Element] -> Maybe Element
    pNode Text
    x [Element]
    es = [Element] -> Maybe Element
    forall a. [a] -> Maybe a
    listToMaybe (Text -> [Element] -> [Element]
    pNodes Text
    x [Element]
    es)

    pQNode :: Name -> [XML.Element] -> Maybe XML.Element
    pQNode :: Name -> [Element] -> Maybe Element
    pQNode Name
    x [Element]
    es = [Element] -> Maybe Element
    forall a. [a] -> Maybe a
    listToMaybe (Name -> [Element] -> [Element]
    pQNodes Name
    x [Element]
    es)

    pLeaf :: Text -> [XML.Element] -> Maybe Text
    pLeaf :: Text -> [Element] -> Maybe Text
    pLeaf Text
    x [Element]
    es = Element -> Text
    strContent (Element -> Text) -> Maybe Element -> Maybe Text
    forall a b. (a -> b) -> Maybe a -> Maybe b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    `fmap` Text -> [Element] -> Maybe Element
    pNode Text
    x [Element]
    es

    pQLeaf :: Name -> [XML.Element] -> Maybe Text
    pQLeaf :: Name -> [Element] -> Maybe Text
    pQLeaf Name
    x [Element]
    es = Element -> Text
    strContent (Element -> Text) -> Maybe Element -> Maybe Text
    forall a b. (a -> b) -> Maybe a -> Maybe b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    `fmap` Name -> [Element] -> Maybe Element
    pQNode Name
    x [Element]
    es

    pAttr :: Text -> XML.Element -> Maybe Text
    pAttr :: Text -> Element -> Maybe Text
    pAttr Text
    x = Name -> Element -> Maybe Text
    attributeText (Text -> Name
    qualName Text
    x)

    pMany :: Text -> (XML.Element -> Maybe a) -> [XML.Element] -> [a]
    pMany :: forall a. Text -> (Element -> Maybe a) -> [Element] -> [a]
    pMany Text
    p Element -> Maybe a
    f [Element]
    es = (Element -> Maybe a) -> [Element] -> [a]
    forall a b. (a -> Maybe b) -> [a] -> [b]
    mapMaybe Element -> Maybe a
    f (Text -> [Element] -> [Element]
    pNodes Text
    p [Element]
    es)

    children :: XML.Element -> [XML.Element]
    children :: Element -> [Element]
    children = Element -> [Element]
    elementChildren

    qualName :: Text -> Name
    qualName :: Text -> Name
    qualName Text
    x = Text -> Maybe Text -> Maybe Text -> Name
    Name Text
    x Maybe Text
    forall a. Maybe a
    Nothing Maybe Text
    forall a. Maybe a
    Nothing

    dcName :: Text -> Name
    dcName :: Text -> Name
    dcName Text
    x = Text -> Maybe Text -> Maybe Text -> Name
    Name Text
    x (Text -> Maybe Text
    forall a. a -> Maybe a
    Just Text
    dcNS) (Text -> Maybe Text
    forall a. a -> Maybe a
    Just Text
    dcPrefix)

    elementToRSS :: XML.Element -> Maybe RSS
    elementToRSS :: Element -> Maybe RSS
    elementToRSS Element
    e = do
      Bool -> Maybe ()
    forall (f :: * -> *). Alternative f => Bool -> f ()
    guard (Element -> Name
    elementName Element
    e Name -> Name -> Bool
    forall a. Eq a => a -> a -> Bool
    == Text -> Name
    qualName Text
    "rss")
      let es :: [Element]
    es = Element -> [Element]
    children Element
    e
      let as :: [(Name, [Content])]
    as = Element -> [(Name, [Content])]
    elementAttributes Element
    e
      v <- Text -> Element -> Maybe Text
    pAttr Text
    "version" Element
    e
      ch <- pNode "channel" es >>= elementToChannel
      return
        RSS
          { rssVersion = v
          , rssAttrs = filter ((`notElem` known_attrs) . fst) as
          , rssChannel = ch
          , rssOther = filter (\Element
    e1 -> Element -> Name
    elementName Element
    e1 Name -> Name -> Bool
    forall a. Eq a => a -> a -> Bool
    /= Text -> Name
    qualName Text
    "channel") es
          }
      where
        known_attrs :: [Name]
    known_attrs = [Name
    "version"]

    elementToChannel :: XML.Element -> Maybe RSSChannel
    elementToChannel :: Element -> Maybe RSSChannel
    elementToChannel Element
    e = do
      Bool -> Maybe ()
    forall (f :: * -> *). Alternative f => Bool -> f ()
    guard (Element -> Name
    elementName Element
    e Name -> Name -> Bool
    forall a. Eq a => a -> a -> Bool
    == Text -> Name
    qualName Text
    "channel")
      let es :: [Element]
    es = Element -> [Element]
    children Element
    e
      title <- Text -> [Element] -> Maybe Text
    pLeaf Text
    "title" [Element]
    es
      link <- pLeaf "link" es
      return
        RSSChannel
          { rssTitle = title
          , rssLink = link
            -- being liberal, <description/> is a required channel element.
          , rssDescription = fromMaybe title (pLeaf "description" es)
          , rssItems = pMany "item" elementToItem es
          , rssLanguage = pLeaf "language" es `mplus` pQLeaf (dcName "lang") es
          , rssCopyright = pLeaf "copyright" es
          , rssEditor = pLeaf "managingEditor" es `mplus` pQLeaf (dcName "creator") es
          , rssWebMaster = pLeaf "webMaster" es
          , rssPubDate = pLeaf "pubDate" es `mplus` pQLeaf (dcName "date") es
          , rssLastUpdate = pLeaf "lastBuildDate" es `mplus` pQLeaf (dcName "date") es
          , rssCategories = pMany "category" elementToCategory es
          , rssGenerator = pLeaf "generator" es `mplus` pQLeaf (dcName "source") es
          , rssDocs = pLeaf "docs" es
          , rssCloud = pNode "cloud" es >>= elementToCloud
          , rssTTL = pLeaf "ttl" es >>= readInt
          , rssImage = pNode "image" es >>= elementToImage
          , rssRating = pLeaf "rating" es
          , rssTextInput = pNode "textInput" es >>= elementToTextInput
          , rssSkipHours = pNode "skipHours" es >>= elementToSkipHours
          , rssSkipDays = pNode "skipDays" es >>= elementToSkipDays
          , rssChannelOther = filter ((`notElem` known_channel_elts) . elementName) es
          }
      where
        known_channel_elts :: [Name]
    known_channel_elts =
          (Text -> Name) -> [Text] -> [Name]
    forall a b. (a -> b) -> [a] -> [b]
    map
            Text -> Name
    qualName
            [ Text
    "title"
            , Text
    "link"
            , Text
    "description"
            , Text
    "item"
            , Text
    "language"
            , Text
    "copyright"
            , Text
    "managingEditor"
            , Text
    "webMaster"
            , Text
    "pubDate"
            , Text
    "lastBuildDate"
            , Text
    "category"
            , Text
    "generator"
            , Text
    "docs"
            , Text
    "cloud"
            , Text
    "ttl"
            , Text
    "image"
            , Text
    "rating"
            , Text
    "textInput"
            , Text
    "skipHours"
            , Text
    "skipDays"
            ]

    elementToImage :: XML.Element -> Maybe RSSImage
    elementToImage :: Element -> Maybe RSSImage
    elementToImage Element
    e = do
      Bool -> Maybe ()
    forall (f :: * -> *). Alternative f => Bool -> f ()
    guard (Element -> Name
    elementName Element
    e Name -> Name -> Bool
    forall a. Eq a => a -> a -> Bool
    == Text -> Name
    qualName Text
    "image")
      let es :: [Element]
    es = Element -> [Element]
    children Element
    e
      url <- Text -> [Element] -> Maybe Text
    pLeaf Text
    "url" [Element]
    es
      title <- pLeaf "title" es
      link <- pLeaf "link" es
      return
        RSSImage
          { rssImageURL = url
          , rssImageTitle = title
          , rssImageLink = link
          , rssImageWidth = pLeaf "width" es >>= readInt
          , rssImageHeight = pLeaf "height" es >>= readInt
          , rssImageDesc = pLeaf "description" es
          , rssImageOther = filter ((`notElem` known_image_elts) . elementName) es
          }
      where
        known_image_elts :: [Name]
    known_image_elts = (Text -> Name) -> [Text] -> [Name]
    forall a b. (a -> b) -> [a] -> [b]
    map Text -> Name
    qualName [Text
    "url", Text
    "title", Text
    "link", Text
    "width", Text
    "height", Text
    "description"]

    elementToCategory :: XML.Element -> Maybe RSSCategory
    elementToCategory :: Element -> Maybe RSSCategory
    elementToCategory Element
    e = do
      Bool -> Maybe ()
    forall (f :: * -> *). Alternative f => Bool -> f ()
    guard (Element -> Name
    elementName Element
    e Name -> Name -> Bool
    forall a. Eq a => a -> a -> Bool
    == Text -> Name
    qualName Text
    "category")
      let as :: [(Name, [Content])]
    as = Element -> [(Name, [Content])]
    elementAttributes Element
    e
      RSSCategory -> Maybe RSSCategory
    forall a. a -> Maybe a
    forall (m :: * -> *) a. Monad m => a -> m a
    return
        RSSCategory
          { rssCategoryDomain :: Maybe Text
    rssCategoryDomain = Text -> Element -> Maybe Text
    pAttr Text
    "domain" Element
    e
          , rssCategoryAttrs :: [(Name, [Content])]
    rssCategoryAttrs = ((Name, [Content]) -> Bool)
    -> [(Name, [Content])] -> [(Name, [Content])]
    forall a. (a -> Bool) -> [a] -> [a]
    filter ((Text -> [Text] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    `notElem` [Text]
    known_attrs) (Text -> Bool)
    -> ((Name, [Content]) -> Text) -> (Name, [Content]) -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Name -> Text
    nameLocalName (Name -> Text)
    -> ((Name, [Content]) -> Name) -> (Name, [Content]) -> Text
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Name, [Content]) -> Name
    attrKey) [(Name, [Content])]
    as
          , rssCategoryValue :: Text
    rssCategoryValue = Element -> Text
    strContent Element
    e
          }
      where
        known_attrs :: [Text]
    known_attrs = [Text
    "domain"]

    elementToCloud :: XML.Element -> Maybe RSSCloud
    elementToCloud :: Element -> Maybe RSSCloud
    elementToCloud Element
    e = do
      Bool -> Maybe ()
    forall (f :: * -> *). Alternative f => Bool -> f ()
    guard (Element -> Name
    elementName Element
    e Name -> Name -> Bool
    forall a. Eq a => a -> a -> Bool
    == Text -> Name
    qualName Text
    "cloud")
      let as :: [(Name, [Content])]
    as = Element -> [(Name, [Content])]
    elementAttributes Element
    e
      RSSCloud -> Maybe RSSCloud
    forall a. a -> Maybe a
    forall (m :: * -> *) a. Monad m => a -> m a
    return
        RSSCloud
          { rssCloudDomain :: Maybe Text
    rssCloudDomain = Text -> Element -> Maybe Text
    pAttr Text
    "domain" Element
    e
          , rssCloudPort :: Maybe Text
    rssCloudPort = Text -> Element -> Maybe Text
    pAttr Text
    "port" Element
    e
          , rssCloudPath :: Maybe Text
    rssCloudPath = Text -> Element -> Maybe Text
    pAttr Text
    "path" Element
    e
          , rssCloudRegisterProcedure :: Maybe Text
    rssCloudRegisterProcedure = Text -> Element -> Maybe Text
    pAttr Text
    "registerProcedure" Element
    e
          , rssCloudProtocol :: Maybe Text
    rssCloudProtocol = Text -> Element -> Maybe Text
    pAttr Text
    "protocol" Element
    e
          , rssCloudAttrs :: [(Name, [Content])]
    rssCloudAttrs = ((Name, [Content]) -> Bool)
    -> [(Name, [Content])] -> [(Name, [Content])]
    forall a. (a -> Bool) -> [a] -> [a]
    filter ((Text -> [Text] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    `notElem` [Text]
    known_attrs) (Text -> Bool)
    -> ((Name, [Content]) -> Text) -> (Name, [Content]) -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Name -> Text
    nameLocalName (Name -> Text)
    -> ((Name, [Content]) -> Name) -> (Name, [Content]) -> Text
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Name, [Content]) -> Name
    attrKey) [(Name, [Content])]
    as
          }
      where
        known_attrs :: [Text]
    known_attrs = [Text
    "domain", Text
    "port", Text
    "path", Text
    "registerProcedure", Text
    "protocol"]

    elementToItem :: XML.Element -> Maybe RSSItem
    elementToItem :: Element -> Maybe RSSItem
    elementToItem Element
    e = do
      Bool -> Maybe ()
    forall (f :: * -> *). Alternative f => Bool -> f ()
    guard (Element -> Name
    elementName Element
    e Name -> Name -> Bool
    forall a. Eq a => a -> a -> Bool
    == Text -> Name
    qualName Text
    "item")
      let es :: [Element]
    es = Element -> [Element]
    children Element
    e
      RSSItem -> Maybe RSSItem
    forall a. a -> Maybe a
    forall (m :: * -> *) a. Monad m => a -> m a
    return
        RSSItem
          { rssItemTitle :: Maybe Text
    rssItemTitle = Text -> [Element] -> Maybe Text
    pLeaf Text
    "title" [Element]
    es
          , rssItemLink :: Maybe Text
    rssItemLink = Text -> [Element] -> Maybe Text
    pLeaf Text
    "link" [Element]
    es
          , rssItemDescription :: Maybe Text
    rssItemDescription = Text -> [Element] -> Maybe Text
    pLeaf Text
    "description" [Element]
    es
          , rssItemAuthor :: Maybe Text
    rssItemAuthor = Text -> [Element] -> Maybe Text
    pLeaf Text
    "author" [Element]
    es Maybe Text -> Maybe Text -> Maybe Text
    forall a. Maybe a -> Maybe a -> Maybe a
    forall (m :: * -> *) a. MonadPlus m => m a -> m a -> m a
    `mplus` Name -> [Element] -> Maybe Text
    pQLeaf (Text -> Name
    dcName Text
    "creator") [Element]
    es
          , rssItemCategories :: [RSSCategory]
    rssItemCategories = Text
    -> (Element -> Maybe RSSCategory) -> [Element] -> [RSSCategory]
    forall a. Text -> (Element -> Maybe a) -> [Element] -> [a]
    pMany Text
    "category" Element -> Maybe RSSCategory
    elementToCategory [Element]
    es
          , rssItemComments :: Maybe Text
    rssItemComments = Text -> [Element] -> Maybe Text
    pLeaf Text
    "comments" [Element]
    es
          , rssItemContent :: Maybe Text
    rssItemContent = Text -> [Element] -> Maybe Text
    pLeaf Text
    "content" [Element]
    es
          , rssItemEnclosure :: Maybe RSSEnclosure
    rssItemEnclosure = Text -> [Element] -> Maybe Element
    pNode Text
    "enclosure" [Element]
    es Maybe Element
    -> (Element -> Maybe RSSEnclosure) -> Maybe RSSEnclosure
    forall a b. Maybe a -> (a -> Maybe b) -> Maybe b
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= Element -> Maybe RSSEnclosure
    elementToEnclosure
          , rssItemGuid :: Maybe RSSGuid
    rssItemGuid = Text -> [Element] -> Maybe Element
    pNode Text
    "guid" [Element]
    es Maybe Element -> (Element -> Maybe RSSGuid) -> Maybe RSSGuid
    forall a b. Maybe a -> (a -> Maybe b) -> Maybe b
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= Element -> Maybe RSSGuid
    elementToGuid
          , rssItemPubDate :: Maybe Text
    rssItemPubDate = Text -> [Element] -> Maybe Text
    pLeaf Text
    "pubDate" [Element]
    es Maybe Text -> Maybe Text -> Maybe Text
    forall a. Maybe a -> Maybe a -> Maybe a
    forall (m :: * -> *) a. MonadPlus m => m a -> m a -> m a
    `mplus` Name -> [Element] -> Maybe Text
    pQLeaf (Text -> Name
    dcName Text
    "date") [Element]
    es
          , rssItemSource :: Maybe RSSSource
    rssItemSource = Text -> [Element] -> Maybe Element
    pNode Text
    "source" [Element]
    es Maybe Element -> (Element -> Maybe RSSSource) -> Maybe RSSSource
    forall a b. Maybe a -> (a -> Maybe b) -> Maybe b
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= Element -> Maybe RSSSource
    elementToSource
          , rssItemAttrs :: [(Name, [Content])]
    rssItemAttrs = Element -> [(Name, [Content])]
    elementAttributes Element
    e
          , rssItemOther :: [Element]
    rssItemOther = (Element -> Bool) -> [Element] -> [Element]
    forall a. (a -> Bool) -> [a] -> [a]
    filter ((Name -> [Name] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    `notElem` [Name]
    known_item_elts) (Name -> Bool) -> (Element -> Name) -> Element -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Element -> Name
    elementName) [Element]
    es
          }
      where
        known_item_elts :: [Name]
    known_item_elts =
          (Text -> Name) -> [Text] -> [Name]
    forall a b. (a -> b) -> [a] -> [b]
    map
            Text -> Name
    qualName
            [ Text
    "title"
            , Text
    "link"
            , Text
    "description"
            , Text
    "author"
            , Text
    "category"
            , Text
    "comments"
            , Text
    "enclosure"
            , Text
    "guid"
            , Text
    "pubDate"
            , Text
    "source"
            ]

    elementToSource :: XML.Element -> Maybe RSSSource
    elementToSource :: Element -> Maybe RSSSource
    elementToSource Element
    e = do
      Bool -> Maybe ()
    forall (f :: * -> *). Alternative f => Bool -> f ()
    guard (Element -> Name
    elementName Element
    e Name -> Name -> Bool
    forall a. Eq a => a -> a -> Bool
    == Text -> Name
    qualName Text
    "source")
      let as :: [(Name, [Content])]
    as = Element -> [(Name, [Content])]
    elementAttributes Element
    e
      url <- Text -> Element -> Maybe Text
    pAttr Text
    "url" Element
    e
      return
        RSSSource
          { rssSourceURL = url
          , rssSourceAttrs = filter ((`notElem` known_attrs) . nameLocalName . attrKey) as
          , rssSourceTitle = strContent e
          }
      where
        known_attrs :: [Text]
    known_attrs = [Text
    "url"]

    elementToEnclosure :: XML.Element -> Maybe RSSEnclosure
    elementToEnclosure :: Element -> Maybe RSSEnclosure
    elementToEnclosure Element
    e = do
      Bool -> Maybe ()
    forall (f :: * -> *). Alternative f => Bool -> f ()
    guard (Element -> Name
    elementName Element
    e Name -> Name -> Bool
    forall a. Eq a => a -> a -> Bool
    == Text -> Name
    qualName Text
    "enclosure")
      let as :: [(Name, [Content])]
    as = Element -> [(Name, [Content])]
    elementAttributes Element
    e
      url <- Text -> Element -> Maybe Text
    pAttr Text
    "url" Element
    e
      ty <- pAttr "type" e
      return
        RSSEnclosure
          { rssEnclosureURL = url
          , rssEnclosureType = ty
          , rssEnclosureLength = pAttr "length" e >>= readInt
          , rssEnclosureAttrs = filter ((`notElem` known_attrs) . nameLocalName . attrKey) as
          }
      where
        known_attrs :: [Text]
    known_attrs = [Text
    "url", Text
    "type", Text
    "length"]

    elementToGuid :: XML.Element -> Maybe RSSGuid
    elementToGuid :: Element -> Maybe RSSGuid
    elementToGuid Element
    e = do
      Bool -> Maybe ()
    forall (f :: * -> *). Alternative f => Bool -> f ()
    guard (Element -> Name
    elementName Element
    e Name -> Name -> Bool
    forall a. Eq a => a -> a -> Bool
    == Text -> Name
    qualName Text
    "guid")
      let as :: [(Name, [Content])]
    as = Element -> [(Name, [Content])]
    elementAttributes Element
    e
      RSSGuid -> Maybe RSSGuid
    forall a. a -> Maybe a
    forall (m :: * -> *) a. Monad m => a -> m a
    return
        RSSGuid
          { rssGuidPermanentURL :: Maybe Bool
    rssGuidPermanentURL = Text -> Element -> Maybe Text
    pAttr Text
    "isPermaLink" Element
    e Maybe Text -> (Text -> Maybe Bool) -> Maybe Bool
    forall a b. Maybe a -> (a -> Maybe b) -> Maybe b
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= Text -> Maybe Bool
    readBool
          , rssGuidAttrs :: [(Name, [Content])]
    rssGuidAttrs = ((Name, [Content]) -> Bool)
    -> [(Name, [Content])] -> [(Name, [Content])]
    forall a. (a -> Bool) -> [a] -> [a]
    filter ((Text -> [Text] -> Bool
    forall (t :: * -> *) a. (Foldable t, Eq a) => a -> t a -> Bool
    `notElem` [Text]
    known_attrs) (Text -> Bool)
    -> ((Name, [Content]) -> Text) -> (Name, [Content]) -> Bool
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Name -> Text
    nameLocalName (Name -> Text)
    -> ((Name, [Content]) -> Name) -> (Name, [Content]) -> Text
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (Name, [Content]) -> Name
    attrKey) [(Name, [Content])]
    as
          , rssGuidValue :: Text
    rssGuidValue = Element -> Text
    strContent Element
    e
          }
      where
        known_attrs :: [Text]
    known_attrs = [Text
    "isPermaLink"]

    elementToTextInput :: XML.Element -> Maybe RSSTextInput
    elementToTextInput :: Element -> Maybe RSSTextInput
    elementToTextInput Element
    e = do
      Bool -> Maybe ()
    forall (f :: * -> *). Alternative f => Bool -> f ()
    guard (Element -> Name
    elementName Element
    e Name -> Name -> Bool
    forall a. Eq a => a -> a -> Bool
    == Text -> Name
    qualName Text
    "textInput")
      let es :: [Element]
    es = Element -> [Element]
    children Element
    e
      title <- Text -> [Element] -> Maybe Text
    pLeaf Text
    "title" [Element]
    es
      desc <- pLeaf "description" es
      name <- pLeaf "name" es
      link <- pLeaf "link" es
      return
        RSSTextInput
          { rssTextInputTitle = title
          , rssTextInputDesc = desc
          , rssTextInputName = name
          , rssTextInputLink = link
          , rssTextInputAttrs = elementAttributes e
          , rssTextInputOther = filter ((`notElem` known_ti_elts) . elementName) es
          }
      where
        known_ti_elts :: [Name]
    known_ti_elts = (Text -> Name) -> [Text] -> [Name]
    forall a b. (a -> b) -> [a] -> [b]
    map Text -> Name
    qualName [Text
    "title", Text
    "description", Text
    "name", Text
    "link"]

    elementToSkipHours :: XML.Element -> Maybe [Integer]
    elementToSkipHours :: Element -> Maybe [Integer]
    elementToSkipHours Element
    e = do
      Bool -> Maybe ()
    forall (f :: * -> *). Alternative f => Bool -> f ()
    guard (Element -> Name
    elementName Element
    e Name -> Name -> Bool
    forall a. Eq a => a -> a -> Bool
    == Text -> Name
    qualName Text
    "skipHours")
         -- don't bother checking that this is below limit ( <= 24)
      [Integer] -> Maybe [Integer]
    forall a. a -> Maybe a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Text -> (Element -> Maybe Integer) -> [Element] -> [Integer]
    forall a. Text -> (Element -> Maybe a) -> [Element] -> [a]
    pMany Text
    "hour" (Text -> Maybe Integer
    readInt (Text -> Maybe Integer)
    -> (Element -> Text) -> Element -> Maybe Integer
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Element -> Text
    strContent) (Element -> [Element]
    children Element
    e))

    elementToSkipDays :: XML.Element -> Maybe [Text]
    elementToSkipDays :: Element -> Maybe [Text]
    elementToSkipDays Element
    e = do
      Bool -> Maybe ()
    forall (f :: * -> *). Alternative f => Bool -> f ()
    guard (Element -> Name
    elementName Element
    e Name -> Name -> Bool
    forall a. Eq a => a -> a -> Bool
    == Text -> Name
    qualName Text
    "skipDays")
         -- don't bother checking that this is below limit ( <= 7)
      [Text] -> Maybe [Text]
    forall a. a -> Maybe a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Text -> (Element -> Maybe Text) -> [Element] -> [Text]
    forall a. Text -> (Element -> Maybe a) -> [Element] -> [a]
    pMany Text
    "day" (Text -> Maybe Text
    forall a. a -> Maybe a
    forall (m :: * -> *) a. Monad m => a -> m a
    return (Text -> Maybe Text) -> (Element -> Text) -> Element -> Maybe Text
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . Element -> Text
    strContent) (Element -> [Element]
    children Element
    e))

    ----
    readBool :: Text -> Maybe Bool
    readBool :: Text -> Maybe Bool
    readBool Text
    s =
      case (Char -> Bool) -> Text -> Text
    Data.Text.dropWhile Char -> Bool
    isSpace Text
    s of
        Text
    "true" -> Bool -> Maybe Bool
    forall a. a -> Maybe a
    Just Bool
    True
        Text
    "false" -> Bool -> Maybe Bool
    forall a. a -> Maybe a
    Just Bool
    False
        Text
    _ -> Maybe Bool
    forall a. Maybe a
    Nothing