feed 1.0.1.0 → 1.3.2.1
raw patch · 27 files changed
Files
- CHANGELOG.md +27/−0
- README.lhs +93/−48
- README.md +93/−48
- feed.cabal +55/−29
- src/Data/Text/Util.hs +12/−8
- src/Text/Atom/Feed.hs +108/−92
- src/Text/Atom/Feed/Export.hs +4/−3
- src/Text/Atom/Feed/Import.hs +7/−5
- src/Text/Atom/Feed/Validate.hs +2/−4
- src/Text/Atom/Pub.hs +24/−22
- src/Text/DublinCore/Types.hs +6/−4
- src/Text/Feed/Export.hs +7/−2
- src/Text/Feed/Import.hs +2/−6
- src/Text/Feed/Query.hs +18/−0
- src/Text/RSS/Export.hs +1/−1
- src/Text/RSS/Import.hs +1/−0
- src/Text/RSS/Syntax.hs +111/−89
- src/Text/RSS1/Export.hs +1/−1
- src/Text/RSS1/Syntax.hs +86/−72
- tests/Example/CreateAtom.hs +6/−5
- tests/ImportExport.hs +44/−0
- tests/Main.hs +5/−1
- tests/Text/Atom/Tests.hs +1/−1
- tests/Text/Atom/Validate/Tests.hs +34/−0
- tests/Text/RSS/Tests.hs +1/−1
- tests/doctest-driver.hs +1/−0
- tests/files/import_export_atom.xml +35/−0
CHANGELOG.md view
@@ -1,3 +1,30 @@+#### 1.3.2.1+* text 2.0 support, thanks to Alexander Batischev.+* Moved the repository to https://github.com/haskell-party/++### 1.3.2.0+* Expose RSS/Atom item content through queries by using `getItemContent`.++### 1.3.0.1+* Add a test to check that validation works on a simple entry.+* Change attribute handling when validating so that type attribute is recognised properly on content.++#### 1.3.0.0+* Reverted changes to `EntryContent` that came in 1.2.0.0. Thanks to Tomas Janousek.++#### 1.2.0.1++* Get rid of xmlns:ns and ns:-prefixed attributes that confused some applications, thanks to Tomas Janousek.+* GHC 8.8 support++## 1.2.0.0++Updated `EntryContent`'s `HTMLContent` to wrap an `XML.Element` instead of `Text`. Thanks to Jake Keuhlen.++## 1.1.0.0++* `parseFeedFromFile` now returns `IO (Maybe Feed)` instead of `IO Feed` to distinguish IO exceptions from parse failures. Thanks to Jake Keuhlen.+ #### 1.0.1.0 * Support for GHC 8.6.x libraries
README.lhs view
@@ -1,18 +1,20 @@ # Feed [](http://hackage.haskell.org/package/feed)-[](https://travis-ci.org/bergmark/feed)+ + ## Goal Interfacing with *RSS* (v 0.9x, 2.x, 1.0) + *Atom* feeds. - Parsers-- Pretty Printers+- Constructors+- Rendering - Querying To help working with the multiple feed formats we've ended up with-this set of modules providing parsers, pretty printers and some utility+this set of modules providing parsers, printers and some utility code for querying and just generally working with a concrete representation of feeds in Haskell. @@ -37,35 +39,50 @@ module Main where import Prelude.Compat hiding (take)-+import Data.Maybe import Data.Text import Data.XML.Types as XML import qualified Data.Text.Lazy as Lazy+import Text.Feed.Types++import Text.XML (def, rsPretty) import qualified Text.Atom.Feed as Atom-import qualified Text.Atom.Feed.Export as Export (textFeed)+import qualified Text.Feed.Export as Export (textFeedWith) myFeed :: Atom.Feed myFeed = Atom.nullFeed- "http://example.com/atom.xml" -- ^ id- (Atom.TextString "Example Website") -- ^ title- "2017-08-01" -- ^ last updated+ "http://example.com/atom.xml"+ (Atom.TextString "Example Website")+ "2017-08-01" ``` Now we can export the feed to `Text`. ```haskell-renderFeed :: Atom.Feed -> Maybe Lazy.Text-renderFeed = Export.textFeed+renderFeed :: Atom.Feed -> Lazy.Text+renderFeed = fromJust . Export.textFeedWith def{rsPretty = True} . AtomFeed ``` -```-> renderFeed myFeed-<?xml version="1.0" encoding="UTF-8"?>-<feed xmlns="http://www.w3.org/2005/Atom">- <title xmlns:ns="http://www.w3.org/2005/Atom" ns:type="text">Example Website</title>- <id>http://example.com/atom.xml</id>- <updated>2017-08-01</updated>-</feed>+We can now render our feed:++```haskell+-- |+-- $setup+-- >>> import qualified Data.Text.Lazy.IO as Lazy+--+-- >>> Lazy.putStr $ renderFeed myFeed+-- <?xml version="1.0" encoding="UTF-8"?>+-- <feed xmlns="http://www.w3.org/2005/Atom">+-- <title type="text">+-- Example Website+-- </title>+-- <id>+-- http://example.com/atom.xml+-- </id>+-- <updated>+-- 2017-08-01+-- </updated>+-- </feed> ``` The `TextContent` sum type allows us to specify which type of text we're providing.@@ -120,37 +137,65 @@ } ``` -```-> renderFeed feed-<?xml version="1.0" encoding="UTF-8"?>-<feed xmlns="http://www.w3.org/2005/Atom">- <title xmlns:ns="http://www.w3.org/2005/Atom" ns:type="text">Example Website</title>- <id>http://example.com/atom.xml</id>- <updated>2017-08-01</updated>- <link xmlns:ns="http://www.w3.org/2005/Atom" ns:href="http://example.com/"/>- <entry>- <id>http://example.com/2</id>- <title xmlns:ns="http://www.w3.org/2005/Atom" ns:type="text">Bar.</title>- <updated>2000-02-02T18:30:00Z</updated>- <author>- <name>J. Smith</name>- </author>- <content xmlns:ns="http://www.w3.org/2005/Atom" ns:type="html">Bar.</content>- <link xmlns:ns="http://www.w3.org/2005/Atom" ns:href="http://example.com/2"/>- </entry>- <entry>- <id>http://example.com/1</id>- <title xmlns:ns="http://www.w3.org/2005/Atom" ns:type="text">Foo.</title>- <updated>2000-01-01T18:30:00Z</updated>- <author>- <name>J. Smith</name>- </author>- <content xmlns:ns="http://www.w3.org/2005/Atom" ns:type="html">Foo.</content>- <link xmlns:ns="http://www.w3.org/2005/Atom" ns:href="http://example.com/1"/>- </entry>-</feed>+```haskell+-- |+-- >>> Lazy.putStr $ renderFeed feed+-- <?xml version="1.0" encoding="UTF-8"?>+-- <feed xmlns="http://www.w3.org/2005/Atom">+-- <title type="text">+-- Example Website+-- </title>+-- <id>+-- http://example.com/atom.xml+-- </id>+-- <updated>+-- 2017-08-01+-- </updated>+-- <link href="http://example.com/"/>+-- <entry>+-- <id>+-- http://example.com/2+-- </id>+-- <title type="text">+-- Bar.+-- </title>+-- <updated>+-- 2000-02-02T18:30:00Z+-- </updated>+-- <author>+-- <name>+-- J. Smith+-- </name>+-- </author>+-- <content type="html">+-- Bar.+-- </content>+-- <link href="http://example.com/2"/>+-- </entry>+-- <entry>+-- <id>+-- http://example.com/1+-- </id>+-- <title type="text">+-- Foo.+-- </title>+-- <updated>+-- 2000-01-01T18:30:00Z+-- </updated>+-- <author>+-- <name>+-- J. Smith+-- </name>+-- </author>+-- <content type="html">+-- Foo.+-- </content>+-- <link href="http://example.com/1"/>+-- </entry>+-- </feed> ```-See [here](https://github.com/bergmark/feed/blob/master/tests/Example/CreateAtom.hs) for this content as an uninterrupted running example.++See [here](https://github.com/haskell-party/feed/blob/master/tests/Example/CreateAtom.hs) for this content as an uninterrupted running example. ```haskell -- Dummy main needed to compile this file with markdown-unlit
README.md view
@@ -1,18 +1,20 @@ # Feed [](http://hackage.haskell.org/package/feed)-[](https://travis-ci.org/bergmark/feed)+ + ## Goal Interfacing with *RSS* (v 0.9x, 2.x, 1.0) + *Atom* feeds. - Parsers-- Pretty Printers+- Constructors+- Rendering - Querying To help working with the multiple feed formats we've ended up with-this set of modules providing parsers, pretty printers and some utility+this set of modules providing parsers, printers and some utility code for querying and just generally working with a concrete representation of feeds in Haskell. @@ -37,35 +39,50 @@ module Main where import Prelude.Compat hiding (take)-+import Data.Maybe import Data.Text import Data.XML.Types as XML import qualified Data.Text.Lazy as Lazy+import Text.Feed.Types++import Text.XML (def, rsPretty) import qualified Text.Atom.Feed as Atom-import qualified Text.Atom.Feed.Export as Export (textFeed)+import qualified Text.Feed.Export as Export (textFeedWith) myFeed :: Atom.Feed myFeed = Atom.nullFeed- "http://example.com/atom.xml" -- ^ id- (Atom.TextString "Example Website") -- ^ title- "2017-08-01" -- ^ last updated+ "http://example.com/atom.xml"+ (Atom.TextString "Example Website")+ "2017-08-01" ``` Now we can export the feed to `Text`. ```haskell-renderFeed :: Atom.Feed -> Maybe Lazy.Text-renderFeed = Export.textFeed+renderFeed :: Atom.Feed -> Lazy.Text+renderFeed = fromJust . Export.textFeedWith def{rsPretty = True} . AtomFeed ``` -```-> renderFeed myFeed-<?xml version="1.0" encoding="UTF-8"?>-<feed xmlns="http://www.w3.org/2005/Atom">- <title xmlns:ns="http://www.w3.org/2005/Atom" ns:type="text">Example Website</title>- <id>http://example.com/atom.xml</id>- <updated>2017-08-01</updated>-</feed>+We can now render our feed:++```haskell+-- |+-- $setup+-- >>> import qualified Data.Text.Lazy.IO as Lazy+--+-- >>> Lazy.putStr $ renderFeed myFeed+-- <?xml version="1.0" encoding="UTF-8"?>+-- <feed xmlns="http://www.w3.org/2005/Atom">+-- <title type="text">+-- Example Website+-- </title>+-- <id>+-- http://example.com/atom.xml+-- </id>+-- <updated>+-- 2017-08-01+-- </updated>+-- </feed> ``` The `TextContent` sum type allows us to specify which type of text we're providing.@@ -120,37 +137,65 @@ } ``` -```-> renderFeed feed-<?xml version="1.0" encoding="UTF-8"?>-<feed xmlns="http://www.w3.org/2005/Atom">- <title xmlns:ns="http://www.w3.org/2005/Atom" ns:type="text">Example Website</title>- <id>http://example.com/atom.xml</id>- <updated>2017-08-01</updated>- <link xmlns:ns="http://www.w3.org/2005/Atom" ns:href="http://example.com/"/>- <entry>- <id>http://example.com/2</id>- <title xmlns:ns="http://www.w3.org/2005/Atom" ns:type="text">Bar.</title>- <updated>2000-02-02T18:30:00Z</updated>- <author>- <name>J. Smith</name>- </author>- <content xmlns:ns="http://www.w3.org/2005/Atom" ns:type="html">Bar.</content>- <link xmlns:ns="http://www.w3.org/2005/Atom" ns:href="http://example.com/2"/>- </entry>- <entry>- <id>http://example.com/1</id>- <title xmlns:ns="http://www.w3.org/2005/Atom" ns:type="text">Foo.</title>- <updated>2000-01-01T18:30:00Z</updated>- <author>- <name>J. Smith</name>- </author>- <content xmlns:ns="http://www.w3.org/2005/Atom" ns:type="html">Foo.</content>- <link xmlns:ns="http://www.w3.org/2005/Atom" ns:href="http://example.com/1"/>- </entry>-</feed>+```haskell+-- |+-- >>> Lazy.putStr $ renderFeed feed+-- <?xml version="1.0" encoding="UTF-8"?>+-- <feed xmlns="http://www.w3.org/2005/Atom">+-- <title type="text">+-- Example Website+-- </title>+-- <id>+-- http://example.com/atom.xml+-- </id>+-- <updated>+-- 2017-08-01+-- </updated>+-- <link href="http://example.com/"/>+-- <entry>+-- <id>+-- http://example.com/2+-- </id>+-- <title type="text">+-- Bar.+-- </title>+-- <updated>+-- 2000-02-02T18:30:00Z+-- </updated>+-- <author>+-- <name>+-- J. Smith+-- </name>+-- </author>+-- <content type="html">+-- Bar.+-- </content>+-- <link href="http://example.com/2"/>+-- </entry>+-- <entry>+-- <id>+-- http://example.com/1+-- </id>+-- <title type="text">+-- Foo.+-- </title>+-- <updated>+-- 2000-01-01T18:30:00Z+-- </updated>+-- <author>+-- <name>+-- J. Smith+-- </name>+-- </author>+-- <content type="html">+-- Foo.+-- </content>+-- <link href="http://example.com/1"/>+-- </entry>+-- </feed> ```-See [here](https://github.com/bergmark/feed/blob/master/tests/Example/CreateAtom.hs) for this content as an uninterrupted running example.++See [here](https://github.com/haskell-party/feed/blob/master/tests/Example/CreateAtom.hs) for this content as an uninterrupted running example. ```haskell -- Dummy main needed to compile this file with markdown-unlit
feed.cabal view
@@ -1,5 +1,5 @@ name: feed-version: 1.0.1.0+version: 1.3.2.1 license: BSD3 license-file: LICENSE category: Text@@ -13,25 +13,28 @@ of feeds in Haskell. . See here for an example of how to create an Atom feed:- <https://github.com/bergmark/feed/blob/master/tests/Example/CreateAtom.hs>+ <https://github.com/haskell-party/feed/blob/master/tests/Example/CreateAtom.hs> . For basic reading and editing of feeds, consult the documentation of the Text.Feed.* hierarchy. author: Sigbjorn Finne <sof@forkIO.com> maintainer: Adam Bergmark <adam@bergmark.nl>-homepage: https://github.com/bergmark/feed-bug-reports: https://github.com/bergmark/feed/issues-cabal-version: >= 1.8+homepage: https://github.com/haskell-party/feed+bug-reports: https://github.com/haskell-party/feed/issues+cabal-version: 2.0 build-type: Simple tested-with:- GHC == 7.4.2- , GHC == 7.6.3+ GHC == 7.6.3 , GHC == 7.8.4 , GHC == 7.10.3 , GHC == 8.0.2- , GHC == 8.2.1- , GHC == 8.4.1- , GHC == 8.6.1+ , GHC == 8.2.2+ , GHC == 8.4.4+ , GHC == 8.6.5+ , GHC == 8.8.4+ , GHC == 8.10.7+ , GHC == 9.0.1+ , GHC == 9.2.1 data-files: tests/files/*.xml extra-source-files:@@ -40,12 +43,13 @@ source-repository head type: git- location: https://github.com/bergmark/feed.git+ location: https://github.com/haskell-party/feed.git library ghc-options: -Wall hs-source-dirs: src- extensions:+ default-language: Haskell2010+ default-extensions: NoImplicitPrelude OverloadedStrings exposed-modules:@@ -75,32 +79,37 @@ Data.Text.Util Data.XML.Compat build-depends:- base >= 4 && < 4.13- , base-compat >= 0.9 && < 0.11- , bytestring >= 0.9 && < 0.11+ base >= 4 && < 4.17+ , base-compat >= 0.9 && < 0.13+ , bytestring >= 0.9 && < 0.12 , old-locale == 1.0.* , old-time >= 1 && < 1.2 , safe == 0.3.*- , text < 1.3- , time < 1.9+ , text < 1.3 || ==2.0.*+ , time < 1.12 , time-locale-compat == 0.1.* , utf8-string < 1.1 , xml-types >= 0.3.6 && < 0.4- , xml-conduit >= 1.3 && < 1.9+ , xml-conduit >= 1.3 && < 1.10 test-suite tests ghc-options: -Wall hs-source-dirs: tests main-is: Main.hs type: exitcode-stdio-1.0- extensions:+ default-language: Haskell2010+ default-extensions: NoImplicitPrelude OverloadedStrings+ autogen-modules:+ Paths_feed other-modules: Paths_feed Example Example.CreateAtom+ ImportExport Text.Atom.Tests+ Text.Atom.Validate.Tests Text.Feed.Util.Tests Text.RSS.Equals Text.RSS.Export.Tests@@ -108,32 +117,49 @@ Text.RSS.Tests Text.RSS.Utils build-depends:- base >= 4 && < 4.13- , base-compat >= 0.9 && < 0.11+ base >= 4.6 && < 4.17+ , base-compat >= 0.9 && < 0.13 , HUnit >= 1.2 && < 1.7 , feed , old-time >= 1 && < 1.2+ , syb , test-framework == 0.8.* , test-framework-hunit == 0.3.*- , text < 1.3- , time < 1.9+ , text < 1.3 || ==2.0.*+ , time < 1.12 , xml-types >= 0.3.6 && < 0.4- , xml-conduit >= 1.3 && < 1.9+ , xml-conduit >= 1.3 && < 1.10 test-suite readme ghc-options: -Wall -pgmL markdown-unlit main-is: README.lhs- extensions:+ default-language: Haskell2010+ default-extensions: NoImplicitPrelude OverloadedStrings type: exitcode-stdio-1.0 build-depends:- base >= 4 && < 4.13- , base-compat >= 0.9 && < 0.11+ base >= 4.6+ , base-compat >= 0.9 && < 0.13 , text- , xml-types , feed , xml-conduit , xml-types build-tool-depends:- markdown-unlit:markdown-unlit == 0.4.*+ markdown-unlit:markdown-unlit >= 0.4 && < 0.6++test-suite readme-doctests+ hs-source-dirs: tests+ main-is: doctest-driver.hs+ type: exitcode-stdio-1.0+ default-language: Haskell2010+ if impl(ghc < 8)+ buildable: False+ build-depends:+ base >= 4.6+ , doctest+ , doctest-driver-gen+ , feed+ build-tool-depends:+ markdown-unlit:markdown-unlit >= 0.4 && < 0.6+ , doctest-driver-gen:doctest-driver-gen
src/Data/Text/Util.hs view
@@ -1,6 +1,7 @@ module Data.Text.Util ( readInt , renderFeed+ , renderFeedWith ) where import Prelude.Compat@@ -8,9 +9,9 @@ import Data.Text import Data.Text.Read +import qualified Data.Text.Lazy as TL import qualified Data.XML.Types as XT -- from xml-types import qualified Text.XML as XC -- from xml-conduit-import qualified Data.Text.Lazy as TL readInt :: Text -> Maybe Integer readInt s =@@ -19,14 +20,17 @@ _ -> Nothing renderFeed :: (a -> XT.Element) -> a -> Maybe TL.Text-renderFeed cf f = let e = cf f- d = elToDoc e- in XC.renderText XC.def <$> d+renderFeed = renderFeedWith XC.def +renderFeedWith :: XC.RenderSettings -> (a -> XT.Element) -> a -> Maybe TL.Text+renderFeedWith opts cf f =+ let e = cf f+ d = elToDoc e+ in XC.renderText opts <$> d -- Ancillaries --- elToDoc :: XT.Element -> Maybe XC.Document-elToDoc el = let txd = XT.Document (XC.Prologue [] Nothing []) el []- cxd = XC.fromXMLDocument txd- in either (const Nothing) Just cxd+elToDoc el =+ let txd = XT.Document (XC.Prologue [] Nothing []) el []+ cxd = XC.fromXMLDocument txd+ in either (const Nothing) Just cxd
src/Text/Atom/Feed.hs view
@@ -54,77 +54,85 @@ type MediaType = Text -data Feed = Feed- { feedId :: URI- , feedTitle :: TextContent- , feedUpdated :: Date- , feedAuthors :: [Person]- , feedCategories :: [Category]- , feedContributors :: [Person]- , feedGenerator :: Maybe Generator- , feedIcon :: Maybe URI- , feedLinks :: [Link]- , feedLogo :: Maybe URI- , feedRights :: Maybe TextContent- , feedSubtitle :: Maybe TextContent- , feedEntries :: [Entry]- , feedAttrs :: [Attr]- , feedOther :: [XML.Element]- } deriving (Show)+data Feed =+ Feed+ { feedId :: URI+ , feedTitle :: TextContent+ , feedUpdated :: Date+ , feedAuthors :: [Person]+ , feedCategories :: [Category]+ , feedContributors :: [Person]+ , feedGenerator :: Maybe Generator+ , feedIcon :: Maybe URI+ , feedLinks :: [Link]+ , feedLogo :: Maybe URI+ , feedRights :: Maybe TextContent+ , feedSubtitle :: Maybe TextContent+ , feedEntries :: [Entry]+ , feedAttrs :: [Attr]+ , feedOther :: [XML.Element]+ }+ deriving (Show) -data Entry = Entry- { entryId :: URI- , entryTitle :: TextContent- , entryUpdated :: Date- , entryAuthors :: [Person]- , entryCategories :: [Category]- , entryContent :: Maybe EntryContent- , entryContributor :: [Person]- , entryLinks :: [Link]- , entryPublished :: Maybe Date- , entryRights :: Maybe TextContent- , entrySource :: Maybe Source- , entrySummary :: Maybe TextContent- , entryInReplyTo :: Maybe InReplyTo- , entryInReplyTotal :: Maybe InReplyTotal- , entryAttrs :: [Attr]- , entryOther :: [XML.Element]- } deriving (Show)+data Entry =+ Entry+ { entryId :: URI+ , entryTitle :: TextContent+ , entryUpdated :: Date+ , entryAuthors :: [Person]+ , entryCategories :: [Category]+ , entryContent :: Maybe EntryContent+ , entryContributor :: [Person]+ , entryLinks :: [Link]+ , entryPublished :: Maybe Date+ , entryRights :: Maybe TextContent+ , entrySource :: Maybe Source+ , entrySummary :: Maybe TextContent+ , entryInReplyTo :: Maybe InReplyTo+ , entryInReplyTotal :: Maybe InReplyTotal+ , entryAttrs :: [Attr]+ , entryOther :: [XML.Element]+ }+ deriving (Show) data EntryContent = TextContent Text | HTMLContent Text | XHTMLContent XML.Element- | MixedContent (Maybe Text)- [XML.Node]- | ExternalContent (Maybe MediaType)- URI+ | MixedContent (Maybe Text) [XML.Node]+ | ExternalContent (Maybe MediaType) URI deriving (Show) -data Category = Category- { catTerm :: Text -- ^ the tag\/term of the category.- , catScheme :: Maybe URI -- ^ optional URL for identifying the categorization scheme.- , catLabel :: Maybe Text -- ^ human-readable label of the category- , catOther :: [XML.Element] -- ^ unknown elements, for extensibility.- } deriving (Show)+data Category =+ Category+ { catTerm :: Text -- ^ the tag\/term of the category.+ , catScheme :: Maybe URI -- ^ optional URL for identifying the categorization scheme.+ , catLabel :: Maybe Text -- ^ human-readable label of the category+ , catOther :: [XML.Element] -- ^ unknown elements, for extensibility.+ }+ deriving (Show) -data Generator = Generator- { genURI :: Maybe URI- , genVersion :: Maybe Text- , genText :: Text- } deriving (Eq, Show)+data Generator =+ Generator+ { genURI :: Maybe URI+ , genVersion :: Maybe Text+ , genText :: Text+ }+ deriving (Eq, Show) -data Link = Link- { linkHref :: URI+data Link =+ Link+ { linkHref :: URI -- ToDo: make the switch over to using the Atom.Feed.Link relation type.- , linkRel :: Maybe (Either NCName URI)- , linkType :: Maybe MediaType- , linkHrefLang :: Maybe Text- , linkTitle :: Maybe Text- , linkLength :: Maybe Text- , linkAttrs :: [Attr]- , linkOther :: [XML.Element]- } deriving (Show)+ , linkRel :: Maybe (Either NCName URI)+ , linkType :: Maybe MediaType+ , linkHrefLang :: Maybe Text+ , linkTitle :: Maybe Text+ , linkLength :: Maybe Text+ , linkAttrs :: [Attr]+ , linkOther :: [XML.Element]+ }+ deriving (Show) data TextContent = TextString Text@@ -137,41 +145,49 @@ txtToString (HTMLString s) = unpack s txtToString (XHTMLString x) = show x -data Source = Source- { sourceAuthors :: [Person]- , sourceCategories :: [Category]- , sourceGenerator :: Maybe Generator- , sourceIcon :: Maybe URI- , sourceId :: Maybe URI- , sourceLinks :: [Link]- , sourceLogo :: Maybe URI- , sourceRights :: Maybe TextContent- , sourceSubtitle :: Maybe TextContent- , sourceTitle :: Maybe TextContent- , sourceUpdated :: Maybe Date- , sourceOther :: [XML.Element]- } deriving (Show)+data Source =+ Source+ { sourceAuthors :: [Person]+ , sourceCategories :: [Category]+ , sourceGenerator :: Maybe Generator+ , sourceIcon :: Maybe URI+ , sourceId :: Maybe URI+ , sourceLinks :: [Link]+ , sourceLogo :: Maybe URI+ , sourceRights :: Maybe TextContent+ , sourceSubtitle :: Maybe TextContent+ , sourceTitle :: Maybe TextContent+ , sourceUpdated :: Maybe Date+ , sourceOther :: [XML.Element]+ }+ deriving (Show) -data Person = Person- { personName :: Text- , personURI :: Maybe URI- , personEmail :: Maybe Text- , personOther :: [XML.Element]- } deriving (Show)+data Person =+ Person+ { personName :: Text+ , personURI :: Maybe URI+ , personEmail :: Maybe Text+ , personOther :: [XML.Element]+ }+ deriving (Show) -data InReplyTo = InReplyTo- { replyToRef :: URI- , replyToHRef :: Maybe URI- , replyToType :: Maybe MediaType- , replyToSource :: Maybe URI- , replyToOther :: [Attr]- , replyToContent :: [Node]- } deriving (Show)+data InReplyTo =+ InReplyTo+ { replyToRef :: URI+ , replyToHRef :: Maybe URI+ , replyToType :: Maybe MediaType+ , replyToSource :: Maybe URI+ , replyToOther :: [Attr]+ , replyToContent :: [Node]+ }+ deriving (Show) -data InReplyTotal = InReplyTotal- { replyToTotal :: Integer -- non-negative :)- , replyToTotalOther :: [Attr]- } deriving (Show)+data InReplyTotal =+ InReplyTotal+ { replyToTotal :: Integer -- non-negative :)+ , replyToTotalOther :: [Attr]+ }+ deriving (Show) -- *Smart Constructors newCategory ::
src/Text/Atom/Feed/Export.hs view
@@ -57,10 +57,10 @@ import Prelude.Compat import Data.Text (Text, pack)-import Data.XML.Types as XML-import Text.Atom.Feed import qualified Data.Text.Lazy as TL import qualified Data.Text.Util as U+import Data.XML.Types as XML+import Text.Atom.Feed atom_prefix :: Maybe Text atom_prefix = Nothing -- Just "atom"@@ -107,7 +107,8 @@ atomName nc = Name {nameLocalName = nc, nameNamespace = Just atomNS, namePrefix = atom_prefix} atomAttr :: Text -> Text -> Attr-atomAttr x y = (atomName x, [ContentText y])+atomAttr x y =+ (Name {nameLocalName = x, nameNamespace = Nothing, namePrefix = atom_prefix}, [ContentText y]) atomNode :: Text -> [Node] -> XML.Element atomNode x = blank_element (atomName x)
src/Text/Atom/Feed/Import.hs view
@@ -71,15 +71,17 @@ pQLeaf x es = (T.concat . elementText) `fmap` pQNode x es pAttr :: Text -> XML.Element -> Maybe Text-pAttr x e = (`attributeText` e) =<< fst <$> find sameAttr (elementAttributes e)- where- ax = atomName x- sameAttr (k, _) = k == ax || (isNothing (nameNamespace k) && nameLocalName k == x)+pAttr x e = (`attributeText` e) =<< find (sameAtomAttr x) (map fst $ elementAttributes e) pAttrs :: Text -> XML.Element -> [Text] pAttrs x e = [t | ContentText t <- cnts] where- cnts = concat [v | (k, v) <- elementAttributes e, k == atomName x]+ cnts = concat [v | (k, v) <- elementAttributes e, sameAtomAttr x k]++sameAtomAttr :: Text -> Name -> Bool+sameAtomAttr x k = k == ax || (isNothing (nameNamespace k) && nameLocalName k == x)+ where+ ax = atomName x pQAttr :: Name -> XML.Element -> Maybe Text pQAttr = attributeText
src/Text/Atom/Feed/Validate.hs view
@@ -53,8 +53,7 @@ import Data.Maybe data VTree a- = VNode [a]- [VTree a]+ = VNode [a] [VTree a] | VLeaf [a] deriving (Eq, Show) @@ -149,8 +148,7 @@ case pNodes "link" (elementChildren e) of xs -> case map fst $- filter (\(_, n) -> n == "alternate") $- mapMaybe (\ex -> (ex,) <$> pAttr "rel" ex) xs of+ filter (\(_, n) -> n == "alternate") $ mapMaybe (\ex -> (ex, ) <$> pAttr "rel" ex) xs of xs1 -> let jmb (Just x) (Just y) = Just (x, y) jmb _ _ = Nothing
src/Text/Atom/Pub.hs view
@@ -26,32 +26,34 @@ import Data.XML.Types as XML import Text.Atom.Feed (Category, TextContent, URI) -data Service = Service- { serviceWorkspaces :: [Workspace]- , serviceOther :: [XML.Element]- }+data Service =+ Service+ { serviceWorkspaces :: [Workspace]+ , serviceOther :: [XML.Element]+ } -data Workspace = Workspace- { workspaceTitle :: TextContent- , workspaceCols :: [Collection]- , workspaceOther :: [XML.Element]- }+data Workspace =+ Workspace+ { workspaceTitle :: TextContent+ , workspaceCols :: [Collection]+ , workspaceOther :: [XML.Element]+ } -data Collection = Collection- { collectionURI :: URI- , collectionTitle :: TextContent- , collectionAccept :: [Accept]- , collectionCats :: [Categories]- , collectionOther :: [XML.Element]- }+data Collection =+ Collection+ { collectionURI :: URI+ , collectionTitle :: TextContent+ , collectionAccept :: [Accept]+ , collectionCats :: [Categories]+ , collectionOther :: [XML.Element]+ } data Categories = CategoriesExternal URI- | Categories (Maybe Bool)- (Maybe URI)- [Category]+ | Categories (Maybe Bool) (Maybe URI) [Category] deriving (Show) -newtype Accept = Accept- { acceptType :: Text- }+newtype Accept =+ Accept+ { acceptType :: Text+ }
src/Text/DublinCore/Types.hs view
@@ -24,10 +24,12 @@ import Data.Text -- | A DCItem pairs a specific element with its (string) value.-data DCItem = DCItem- { dcElt :: DCInfo- , dcText :: Text- } deriving (Eq, Show)+data DCItem =+ DCItem+ { dcElt :: DCInfo+ , dcText :: Text+ }+ deriving (Eq, Show) -- | The Dublin Core Metadata Element Set, all 15 of them (plus an extension constructor.) data DCInfo
src/Text/Feed/Export.hs view
@@ -14,19 +14,21 @@ module Text.Feed.Export ( Text.Feed.Export.xmlFeed -- :: Feed -> XML.Element , Text.Feed.Export.textFeed -- :: Feed -> TL.Text+ , Text.Feed.Export.textFeedWith ) where import Prelude.Compat import Text.Feed.Types +import qualified Data.Text.Util as U import Text.Atom.Feed.Export as Atom import Text.RSS.Export as RSS import Text.RSS1.Export as RSS1-import qualified Data.Text.Util as U -import Data.XML.Types as XML import qualified Data.Text.Lazy as TL+import Data.XML.Types as XML+import Text.XML (RenderSettings) -- | 'xmlFeed f' serializes a @Feed@ document into a conforming -- XML toplevel element.@@ -40,3 +42,6 @@ textFeed :: Feed -> Maybe TL.Text textFeed = U.renderFeed Text.Feed.Export.xmlFeed++textFeedWith :: RenderSettings -> Feed -> Maybe TL.Text+textFeedWith settings = U.renderFeedWith settings Text.Feed.Export.xmlFeed
src/Text/Feed/Import.hs view
@@ -68,12 +68,8 @@ -- | 'parseFeedFromFile fp' reads in the contents of the file at @fp@; -- the assumed encoding is UTF-8.-parseFeedFromFile :: FilePath -> IO Feed-parseFeedFromFile fp = do- ls <- utf8readFile fp- case parseFeedString ls of- Nothing -> fail ("parseFeedFromFile: not a well-formed XML content in: " ++ fp)- Just f -> return f+parseFeedFromFile :: FilePath -> IO (Maybe Feed)+parseFeedFromFile fp = parseFeedString <$> utf8readFile fp -- | 'parseFeedWithParser tries to parse the string @str@ -- as one of the feed formats. First as Atom, then RSS2 before
src/Text/Feed/Query.hs view
@@ -42,6 +42,7 @@ , getItemCategories -- :: ItemGetter [Text] , getItemRights -- :: ItemGetter Text , getItemSummary -- :: ItemGetter Text+ , getItemContent -- :: ItemGetter Text , getItemDescription -- :: ItemGetter Text (synonym of previous.) ) where @@ -430,6 +431,14 @@ where isRights dc = dcElt dc == DC_Rights +getItemContent :: ItemGetter Text+getItemContent it =+ case it of+ Feed.AtomItem e -> atomContentToStr <$> Atom.entryContent e+ Feed.RSSItem e -> RSS.rssItemContent e+ Feed.RSS1Item _ -> Nothing+ Feed.XMLItem i -> strContent <$> findElement (atomName "content") i+ getItemSummary :: ItemGetter Text getItemSummary = getItemDescription @@ -446,6 +455,15 @@ toStr Nothing = "" toStr (Just (Left x)) = x toStr (Just (Right x)) = x++atomContentToStr :: EntryContent -> Text+atomContentToStr entry =+ case entry of+ HTMLContent e -> e+ XHTMLContent e -> T.unlines $ elementText e+ MixedContent text _ -> fromMaybe "" text+ ExternalContent _ b -> b+ TextContent text -> text contentToStr :: TextContent -> Text contentToStr x =
src/Text/RSS/Export.hs view
@@ -33,10 +33,10 @@ import Prelude.Compat +import qualified Data.Text.Util as U import Data.XML.Compat import Data.XML.Types as XML import Text.RSS.Syntax-import qualified Data.Text.Util as U import Data.Text (Text, pack) import qualified Data.Text.Lazy as TL
src/Text/RSS/Import.hs view
@@ -221,6 +221,7 @@ , rssItemAuthor = pLeaf "author" es `mplus` pQLeaf (dcName "creator") es , rssItemCategories = pMany "category" elementToCategory es , rssItemComments = pLeaf "comments" es+ , rssItemContent = pLeaf "content" es , rssItemEnclosure = pNode "enclosure" es >>= elementToEnclosure , rssItemGuid = pNode "guid" es >>= elementToGuid , rssItemPubDate = pLeaf "pubDate" es `mplus` pQLeaf (dcName "date") es
src/Text/RSS/Syntax.hs view
@@ -48,109 +48,130 @@ -- * Core Types -- ^The Radio Userland version of RSS documents\/feeds. -- (versions 0.9x, 2.x)-data RSS = RSS- { rssVersion :: Text- , rssAttrs :: [Attr]- , rssChannel :: RSSChannel- , rssOther :: [XML.Element]- } deriving (Show)+data RSS =+ RSS+ { rssVersion :: Text+ , rssAttrs :: [Attr]+ , rssChannel :: RSSChannel+ , rssOther :: [XML.Element]+ }+ deriving (Show) type URLString = Text -- | RFC 822 conforming. type DateString = Text -data RSSChannel = RSSChannel- { rssTitle :: Text- , rssLink :: URLString- , rssDescription :: Text- , rssItems :: [RSSItem]- , rssLanguage :: Maybe Text- , rssCopyright :: Maybe Text- , rssEditor :: Maybe Text- , rssWebMaster :: Maybe Text- , rssPubDate :: Maybe DateString -- ^ rfc 822 conforming.- , rssLastUpdate :: Maybe DateString -- ^ rfc 822 conforming.- , rssCategories :: [RSSCategory]- , rssGenerator :: Maybe Text- , rssDocs :: Maybe URLString- , rssCloud :: Maybe RSSCloud- , rssTTL :: Maybe Integer- , rssImage :: Maybe RSSImage- , rssRating :: Maybe Text- , rssTextInput :: Maybe RSSTextInput- , rssSkipHours :: Maybe [Integer]- , rssSkipDays :: Maybe [Text]- , rssChannelOther :: [XML.Element]- } deriving (Show)+data RSSChannel =+ RSSChannel+ { rssTitle :: Text+ , rssLink :: URLString+ , rssDescription :: Text+ , rssItems :: [RSSItem]+ , rssLanguage :: Maybe Text+ , rssCopyright :: Maybe Text+ , rssEditor :: Maybe Text+ , rssWebMaster :: Maybe Text+ , rssPubDate :: Maybe DateString -- ^ rfc 822 conforming.+ , rssLastUpdate :: Maybe DateString -- ^ rfc 822 conforming.+ , rssCategories :: [RSSCategory]+ , rssGenerator :: Maybe Text+ , rssDocs :: Maybe URLString+ , rssCloud :: Maybe RSSCloud+ , rssTTL :: Maybe Integer+ , rssImage :: Maybe RSSImage+ , rssRating :: Maybe Text+ , rssTextInput :: Maybe RSSTextInput+ , rssSkipHours :: Maybe [Integer]+ , rssSkipDays :: Maybe [Text]+ , rssChannelOther :: [XML.Element]+ }+ deriving (Show) -data RSSItem = RSSItem- { rssItemTitle :: Maybe Text- , rssItemLink :: Maybe URLString- , rssItemDescription :: Maybe Text -- ^if not present, the title is. (per spec, at least.)- , rssItemAuthor :: Maybe Text- , rssItemCategories :: [RSSCategory]- , rssItemComments :: Maybe URLString- , rssItemEnclosure :: Maybe RSSEnclosure- , rssItemGuid :: Maybe RSSGuid- , rssItemPubDate :: Maybe DateString- , rssItemSource :: Maybe RSSSource- , rssItemAttrs :: [Attr]- , rssItemOther :: [XML.Element]- } deriving (Show)+data RSSItem =+ RSSItem+ { rssItemTitle :: Maybe Text+ , rssItemLink :: Maybe URLString+ , rssItemDescription :: Maybe Text -- ^if not present, the title is. (per spec, at least.)+ , rssItemAuthor :: Maybe Text+ , rssItemCategories :: [RSSCategory]+ , rssItemComments :: Maybe URLString+ , rssItemContent :: Maybe Text+ , rssItemEnclosure :: Maybe RSSEnclosure+ , rssItemGuid :: Maybe RSSGuid+ , rssItemPubDate :: Maybe DateString+ , rssItemSource :: Maybe RSSSource+ , rssItemAttrs :: [Attr]+ , rssItemOther :: [XML.Element]+ }+ deriving (Show) -data RSSSource = RSSSource- { rssSourceURL :: URLString- , rssSourceAttrs :: [Attr]- , rssSourceTitle :: Text- } deriving (Show)+data RSSSource =+ RSSSource+ { rssSourceURL :: URLString+ , rssSourceAttrs :: [Attr]+ , rssSourceTitle :: Text+ }+ deriving (Show) -data RSSEnclosure = RSSEnclosure- { rssEnclosureURL :: URLString- , rssEnclosureLength :: Maybe Integer- , rssEnclosureType :: Text- , rssEnclosureAttrs :: [Attr]- } deriving (Show)+data RSSEnclosure =+ RSSEnclosure+ { rssEnclosureURL :: URLString+ , rssEnclosureLength :: Maybe Integer+ , rssEnclosureType :: Text+ , rssEnclosureAttrs :: [Attr]+ }+ deriving (Show) -data RSSCategory = RSSCategory- { rssCategoryDomain :: Maybe Text- , rssCategoryAttrs :: [Attr]- , rssCategoryValue :: Text- } deriving (Show)+data RSSCategory =+ RSSCategory+ { rssCategoryDomain :: Maybe Text+ , rssCategoryAttrs :: [Attr]+ , rssCategoryValue :: Text+ }+ deriving (Show) -data RSSGuid = RSSGuid- { rssGuidPermanentURL :: Maybe Bool- , rssGuidAttrs :: [Attr]- , rssGuidValue :: Text- } deriving (Show)+data RSSGuid =+ RSSGuid+ { rssGuidPermanentURL :: Maybe Bool+ , rssGuidAttrs :: [Attr]+ , rssGuidValue :: Text+ }+ deriving (Show) -data RSSImage = RSSImage- { rssImageURL :: URLString -- the URL to the image resource.- , rssImageTitle :: Text- , rssImageLink :: URLString -- URL that the image resource should be an href to.- , rssImageWidth :: Maybe Integer- , rssImageHeight :: Maybe Integer- , rssImageDesc :: Maybe Text- , rssImageOther :: [XML.Element]- } deriving (Show)+data RSSImage =+ RSSImage+ { rssImageURL :: URLString -- the URL to the image resource.+ , rssImageTitle :: Text+ , rssImageLink :: URLString -- URL that the image resource should be an href to.+ , rssImageWidth :: Maybe Integer+ , rssImageHeight :: Maybe Integer+ , rssImageDesc :: Maybe Text+ , rssImageOther :: [XML.Element]+ }+ deriving (Show) -data RSSCloud = RSSCloud- { rssCloudDomain :: Maybe Text- , rssCloudPort :: Maybe Text -- on purpose (i.e., not an int)- , rssCloudPath :: Maybe Text- , rssCloudRegisterProcedure :: Maybe Text- , rssCloudProtocol :: Maybe Text- , rssCloudAttrs :: [Attr]- } deriving (Show)+data RSSCloud =+ RSSCloud+ { rssCloudDomain :: Maybe Text+ , rssCloudPort :: Maybe Text -- on purpose (i.e., not an int)+ , rssCloudPath :: Maybe Text+ , rssCloudRegisterProcedure :: Maybe Text+ , rssCloudProtocol :: Maybe Text+ , rssCloudAttrs :: [Attr]+ }+ deriving (Show) -data RSSTextInput = RSSTextInput- { rssTextInputTitle :: Text- , rssTextInputDesc :: Text- , rssTextInputName :: Text- , rssTextInputLink :: URLString- , rssTextInputAttrs :: [Attr]- , rssTextInputOther :: [XML.Element]- } deriving (Show)+data RSSTextInput =+ RSSTextInput+ { rssTextInputTitle :: Text+ , rssTextInputDesc :: Text+ , rssTextInputName :: Text+ , rssTextInputLink :: URLString+ , rssTextInputAttrs :: [Attr]+ , rssTextInputOther :: [XML.Element]+ }+ deriving (Show) -- * Default Constructors: nullRSS ::@@ -200,6 +221,7 @@ , rssItemAuthor = Nothing , rssItemCategories = [] , rssItemComments = Nothing+ , rssItemContent = Nothing , rssItemEnclosure = Nothing , rssItemGuid = Nothing , rssItemPubDate = Nothing
src/Text/RSS1/Export.hs view
@@ -17,10 +17,10 @@ import Prelude.Compat +import qualified Data.Text.Util as U import Text.DublinCore.Types import Text.RSS1.Syntax import Text.RSS1.Utils-import qualified Data.Text.Util as U import Data.List.Compat import Data.Text (Text)
src/Text/RSS1/Syntax.hs view
@@ -47,79 +47,91 @@ type TextString = Text -data Feed = Feed- { feedVersion :: Text- , feedChannel :: Channel- , feedImage :: Maybe Image- , feedItems :: [Item]- , feedTextInput :: Maybe TextInputInfo- , feedTopics :: [TaxonomyTopic]- , feedOther :: [XML.Element]- , feedAttrs :: [Attr]- } deriving (Show)+data Feed =+ Feed+ { feedVersion :: Text+ , feedChannel :: Channel+ , feedImage :: Maybe Image+ , feedItems :: [Item]+ , feedTextInput :: Maybe TextInputInfo+ , feedTopics :: [TaxonomyTopic]+ , feedOther :: [XML.Element]+ , feedAttrs :: [Attr]+ }+ deriving (Show) -data Channel = Channel- { channelURI :: URIString- , channelTitle :: TitleString- , channelLink :: URIString- , channelDesc :: TextString+data Channel =+ Channel+ { channelURI :: URIString+ , channelTitle :: TitleString+ , channelLink :: URIString+ , channelDesc :: TextString -- these are indirect RDF associations to elements declared -- outside the channel element in the RDF \/ feed document.- , channelImageURI :: Maybe URIString- , channelItemURIs :: [URIString]- , channelTextInputURI :: Maybe URIString- , channelDC :: [DCItem]- , channelUpdatePeriod :: Maybe UpdatePeriod- , channelUpdateFreq :: Maybe Integer- , channelUpdateBase :: Maybe TimeString -- format is yyyy-mm-ddThh:mm- , channelContent :: [ContentInfo]- , channelTopics :: [URIString]- , channelOther :: [XML.Element]- , channelAttrs :: [Attr]- } deriving (Show)+ , channelImageURI :: Maybe URIString+ , channelItemURIs :: [URIString]+ , channelTextInputURI :: Maybe URIString+ , channelDC :: [DCItem]+ , channelUpdatePeriod :: Maybe UpdatePeriod+ , channelUpdateFreq :: Maybe Integer+ , channelUpdateBase :: Maybe TimeString -- format is yyyy-mm-ddThh:mm+ , channelContent :: [ContentInfo]+ , channelTopics :: [URIString]+ , channelOther :: [XML.Element]+ , channelAttrs :: [Attr]+ }+ deriving (Show) -data Image = Image- { imageURI :: URIString -- the image resource, most likely.- , imageTitle :: TextString -- the "alt"ernative text.- , imageURL :: URIString- , imageLink :: URIString -- the href of the rendered img resource.- , imageDC :: [DCItem]- , imageOther :: [XML.Element]- , imageAttrs :: [Attr]- } deriving (Show)+data Image =+ Image+ { imageURI :: URIString -- the image resource, most likely.+ , imageTitle :: TextString -- the "alt"ernative text.+ , imageURL :: URIString+ , imageLink :: URIString -- the href of the rendered img resource.+ , imageDC :: [DCItem]+ , imageOther :: [XML.Element]+ , imageAttrs :: [Attr]+ }+ deriving (Show) -data Item = Item- { itemURI :: URIString- , itemTitle :: TextString- , itemLink :: URIString- , itemDesc :: Maybe TextString- , itemDC :: [DCItem]- , itemTopics :: [URIString]- , itemContent :: [ContentInfo]- , itemOther :: [XML.Element]- , itemAttrs :: [Attr]- } deriving (Show)+data Item =+ Item+ { itemURI :: URIString+ , itemTitle :: TextString+ , itemLink :: URIString+ , itemDesc :: Maybe TextString+ , itemDC :: [DCItem]+ , itemTopics :: [URIString]+ , itemContent :: [ContentInfo]+ , itemOther :: [XML.Element]+ , itemAttrs :: [Attr]+ }+ deriving (Show) -data TextInputInfo = TextInputInfo- { textInputURI :: URIString- , textInputTitle :: TextString- , textInputDesc :: TextString- , textInputName :: TextString- , textInputLink :: URIString- , textInputDC :: [DCItem]- , textInputOther :: [XML.Element]- , textInputAttrs :: [Attr]- } deriving (Show)+data TextInputInfo =+ TextInputInfo+ { textInputURI :: URIString+ , textInputTitle :: TextString+ , textInputDesc :: TextString+ , textInputName :: TextString+ , textInputLink :: URIString+ , textInputDC :: [DCItem]+ , textInputOther :: [XML.Element]+ , textInputAttrs :: [Attr]+ }+ deriving (Show) -data TaxonomyTopic = TaxonomyTopic- { taxonomyURI :: URIString- , taxonomyLink :: URIString- , taxonomyTitle :: Maybe Text- , taxonomyDesc :: Maybe Text- , taxonomyTopics :: [URIString]- , taxonomyDC :: [DCItem]- , taxonomyOther :: [XML.Element]- } deriving (Show)+data TaxonomyTopic =+ TaxonomyTopic+ { taxonomyURI :: URIString+ , taxonomyLink :: URIString+ , taxonomyTitle :: Maybe Text+ , taxonomyDesc :: Maybe Text+ , taxonomyTopics :: [URIString]+ , taxonomyDC :: [DCItem]+ , taxonomyOther :: [XML.Element]+ }+ deriving (Show) data UpdatePeriod = Update_Hourly@@ -129,12 +141,14 @@ | Update_Yearly deriving (Eq, Show) -data ContentInfo = ContentInfo- { contentURI :: Maybe URIString- , contentFormat :: Maybe URIString- , contentEncoding :: Maybe URIString- , contentValue :: Maybe Text -- should be: RDFValue- } deriving (Eq, Show)+data ContentInfo =+ ContentInfo+ { contentURI :: Maybe URIString+ , contentFormat :: Maybe URIString+ , contentEncoding :: Maybe URIString+ , contentValue :: Maybe Text -- should be: RDFValue+ }+ deriving (Eq, Show) --default constructors: nullFeed :: URIString -> TitleString -> Feed
tests/Example/CreateAtom.hs view
@@ -15,11 +15,12 @@ atomFeed :: Maybe Text atomFeed = renderFeed examplePosts -data Post = Post- { _postedOn :: Text- , _url :: Text- , _content :: Text- }+data Post =+ Post+ { _postedOn :: Text+ , _url :: Text+ , _content :: Text+ } examplePosts :: [Post] examplePosts =
+ tests/ImportExport.hs view
@@ -0,0 +1,44 @@+module ImportExport+ ( importExportTests+ ) where++import Prelude.Compat++import Data.Generics (everywhere, mkT)+import Data.Text (strip)+import qualified Data.Text.Lazy.IO as T+import qualified Data.XML.Types as XML+import Test.Framework (Test, testGroup)+import Test.Framework.Providers.HUnit (testCase)+import Test.HUnit ((@=?))+import qualified Text.XML as C++import Text.Feed.Export (xmlFeed)+import Text.Feed.Import (readAtom)+import Text.Feed.Types (Feed)+import Text.RSS.Utils (elementToDoc)++import Paths_feed++importExportTests :: Test+importExportTests =+ testGroup "ImportExport" [testImportExport readAtom "tests/files/import_export_atom.xml"]++testImportExport :: (XML.Element -> Maybe Feed) -> FilePath -> Test+testImportExport readFeed fileName =+ testCase fileName $ do+ input <- T.readFile =<< getDataFileName fileName+ let inputXml = C.parseText_ C.def input+ let Just feed = readFeed $ C.toXMLElement $ C.documentRoot inputXml+ let Just outputXml = elementToDoc $ xmlFeed feed+ let output = C.renderText C.def outputXml+ let input' = C.renderText C.def $ stripXmlWhitespace inputXml+ input' @=? output++stripXmlWhitespace :: C.Document -> C.Document+stripXmlWhitespace = everywhere (mkT stripWhitespaceNodes)+ where+ stripWhitespaceNodes e = e {C.elementNodes = filter (not . isWhite) (C.elementNodes e)}+ isWhite (C.NodeContent t) = strip t == ""+ isWhite (C.NodeComment _) = True+ isWhite _ = False
tests/Main.hs view
@@ -5,10 +5,14 @@ import Prelude.Compat import Example (exampleTests)+import ImportExport (importExportTests) import Test.Framework (defaultMain) import Text.Atom.Tests (atomTests)+import Text.Atom.Validate.Tests (atomValidateTests) import Text.Feed.Util.Tests (feedUtilTests) import Text.RSS.Tests (rssTests) main :: IO ()-main = defaultMain [rssTests, atomTests, feedUtilTests, exampleTests]+main =+ defaultMain+ [rssTests, atomTests, atomValidateTests, feedUtilTests, exampleTests, importExportTests]
tests/Text/Atom/Tests.hs view
@@ -31,7 +31,7 @@ testAtom :: Assertion testAtom = do contents <- parseFeedFromFile =<< getDataFileName "tests/files/atom.xml"- let res = fmap (renderText def) . elementToDoc . xmlFeed $ contents+ let res = fmap (renderText def) . (>>= elementToDoc) . fmap xmlFeed $ contents assertBool "Atom Parsing" $ isJust res testAtomAlternate :: Test
+ tests/Text/Atom/Validate/Tests.hs view
@@ -0,0 +1,34 @@+module Text.Atom.Validate.Tests+ ( atomValidateTests+ ) where++import Prelude.Compat++import Data.Text (Text)+import Data.Text.Lazy (fromStrict)++import Data.XML.Types++import Test.Framework (Test, testGroup)+import Test.Framework.Providers.HUnit (testCase)+import Test.HUnit (Assertion, assertEqual)++import Text.Atom.Feed.Validate++import qualified Text.XML as C++atomValidateTests :: Test+atomValidateTests = testGroup "Text.Atom.Validate" [testAtomValidate]++sampleEntryText :: Text+sampleEntryText =+ "<?xml version=\"1.0\" encoding=\"UTF-8\"?><entry xmlns=\"http://www.w3.org/2005/Atom\"><id>http://example.com</id><title type=\"text\">example</title><updated>2000-01-01T00:00:00Z</updated><author><name>Nobody</name></author><content type=\"xhtml\"><div xmlns=\"http://www.w3.org/1999/xhtml\">This is <b>XHTML</b> content.</div></content></entry>"++testAtomValidate :: Test+testAtomValidate = testCase "simple entry is valid" testValid+ where+ testValid :: Assertion+ testValid = do+ let document = C.toXMLDocument $ C.parseText_ C.def $ fromStrict sampleEntryText+ let entry = documentRoot document+ assertEqual "" [] $ flattenT $ validateEntry entry
tests/Text/RSS/Tests.hs view
@@ -30,5 +30,5 @@ testRss20 :: Assertion testRss20 = do contents <- parseFeedFromFile =<< getDataFileName "tests/files/rss20.xml"- let res = fmap (renderText def) . elementToDoc . xmlFeed $ contents+ let res = fmap (renderText def) . (>>= elementToDoc) . fmap xmlFeed $ contents assertBool "RSS 2.0 Parsing" $ isJust res
+ tests/doctest-driver.hs view
@@ -0,0 +1,1 @@+{-# OPTIONS_GHC -F -pgmF doctest-driver-gen -optF README.lhs -optF -pgmL -optF markdown-unlit -optF -XOverloadedStrings -optF -XNoImplicitPrelude -optF -package -optF text -optF -package -optF xml-types #-}
+ tests/files/import_export_atom.xml view
@@ -0,0 +1,35 @@+<?xml version="1.0" encoding="UTF-8"?>+<feed xmlns="http://www.w3.org/2005/Atom">+ <title type="text">Example Feed</title>+ <id>urn:uuid:60a76c80-d399-11d9-b91C-0003939e0af6</id>+ <updated>2003-12-13T18:30:02Z</updated>+ <link href="http://example.org/feed/" rel="self"/>+ <link href="http://example.org/"/>+ <subtitle type="text">A subtitle.</subtitle>+ <entry>+ <id>urn:uuid:1225c695-cfb8-4ebb-aaaa-80da344efa6a</id>+ <title type="text">Atom-Powered Robots Run Amok</title>+ <updated>2003-12-13T18:30:00Z</updated>+ <author>+ <name>John Doe</name>+ <email>johndoe@example.com</email>+ </author>+ <content type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>This is the entry content.</p></div></content>+ <link href="http://example.org/2003/12/13/atom03"/>+ <link href="http://example.org/2003/12/13/atom03.html" rel="alternate" type="text/html"/>+ <link href="http://example.org/2003/12/13/atom03/edit" rel="edit"/>+ <summary type="html"><div><p>This is the entry content.</p></div></summary>+ </entry>+ <entry>+ <id>urn:uuid:f5ae72c9-b02e-42bc-957e-bbfe60b2c4a9</id>+ <title type="text">Robot-Powered Atoms Run Amok</title>+ <updated>2003-12-13T19:00:00Z</updated>+ <author>+ <name>John Doe</name>+ <email>johndoe@example.com</email>+ </author>+ <content type="html"><div><p>This is the entry content.</p></div></content>+ <link href="http://example.org/2003/12/13/atom04"/>+ <summary type="xhtml"><div xmlns="http://www.w3.org/1999/xhtml"><p>This is the entry content.</p></div></summary>+ </entry>+</feed>