{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE RankNTypes #-}
module Text.Atom.Conduit.Render
(
renderAtomFeed
, renderAtomEntry
, renderAtomContent
, renderAtomSource
, renderAtomGenerator
, renderAtomLink
, renderAtomCategory
, renderAtomPerson
, renderAtomText
) where
import Text.Atom.Lens
import Text.Atom.Types
import Control.Monad
import Data.Conduit
import Data.Monoid
import Data.NonNull
import Data.Text as Text
import Data.Text.Encoding
import Data.Time.Clock
import Data.Time.LocalTime
import Data.Time.RFC3339
import Data.XML.Types
import Lens.Simple
import Text.XML.Stream.Render
import URI.ByteString
renderAtomFeed :: (Monad m) => AtomFeed -> ConduitT () Event m ()
renderAtomFeed f = atomTag "feed" (attr "xmlns" "http://www.w3.org/2005/Atom") $ do
forM_ (f^.feedAuthorsL) $ renderAtomPerson "author"
forM_ (f^.feedCategoriesL) renderAtomCategory
forM_ (f^.feedContributorsL) $ renderAtomPerson "contributor"
forM_ (f^.feedEntriesL) renderAtomEntry
forM_ (f^.feedGeneratorL) renderAtomGenerator
forM_ (feedIcon f) $ atomTag "icon" mempty . content . decodeUtf8 . withAtomURI serializeURIRef'
atomTag "id" mempty . content $ f^.feedIdL
forM_ (f^.feedLinksL) renderAtomLink
forM_ (feedLogo f) $ atomTag "logo" mempty . content . decodeUtf8 . withAtomURI serializeURIRef'
forM_ (f^.feedRightsL) $ renderAtomText "rights"
forM_ (f^.feedSubtitleL) $ renderAtomText "subtitle"
renderAtomText "title" $ f^.feedTitleL
dateTag "updated" $ f^.feedUpdatedL
renderAtomEntry :: (Monad m) => AtomEntry -> ConduitT () Event m ()
renderAtomEntry e = atomTag "entry" mempty $ do
forM_ (e^.entryAuthorsL) $ renderAtomPerson "author"
forM_ (e^.entryCategoriesL) renderAtomCategory
forM_ (e^.entryContentL) renderAtomContent
forM_ (e^.entryContributorsL) $ renderAtomPerson "contributor"
atomTag "id" mempty . content $ e^.entryIdL
forM_ (e^.entryLinksL) renderAtomLink
forM_ (e^.entryPublishedL) $ dateTag "published"
forM_ (e^.entryRightsL) $ renderAtomText "rights"
forM_ (e^.entrySourceL) renderAtomSource
forM_ (e^.entrySummaryL) $ renderAtomText "summary"
renderAtomText "title" (e^.entryTitleL)
dateTag "updated" (e^.entryUpdatedL)
renderAtomContent :: (Monad m) => AtomContent -> ConduitT () Event m ()
renderAtomContent (AtomContentInlineXHTML t) = atomTag "content" (attr "type" "xhtml")
. tag "{http://www.w3.org/1999/xhtml}div" mempty $ content t
renderAtomContent (AtomContentOutOfLine ctype uri) = atomTag "content" (nonEmptyAttr "type" ctype <> attr "src" (decodeUtf8 $ withAtomURI serializeURIRef' uri)) $ return ()
renderAtomContent (AtomContentInlineText TypeHTML t) = atomTag "content" (attr "type" "html") $ content t
renderAtomContent (AtomContentInlineText TypeText t) = atomTag "content" mempty $ content t
renderAtomContent (AtomContentInlineOther ctype t) = atomTag "content" (attr "type" ctype) $ content t
renderAtomSource :: (Monad m) => AtomSource -> ConduitT () Event m ()
renderAtomSource s = atomTag "source" mempty $ do
forM_ (s^.sourceAuthorsL) $ renderAtomPerson "author"
forM_ (s^.sourceCategoriesL) renderAtomCategory
forM_ (s^.sourceContributorsL) $ renderAtomPerson "contributor"
forM_ (s^.sourceGeneratorL) renderAtomGenerator
forM_ (sourceIcon s) $ atomTag "icon" mempty . content . decodeUtf8 . withAtomURI serializeURIRef'
unless (Text.null $ s^.sourceIdL) . atomTag "id" mempty . content $ s^.sourceIdL
forM_ (s^.sourceLinksL) renderAtomLink
forM_ (sourceLogo s) $ atomTag "logo" mempty . content . decodeUtf8 . withAtomURI serializeURIRef'
forM_ (s^.sourceRightsL) $ renderAtomText "rights"
forM_ (s^.sourceSubtitleL) $ renderAtomText "subtitle"
forM_ (s^.sourceTitleL) $ renderAtomText "title"
forM_ (s^.sourceUpdatedL) $ dateTag "updated"
renderAtomGenerator :: (Monad m) => AtomGenerator -> ConduitT () Event m ()
renderAtomGenerator g = atomTag "generator" attributes . content . toNullable $ g^.generatorContentL
where attributes = optionalAttr "uri" (decodeUtf8 . withAtomURI serializeURIRef' <$> generatorUri g)
<> nonEmptyAttr "version" (g^.generatorVersionL)
renderAtomLink :: (Monad m) => AtomLink -> ConduitT () Event m ()
renderAtomLink l = atomTag "link" linkAttrs $ return ()
where linkAttrs = attr "href" (decodeUtf8 . withAtomURI serializeURIRef' $ linkHref l)
<> nonEmptyAttr "rel" (l^.linkRelL)
<> nonEmptyAttr "type" (l^.linkTypeL)
<> nonEmptyAttr "hreflang" (l^.linkLangL)
<> nonEmptyAttr "title" (l^.linkTitleL)
<> nonEmptyAttr "length" (l^.linkLengthL)
renderAtomCategory :: (Monad m) => AtomCategory -> ConduitT () Event m ()
renderAtomCategory c = atomTag "category" attributes $ return ()
where attributes = attr "term" (toNullable $ c^.categoryTermL)
<> nonEmptyAttr "scheme" (c^.categorySchemeL)
<> nonEmptyAttr "label" (c^.categoryLabelL)
renderAtomPerson :: (Monad m) => Text -> AtomPerson -> ConduitT () Event m ()
renderAtomPerson name p = atomTag name mempty $ do
atomTag "name" mempty . content . toNullable $ p^.personNameL
unless (Text.null $ p^.personEmailL) $ atomTag "email" mempty . content $ p^.personEmailL
forM_ (personUri p) $ atomTag "uri" mempty . content . decodeUtf8 . withAtomURI serializeURIRef'
renderAtomText :: (Monad m) => Text -> AtomText -> ConduitT () Event m ()
renderAtomText name (AtomXHTMLText t) = atomTag name (attr "type" "xhtml")
. tag "{http://www.w3.org/1999/xhtml}div" mempty $ content t
renderAtomText name (AtomPlainText TypeHTML t) = atomTag name (attr "type" "html") $ content t
renderAtomText name (AtomPlainText TypeText t) = atomTag name mempty $ content t
atomTag :: Monad m => Text -> Attributes -> ConduitT () Event m () -> ConduitT () Event m ()
atomTag name = tag (Name name (Just "http://www.w3.org/2005/Atom") (Just "atom"))
dateTag :: (Monad m) => Text -> UTCTime -> ConduitT () Event m ()
dateTag name = atomTag name mempty . content . formatTimeRFC3339 . utcToZonedTime utc
nonEmptyAttr :: Name -> Text -> Attributes
nonEmptyAttr name value
| value == mempty = mempty
| otherwise = attr name value