epub-metadata 1.0.2 → 2.0.0
raw patch · 29 files changed
+1081/−555 lines, 29 filesdep +containersdep ~hxtsetup-changedPVP ok
version bump matches the API change (PVP)
Dependencies added: containers
Dependency ranges changed: hxt
API changes (from Hackage documentation)
- Codec.Epub.Opf.Metadata: EMCreator :: (Maybe String) -> (Maybe String) -> String -> EMCreator
- Codec.Epub.Opf.Metadata: EMDate :: (Maybe String) -> String -> EMDate
- Codec.Epub.Opf.Metadata: EMId :: String -> (Maybe String) -> String -> EMId
- Codec.Epub.Opf.Metadata: EMTitle :: (Maybe String) -> String -> EMTitle
- Codec.Epub.Opf.Metadata: EpubMeta :: [EMTitle] -> [EMCreator] -> [EMCreator] -> [String] -> Maybe String -> Maybe String -> [EMDate] -> Maybe String -> Maybe String -> [EMId] -> Maybe String -> [String] -> Maybe String -> Maybe String -> Maybe String -> EpubMeta
- Codec.Epub.Opf.Metadata: OPFPackage :: String -> String -> EpubMeta -> OPFPackage
- Codec.Epub.Opf.Metadata: data EMCreator
- Codec.Epub.Opf.Metadata: data EMDate
- Codec.Epub.Opf.Metadata: data EMId
- Codec.Epub.Opf.Metadata: data EMTitle
- Codec.Epub.Opf.Metadata: data EpubMeta
- Codec.Epub.Opf.Metadata: data OPFPackage
- Codec.Epub.Opf.Metadata: emContributors :: EpubMeta -> [EMCreator]
- Codec.Epub.Opf.Metadata: emCoverage :: EpubMeta -> Maybe String
- Codec.Epub.Opf.Metadata: emCreators :: EpubMeta -> [EMCreator]
- Codec.Epub.Opf.Metadata: emDates :: EpubMeta -> [EMDate]
- Codec.Epub.Opf.Metadata: emDescription :: EpubMeta -> Maybe String
- Codec.Epub.Opf.Metadata: emFormat :: EpubMeta -> Maybe String
- Codec.Epub.Opf.Metadata: emIds :: EpubMeta -> [EMId]
- Codec.Epub.Opf.Metadata: emLangs :: EpubMeta -> [String]
- Codec.Epub.Opf.Metadata: emPublisher :: EpubMeta -> Maybe String
- Codec.Epub.Opf.Metadata: emRelation :: EpubMeta -> Maybe String
- Codec.Epub.Opf.Metadata: emRights :: EpubMeta -> Maybe String
- Codec.Epub.Opf.Metadata: emSource :: EpubMeta -> Maybe String
- Codec.Epub.Opf.Metadata: emSubjects :: EpubMeta -> [String]
- Codec.Epub.Opf.Metadata: emTitles :: EpubMeta -> [EMTitle]
- Codec.Epub.Opf.Metadata: emType :: EpubMeta -> Maybe String
- Codec.Epub.Opf.Metadata: emptyEpubMeta :: EpubMeta
- Codec.Epub.Opf.Metadata: instance Eq EMCreator
- Codec.Epub.Opf.Metadata: instance Eq EMDate
- Codec.Epub.Opf.Metadata: instance Eq EMId
- Codec.Epub.Opf.Metadata: instance Eq EMTitle
- Codec.Epub.Opf.Metadata: instance Eq EpubMeta
- Codec.Epub.Opf.Metadata: instance Eq OPFPackage
- Codec.Epub.Opf.Metadata: instance Show EMCreator
- Codec.Epub.Opf.Metadata: instance Show EMDate
- Codec.Epub.Opf.Metadata: instance Show EMId
- Codec.Epub.Opf.Metadata: instance Show EMTitle
- Codec.Epub.Opf.Metadata: instance Show EpubMeta
- Codec.Epub.Opf.Metadata: instance Show OPFPackage
- Codec.Epub.Opf.Metadata: opMeta :: OPFPackage -> EpubMeta
- Codec.Epub.Opf.Metadata: opUniqueId :: OPFPackage -> String
- Codec.Epub.Opf.Metadata: opVersion :: OPFPackage -> String
- Codec.Epub.Opf.Metadata.Format: opfToString :: OPFPackage -> String
- Codec.Epub.Opf.Metadata.Parse: parseEpubOpf :: (MonadIO m, MonadError String m) => FilePath -> m OPFPackage
- Codec.Epub.Opf.Metadata.Parse: parseXmlToOpf :: (MonadIO m) => String -> m [OPFPackage]
+ Codec.Epub.Opf.Common: type MFItemId = String
+ Codec.Epub.Opf.Format.Guide: tellGuide :: MonadWriter (Seq Char) m => [GuideRef] -> m ()
+ Codec.Epub.Opf.Format.Guide: tellGuideRef :: MonadWriter (Seq Char) m => GuideRef -> m ()
+ Codec.Epub.Opf.Format.Manifest: tellManifest :: MonadWriter (Seq Char) m => [ManifestItem] -> m ()
+ Codec.Epub.Opf.Format.Manifest: tellManifestItem :: MonadWriter (Seq Char) m => ManifestItem -> m ()
+ Codec.Epub.Opf.Format.Metadata: tellContributor :: MonadWriter (Seq Char) m => MetaCreator -> m ()
+ Codec.Epub.Opf.Format.Metadata: tellCoverage :: MonadWriter (Seq Char) m => Maybe String -> m ()
+ Codec.Epub.Opf.Format.Metadata: tellCreator :: MonadWriter (Seq Char) m => MetaCreator -> m ()
+ Codec.Epub.Opf.Format.Metadata: tellDate :: MonadWriter (Seq Char) m => MetaDate -> m ()
+ Codec.Epub.Opf.Format.Metadata: tellDescription :: MonadWriter (Seq Char) m => Maybe String -> m ()
+ Codec.Epub.Opf.Format.Metadata: tellFormat :: MonadWriter (Seq Char) m => Maybe String -> m ()
+ Codec.Epub.Opf.Format.Metadata: tellId :: MonadWriter (Seq Char) m => MetaId -> m ()
+ Codec.Epub.Opf.Format.Metadata: tellLang :: MonadWriter (Seq Char) m => String -> m ()
+ Codec.Epub.Opf.Format.Metadata: tellMetadata :: MonadWriter (Seq Char) m => Metadata -> m ()
+ Codec.Epub.Opf.Format.Metadata: tellPublisher :: MonadWriter (Seq Char) m => Maybe String -> m ()
+ Codec.Epub.Opf.Format.Metadata: tellRelation :: MonadWriter (Seq Char) m => Maybe String -> m ()
+ Codec.Epub.Opf.Format.Metadata: tellRights :: MonadWriter (Seq Char) m => Maybe String -> m ()
+ Codec.Epub.Opf.Format.Metadata: tellSource :: MonadWriter (Seq Char) m => Maybe String -> m ()
+ Codec.Epub.Opf.Format.Metadata: tellSubject :: MonadWriter (Seq Char) m => String -> m ()
+ Codec.Epub.Opf.Format.Metadata: tellTitle :: MonadWriter (Seq Char) m => MetaTitle -> m ()
+ Codec.Epub.Opf.Format.Metadata: tellType :: MonadWriter (Seq Char) m => Maybe String -> m ()
+ Codec.Epub.Opf.Format.Package: formatPackage :: Bool -> Package -> String
+ Codec.Epub.Opf.Format.Spine: tellSpine :: MonadWriter (Seq Char) m => Spine -> m ()
+ Codec.Epub.Opf.Format.Spine: tellSpineItemref :: MonadWriter (Seq Char) m => SpineItemref -> m ()
+ Codec.Epub.Opf.Format.Util: data Seq a :: * -> *
+ Codec.Epub.Opf.Format.Util: formatSubline :: String -> Maybe String -> String
+ Codec.Epub.Opf.Format.Util: tellSeq :: MonadWriter (Seq a) m => [a] -> m ()
+ Codec.Epub.Opf.Package: GuideRef :: String -> Maybe String -> String -> GuideRef
+ Codec.Epub.Opf.Package: ManifestItem :: MFItemId -> MFItemHref -> MFItemMediaType -> ManifestItem
+ Codec.Epub.Opf.Package: MetaCreator :: (Maybe String) -> (Maybe String) -> String -> MetaCreator
+ Codec.Epub.Opf.Package: MetaDate :: (Maybe String) -> String -> MetaDate
+ Codec.Epub.Opf.Package: MetaId :: String -> (Maybe String) -> String -> MetaId
+ Codec.Epub.Opf.Package: MetaTitle :: (Maybe String) -> String -> MetaTitle
+ Codec.Epub.Opf.Package: Metadata :: [MetaTitle] -> [MetaCreator] -> [MetaCreator] -> [String] -> Maybe String -> Maybe String -> [MetaDate] -> Maybe String -> Maybe String -> [MetaId] -> Maybe String -> [String] -> Maybe String -> Maybe String -> Maybe String -> Metadata
+ Codec.Epub.Opf.Package: Package :: String -> String -> Metadata -> [ManifestItem] -> Spine -> [GuideRef] -> Package
+ Codec.Epub.Opf.Package: Spine :: MFItemId -> [SpineItemref] -> Spine
+ Codec.Epub.Opf.Package: SpineItemref :: MFItemId -> Maybe Bool -> SpineItemref
+ Codec.Epub.Opf.Package: data GuideRef
+ Codec.Epub.Opf.Package: data ManifestItem
+ Codec.Epub.Opf.Package: data MetaCreator
+ Codec.Epub.Opf.Package: data MetaDate
+ Codec.Epub.Opf.Package: data MetaId
+ Codec.Epub.Opf.Package: data MetaTitle
+ Codec.Epub.Opf.Package: data Metadata
+ Codec.Epub.Opf.Package: data Package
+ Codec.Epub.Opf.Package: data Spine
+ Codec.Epub.Opf.Package: data SpineItemref
+ Codec.Epub.Opf.Package: emptyMetadata :: Metadata
+ Codec.Epub.Opf.Package: grHref :: GuideRef -> String
+ Codec.Epub.Opf.Package: grTitle :: GuideRef -> Maybe String
+ Codec.Epub.Opf.Package: grType :: GuideRef -> String
+ Codec.Epub.Opf.Package: instance Eq Package
+ Codec.Epub.Opf.Package: instance Show Package
+ Codec.Epub.Opf.Package: metaContributors :: Metadata -> [MetaCreator]
+ Codec.Epub.Opf.Package: metaCoverage :: Metadata -> Maybe String
+ Codec.Epub.Opf.Package: metaCreators :: Metadata -> [MetaCreator]
+ Codec.Epub.Opf.Package: metaDates :: Metadata -> [MetaDate]
+ Codec.Epub.Opf.Package: metaDescription :: Metadata -> Maybe String
+ Codec.Epub.Opf.Package: metaFormat :: Metadata -> Maybe String
+ Codec.Epub.Opf.Package: metaIds :: Metadata -> [MetaId]
+ Codec.Epub.Opf.Package: metaLangs :: Metadata -> [String]
+ Codec.Epub.Opf.Package: metaPublisher :: Metadata -> Maybe String
+ Codec.Epub.Opf.Package: metaRelation :: Metadata -> Maybe String
+ Codec.Epub.Opf.Package: metaRights :: Metadata -> Maybe String
+ Codec.Epub.Opf.Package: metaSource :: Metadata -> Maybe String
+ Codec.Epub.Opf.Package: metaSubjects :: Metadata -> [String]
+ Codec.Epub.Opf.Package: metaTitles :: Metadata -> [MetaTitle]
+ Codec.Epub.Opf.Package: metaType :: Metadata -> Maybe String
+ Codec.Epub.Opf.Package: mfiHref :: ManifestItem -> MFItemHref
+ Codec.Epub.Opf.Package: mfiId :: ManifestItem -> MFItemId
+ Codec.Epub.Opf.Package: mfiMediaType :: ManifestItem -> MFItemMediaType
+ Codec.Epub.Opf.Package: opGuide :: Package -> [GuideRef]
+ Codec.Epub.Opf.Package: opManifest :: Package -> [ManifestItem]
+ Codec.Epub.Opf.Package: opMeta :: Package -> Metadata
+ Codec.Epub.Opf.Package: opSpine :: Package -> Spine
+ Codec.Epub.Opf.Package: opUniqueId :: Package -> String
+ Codec.Epub.Opf.Package: opVersion :: Package -> String
+ Codec.Epub.Opf.Package: siIdRef :: SpineItemref -> MFItemId
+ Codec.Epub.Opf.Package: siLinear :: SpineItemref -> Maybe Bool
+ Codec.Epub.Opf.Package: spineItemrefs :: Spine -> [SpineItemref]
+ Codec.Epub.Opf.Package: spineToc :: Spine -> MFItemId
+ Codec.Epub.Opf.Package.Guide: GuideRef :: String -> Maybe String -> String -> GuideRef
+ Codec.Epub.Opf.Package.Guide: data GuideRef
+ Codec.Epub.Opf.Package.Guide: grHref :: GuideRef -> String
+ Codec.Epub.Opf.Package.Guide: grTitle :: GuideRef -> Maybe String
+ Codec.Epub.Opf.Package.Guide: grType :: GuideRef -> String
+ Codec.Epub.Opf.Package.Guide: instance Eq GuideRef
+ Codec.Epub.Opf.Package.Guide: instance Show GuideRef
+ Codec.Epub.Opf.Package.Manifest: ManifestItem :: MFItemId -> MFItemHref -> MFItemMediaType -> ManifestItem
+ Codec.Epub.Opf.Package.Manifest: data ManifestItem
+ Codec.Epub.Opf.Package.Manifest: instance Eq ManifestItem
+ Codec.Epub.Opf.Package.Manifest: instance Show ManifestItem
+ Codec.Epub.Opf.Package.Manifest: mfiHref :: ManifestItem -> MFItemHref
+ Codec.Epub.Opf.Package.Manifest: mfiId :: ManifestItem -> MFItemId
+ Codec.Epub.Opf.Package.Manifest: mfiMediaType :: ManifestItem -> MFItemMediaType
+ Codec.Epub.Opf.Package.Metadata: MetaCreator :: (Maybe String) -> (Maybe String) -> String -> MetaCreator
+ Codec.Epub.Opf.Package.Metadata: MetaDate :: (Maybe String) -> String -> MetaDate
+ Codec.Epub.Opf.Package.Metadata: MetaId :: String -> (Maybe String) -> String -> MetaId
+ Codec.Epub.Opf.Package.Metadata: MetaTitle :: (Maybe String) -> String -> MetaTitle
+ Codec.Epub.Opf.Package.Metadata: Metadata :: [MetaTitle] -> [MetaCreator] -> [MetaCreator] -> [String] -> Maybe String -> Maybe String -> [MetaDate] -> Maybe String -> Maybe String -> [MetaId] -> Maybe String -> [String] -> Maybe String -> Maybe String -> Maybe String -> Metadata
+ Codec.Epub.Opf.Package.Metadata: data MetaCreator
+ Codec.Epub.Opf.Package.Metadata: data MetaDate
+ Codec.Epub.Opf.Package.Metadata: data MetaId
+ Codec.Epub.Opf.Package.Metadata: data MetaTitle
+ Codec.Epub.Opf.Package.Metadata: data Metadata
+ Codec.Epub.Opf.Package.Metadata: emptyMetadata :: Metadata
+ Codec.Epub.Opf.Package.Metadata: instance Eq MetaCreator
+ Codec.Epub.Opf.Package.Metadata: instance Eq MetaDate
+ Codec.Epub.Opf.Package.Metadata: instance Eq MetaId
+ Codec.Epub.Opf.Package.Metadata: instance Eq MetaTitle
+ Codec.Epub.Opf.Package.Metadata: instance Eq Metadata
+ Codec.Epub.Opf.Package.Metadata: instance Show MetaCreator
+ Codec.Epub.Opf.Package.Metadata: instance Show MetaDate
+ Codec.Epub.Opf.Package.Metadata: instance Show MetaId
+ Codec.Epub.Opf.Package.Metadata: instance Show MetaTitle
+ Codec.Epub.Opf.Package.Metadata: instance Show Metadata
+ Codec.Epub.Opf.Package.Metadata: metaContributors :: Metadata -> [MetaCreator]
+ Codec.Epub.Opf.Package.Metadata: metaCoverage :: Metadata -> Maybe String
+ Codec.Epub.Opf.Package.Metadata: metaCreators :: Metadata -> [MetaCreator]
+ Codec.Epub.Opf.Package.Metadata: metaDates :: Metadata -> [MetaDate]
+ Codec.Epub.Opf.Package.Metadata: metaDescription :: Metadata -> Maybe String
+ Codec.Epub.Opf.Package.Metadata: metaFormat :: Metadata -> Maybe String
+ Codec.Epub.Opf.Package.Metadata: metaIds :: Metadata -> [MetaId]
+ Codec.Epub.Opf.Package.Metadata: metaLangs :: Metadata -> [String]
+ Codec.Epub.Opf.Package.Metadata: metaPublisher :: Metadata -> Maybe String
+ Codec.Epub.Opf.Package.Metadata: metaRelation :: Metadata -> Maybe String
+ Codec.Epub.Opf.Package.Metadata: metaRights :: Metadata -> Maybe String
+ Codec.Epub.Opf.Package.Metadata: metaSource :: Metadata -> Maybe String
+ Codec.Epub.Opf.Package.Metadata: metaSubjects :: Metadata -> [String]
+ Codec.Epub.Opf.Package.Metadata: metaTitles :: Metadata -> [MetaTitle]
+ Codec.Epub.Opf.Package.Metadata: metaType :: Metadata -> Maybe String
+ Codec.Epub.Opf.Package.Spine: Spine :: MFItemId -> [SpineItemref] -> Spine
+ Codec.Epub.Opf.Package.Spine: SpineItemref :: MFItemId -> Maybe Bool -> SpineItemref
+ Codec.Epub.Opf.Package.Spine: data Spine
+ Codec.Epub.Opf.Package.Spine: data SpineItemref
+ Codec.Epub.Opf.Package.Spine: instance Eq Spine
+ Codec.Epub.Opf.Package.Spine: instance Eq SpineItemref
+ Codec.Epub.Opf.Package.Spine: instance Show Spine
+ Codec.Epub.Opf.Package.Spine: instance Show SpineItemref
+ Codec.Epub.Opf.Package.Spine: siIdRef :: SpineItemref -> MFItemId
+ Codec.Epub.Opf.Package.Spine: siLinear :: SpineItemref -> Maybe Bool
+ Codec.Epub.Opf.Package.Spine: spineItemrefs :: Spine -> [SpineItemref]
+ Codec.Epub.Opf.Package.Spine: spineToc :: Spine -> MFItemId
+ Codec.Epub.Opf.Parse: parseEpubOpf :: (MonadIO m, MonadError String m) => FilePath -> m Package
+ Codec.Epub.Opf.Parse: parseXmlToOpf :: MonadIO m => String -> m [Package]
Files
- LICENSE +1/−1
- Setup.hs +1/−1
- TODO +2/−0
- epub-metadata.cabal +24/−15
- src/Codec/Epub/IO.hs +6/−3
- src/Codec/Epub/Opf/Cli/Opts.hs +56/−0
- src/Codec/Epub/Opf/Cli/epub-meta.hs +25/−0
- src/Codec/Epub/Opf/Common.hs +17/−0
- src/Codec/Epub/Opf/Format/Guide.hs +31/−0
- src/Codec/Epub/Opf/Format/Manifest.hs +27/−0
- src/Codec/Epub/Opf/Format/Metadata.hs +120/−0
- src/Codec/Epub/Opf/Format/Package.hs +40/−0
- src/Codec/Epub/Opf/Format/Spine.hs +33/−0
- src/Codec/Epub/Opf/Format/Util.hs +26/−0
- src/Codec/Epub/Opf/Metadata.hs +0/−92
- src/Codec/Epub/Opf/Metadata/Format.hs +0/−131
- src/Codec/Epub/Opf/Metadata/Parse.hs +0/−210
- src/Codec/Epub/Opf/Package.hs +43/−0
- src/Codec/Epub/Opf/Package/Guide.hs +24/−0
- src/Codec/Epub/Opf/Package/Manifest.hs +31/−0
- src/Codec/Epub/Opf/Package/Metadata.hs +81/−0
- src/Codec/Epub/Opf/Package/Spine.hs +34/−0
- src/Codec/Epub/Opf/Parse.hs +270/−0
- src/Codec/Epub/Opf/epub-meta.hs +0/−24
- testsuite/runtests.hs +136/−70
- testsuite/testFull.opf +25/−4
- testsuite/testMinimal.opf +9/−2
- testsuite/testMissingAll.opf +6/−2
- util/show-opf.hs +13/−0
LICENSE view
@@ -1,4 +1,4 @@-Copyright Dino Morelli 2010+Copyright Dino Morelli 2010, 2011 All rights reserved.
Setup.hs view
@@ -1,6 +1,6 @@ #! /usr/bin/env runhaskell --- Copyright: 2010 Dino Morelli+-- Copyright: 2010, 2011 Dino Morelli -- License: BSD3 (see LICENSE) -- Author: Dino Morelli <dino@ui3.info>
TODO view
@@ -1,1 +1,3 @@ - Better errors on parse failure, this will emerge along with more unit testing++- More unit testing
epub-metadata.cabal view
@@ -1,36 +1,45 @@ name: epub-metadata-version: 1.0.2+version: 2.0.0 cabal-version: >= 1.2 build-type: Simple license: BSD3 license-file: LICENSE-copyright: 2010 Dino Morelli+copyright: 2010, 2011 Dino Morelli author: Dino Morelli maintainer: Dino Morelli <dino@ui3.info> stability: experimental homepage: http://ui3.info/d/proj/epub-metadata.html-synopsis: Library and utility for parsing and manipulating - ePub metadata-description: Library for parsing and manipulating ePub OPF - metadata. An attempt has been made here to very - thoroughly implement the metadata portion of the OPF - Package Document specification. Also included is a - command-line utility to dump ePub metadata to stdout - in a human-readable form.+synopsis: Library and utility for parsing and manipulating ePub OPF package data+description: Library and utility for parsing and manipulating ePub + OPF package data. An attempt has been made here to + very thoroughly implement the OPF Package Document + specification. Also included is a command-line + utility to dump OPF package data to stdout in a + human-readable form. category: Codec, Text tested-with: GHC>=6.12.1 library exposed-modules: Codec.Epub.IO,- Codec.Epub.Opf.Metadata,- Codec.Epub.Opf.Metadata.Format,- Codec.Epub.Opf.Metadata.Parse+ Codec.Epub.Opf.Common,+ Codec.Epub.Opf.Format.Guide,+ Codec.Epub.Opf.Format.Manifest,+ Codec.Epub.Opf.Format.Metadata,+ Codec.Epub.Opf.Format.Package,+ Codec.Epub.Opf.Format.Spine,+ Codec.Epub.Opf.Format.Util,+ Codec.Epub.Opf.Package,+ Codec.Epub.Opf.Package.Guide,+ Codec.Epub.Opf.Package.Manifest,+ Codec.Epub.Opf.Package.Metadata,+ Codec.Epub.Opf.Package.Spine,+ Codec.Epub.Opf.Parse hs-source-dirs: src- build-depends: base >= 3 && < 5, HSH, hxt, mtl+ build-depends: base >= 3 && < 5, containers, HSH, hxt >= 9, mtl ghc-options: -Wall executable epub-meta- main-is: Codec/Epub/Opf/epub-meta.hs+ main-is: Codec/Epub/Opf/Cli/epub-meta.hs hs-source-dirs: src build-depends: base >= 3 && < 5 ghc-options: -Wall
src/Codec/Epub/IO.hs view
@@ -1,4 +1,4 @@--- Copyright: 2010 Dino Morelli+-- Copyright: 2010, 2011 Dino Morelli -- License: BSD3 (see LICENSE) -- Author: Dino Morelli <dino@ui3.info> @@ -13,10 +13,13 @@ ( extractFileFromZip, opfPath ) where +import Control.Arrow.ListArrows ( (>>>), deep ) import Control.Monad.Error import HSH.Command import Text.Printf-import Text.XML.HXT.Arrow+import Text.XML.HXT.Arrow.XmlArrow ( getAttrValue, hasName, isElem )+import Text.XML.HXT.Arrow.XmlState ( no, runX, withValidate )+import Text.XML.HXT.Arrow.ReadDocument ( readString ) {- | Extract a file from a zipfile.@@ -46,7 +49,7 @@ "META-INF/container.xml" result <- liftIO $ runX (- readString [(a_validate, v_0)] containerContents+ readString [withValidate no] containerContents >>> deep (isElem >>> hasName "rootfile") >>> getAttrValue "full-path" )
+ src/Codec/Epub/Opf/Cli/Opts.hs view
@@ -0,0 +1,56 @@+-- Copyright: 2010, 2011 Dino Morelli+-- License: BSD3 (see LICENSE)+-- Author: Dino Morelli <dino@ui3.info>++module Codec.Epub.Opf.Cli.Opts+ ( Options (..)+ , parseOpts, usageText+ )+ where++import System.Console.GetOpt+++data Options = Options+ { optHelp :: Bool+ , optVerbose :: Bool+ }+++defaultOptions :: Options+defaultOptions = Options+ { optHelp = False+ , optVerbose = False+ }+++options :: [OptDescr (Options -> Options)]+options =+ [ Option ['h'] ["help"] + (NoArg (\opts -> opts { optHelp = True } ))+ "This help text"+ , Option ['v'] ["verbose"]+ (NoArg (\opts -> opts { optVerbose = True } )) + "Display all OPF package info, including manifest, spine and guide"+ ]+++parseOpts :: [String] -> IO (Options, [String])+parseOpts argv = + case getOpt Permute options argv of+ (o,n,[] ) -> return (foldl (flip id) defaultOptions o, n)+ (_,_,errs) -> ioError $ userError (concat errs ++ usageText)+++usageText :: String+usageText = (usageInfo header options) ++ "\n" ++ footer+ where+ header = init $ unlines+ [ "Usage: epub-meta [OPTIONS] EPUBFILE"+ , "Examine ePub OPF package data"+ , ""+ , "Options:"+ ]+ footer = init $ unlines+ [ "Version 2.0.0 Dino Morelli <dino@ui3.info>"+ ]
+ src/Codec/Epub/Opf/Cli/epub-meta.hs view
@@ -0,0 +1,25 @@+-- Copyright: 2010, 2011 Dino Morelli+-- License: BSD3 (see LICENSE)+-- Author: Dino Morelli <dino@ui3.info>++import Control.Monad.Error+import System.Environment ( getArgs )+import System.Exit++import Codec.Epub.Opf.Cli.Opts+import Codec.Epub.Opf.Format.Package+import Codec.Epub.Opf.Parse+++main :: IO ()+main = do+ (opts, paths) <- getArgs >>= parseOpts++ when ((optHelp opts) || (null paths)) $ do+ putStrLn usageText+ exitWith $ ExitFailure 1++ let zipPath = head paths+ result <- runErrorT $ parseEpubOpf zipPath++ putStr $ either id (formatPackage (optVerbose opts)) result
+ src/Codec/Epub/Opf/Common.hs view
@@ -0,0 +1,17 @@+-- Copyright: 2010, 2011 Dino Morelli+-- License: BSD3 (see LICENSE)+-- Author: Dino Morelli <dino@ui3.info>++{- | Data types for working with the metadata of ePub documents++ These data types were constructed by studying the IDPF OPF + specification for ePub documents found here:++ <http://www.idpf.org/2007/opf/OPF_2.0_final_spec.html>+-}+module Codec.Epub.Opf.Common+ where+++-- | Attribute value used to relate things to each other in the OPF data+type MFItemId = String
+ src/Codec/Epub/Opf/Format/Guide.hs view
@@ -0,0 +1,31 @@+-- Copyright: 2010, 2011 Dino Morelli+-- License: BSD3 (see LICENSE)+-- Author: Dino Morelli <dino@ui3.info>++{-# LANGUAGE FlexibleContexts #-}++-- | Module for pretty-printing ePub metadata info+module Codec.Epub.Opf.Format.Guide+ where++import Control.Monad.Writer.Lazy+import Text.Printf++import Codec.Epub.Opf.Format.Util+import Codec.Epub.Opf.Package.Guide+++tellGuideRef :: MonadWriter (Seq Char) m => GuideRef -> m ()+tellGuideRef (GuideRef grty title href) =+ tellSeq $ printf " type: %s%s, href: %s\n"+ grty (titleToString title) href++ where+ titleToString = maybe "" (printf ", title: %s")+++tellGuide :: MonadWriter (Seq Char) m => [GuideRef] -> m ()+tellGuide [] = return ()+tellGuide grs = do+ tellSeq "guide items:\n"+ mapM_ tellGuideRef grs
+ src/Codec/Epub/Opf/Format/Manifest.hs view
@@ -0,0 +1,27 @@+-- Copyright: 2010, 2011 Dino Morelli+-- License: BSD3 (see LICENSE)+-- Author: Dino Morelli <dino@ui3.info>++{-# LANGUAGE FlexibleContexts #-}++-- | Module for pretty-printing ePub metadata info+module Codec.Epub.Opf.Format.Manifest+ where++import Control.Monad.Writer.Lazy+import Text.Printf++import Codec.Epub.Opf.Format.Util+import Codec.Epub.Opf.Package.Manifest+++tellManifestItem :: MonadWriter (Seq Char) m => ManifestItem -> m ()+tellManifestItem (ManifestItem mfId href mediaType) =+ tellSeq $ printf " id: %s, href: %s, media-type: %s\n"+ mfId href mediaType+++tellManifest :: MonadWriter (Seq Char) m => [ManifestItem] -> m ()+tellManifest mas = do+ tellSeq "manifest items:\n"+ mapM_ tellManifestItem mas
+ src/Codec/Epub/Opf/Format/Metadata.hs view
@@ -0,0 +1,120 @@+-- Copyright: 2010, 2011 Dino Morelli+-- License: BSD3 (see LICENSE)+-- Author: Dino Morelli <dino@ui3.info>++{-# LANGUAGE FlexibleContexts #-}++-- | Module for pretty-printing ePub metadata info+module Codec.Epub.Opf.Format.Metadata+ where++import Control.Monad.Writer.Lazy+import Text.Printf++import Codec.Epub.Opf.Format.Util+import Codec.Epub.Opf.Package.Metadata+++tellTitle :: MonadWriter (Seq Char) m => MetaTitle -> m ()+tellTitle (MetaTitle Nothing title) = tellSeq $ printf "title: %s\n" title+tellTitle (MetaTitle lang title) =+ tellSeq $ printf "title\n%s%s" (formatSubline "lang" lang)+ (formatSubline "title" (Just title))+++tellCreator :: MonadWriter (Seq Char) m => MetaCreator -> m ()+tellCreator (MetaCreator Nothing Nothing creator) =+ tellSeq $ printf "creator: %s\n" creator+tellCreator (MetaCreator role fileAs creator) =+ tellSeq $ printf "creator\n%s%s%s"+ (formatSubline "role" role)+ (formatSubline "file-as" fileAs)+ (formatSubline "creator" (Just creator))+++tellContributor :: MonadWriter (Seq Char) m => MetaCreator -> m ()+tellContributor (MetaCreator Nothing Nothing contributor) =+ tellSeq $ printf "contributor: %s\n" contributor+tellContributor (MetaCreator role fileAs contributor) =+ tellSeq $ printf "contributor\n%s%s%s"+ (formatSubline "role" role)+ (formatSubline "file-as" fileAs)+ (formatSubline "creator" (Just contributor))+++tellDate :: MonadWriter (Seq Char) m => MetaDate -> m ()+tellDate (MetaDate Nothing date) =+ tellSeq $ printf "date: %s\n" date+tellDate (MetaDate event date) =+ tellSeq $ printf "date\n%s%s"+ (formatSubline "event" event)+ (formatSubline "date" (Just date))+++tellType :: MonadWriter (Seq Char) m => Maybe String -> m ()+tellType = maybe (return ()) (tellSeq . (printf "type: %s\n"))+++tellFormat :: MonadWriter (Seq Char) m => Maybe String -> m ()+tellFormat = maybe (return ()) (tellSeq . (printf "format: %s\n"))+++tellId :: MonadWriter (Seq Char) m => MetaId -> m ()+tellId (MetaId idVal scheme content) =+ tellSeq $ printf "identifier\n%s%s%s"+ (formatSubline "id" (Just idVal))+ (formatSubline "scheme" scheme)+ (formatSubline "identifier" (Just content))+++tellSource :: MonadWriter (Seq Char) m => Maybe String -> m ()+tellSource = maybe (return ()) (tellSeq . (printf "source: %s\n"))+++tellSubject :: MonadWriter (Seq Char) m => String -> m ()+tellSubject = tellSeq . (printf "subject: %s\n")+++tellDescription :: MonadWriter (Seq Char) m => Maybe String -> m ()+tellDescription = maybe (return ()) (tellSeq . (printf "description: %s\n"))+++tellPublisher :: MonadWriter (Seq Char) m => Maybe String -> m ()+tellPublisher = maybe (return ()) (tellSeq . (printf "publisher: %s\n"))+++tellLang :: MonadWriter (Seq Char) m => String -> m ()+tellLang = tellSeq . (printf "language: %s\n")+++tellRelation :: MonadWriter (Seq Char) m => Maybe String -> m ()+tellRelation = maybe (return ()) (tellSeq . (printf "relation: %s\n"))+++tellCoverage :: MonadWriter (Seq Char) m => Maybe String -> m ()+tellCoverage = maybe (return ()) (tellSeq . (printf "coverage: %s\n"))+++tellRights :: MonadWriter (Seq Char) m => Maybe String -> m ()+tellRights = maybe (return ()) (tellSeq . (printf "rights: %s\n"))+++tellMetadata :: MonadWriter (Seq Char) m => Metadata -> m ()+tellMetadata (Metadata titles creators contributors subjects desc + publisher dates mType format ids source langs relation + coverage rights) = do+ mapM_ tellTitle titles+ mapM_ tellCreator creators+ mapM_ tellContributor contributors+ mapM_ tellDate dates+ tellType mType+ tellFormat format+ mapM_ tellId ids+ tellSource source+ mapM_ tellSubject subjects+ tellDescription desc+ tellPublisher publisher+ mapM_ tellLang langs+ tellRelation relation+ tellCoverage coverage+ tellRights rights
+ src/Codec/Epub/Opf/Format/Package.hs view
@@ -0,0 +1,40 @@+-- Copyright: 2010, 2011 Dino Morelli+-- License: BSD3 (see LICENSE)+-- Author: Dino Morelli <dino@ui3.info>++{-# LANGUAGE FlexibleContexts #-}++-- | Module for pretty-printing OPF package data+module Codec.Epub.Opf.Format.Package+ ( formatPackage+ )+ where++import Control.Monad.Writer.Lazy+import Data.Foldable ( toList )++import Codec.Epub.Opf.Format.Guide+import Codec.Epub.Opf.Format.Manifest+import Codec.Epub.Opf.Format.Metadata+import Codec.Epub.Opf.Format.Spine+import Codec.Epub.Opf.Format.Util+import Codec.Epub.Opf.Package+++tellPackage :: MonadWriter (Seq Char) m => (String, String) -> m ()+tellPackage (version, uniqueId) = do+ tellSeq "package\n"+ tellSeq $ formatSubline "version" (Just version)+ tellSeq $ formatSubline "unique-identifier" (Just uniqueId)+++formatPackage :: Bool -> Package -> String+formatPackage showAll (Package v u meta ma sp gu) =+ toList . execWriter $ do+ tellPackage (v, u)+ tellMetadata meta++ when showAll $ do+ tellManifest ma+ tellSpine sp+ tellGuide gu
+ src/Codec/Epub/Opf/Format/Spine.hs view
@@ -0,0 +1,33 @@+-- Copyright: 2010, 2011 Dino Morelli+-- License: BSD3 (see LICENSE)+-- Author: Dino Morelli <dino@ui3.info>++{-# LANGUAGE FlexibleContexts #-}++-- | Module for pretty-printing ePub metadata info+module Codec.Epub.Opf.Format.Spine+ where++import Control.Monad.Writer.Lazy+import Text.Printf++import Codec.Epub.Opf.Format.Util+import Codec.Epub.Opf.Package.Spine+++tellSpineItemref :: MonadWriter (Seq Char) m => SpineItemref -> m ()+tellSpineItemref (SpineItemref idref linear) =+ tellSeq $ printf " idref: %s%s\n" idref (linearToString linear)++ where+ boolToYn True = "yes"+ boolToYn False = "no"++ linearToString Nothing = ""+ linearToString (Just l) = printf ", linear: %s" (boolToYn l)+++tellSpine :: MonadWriter (Seq Char) m => Spine -> m ()+tellSpine (Spine toc itemRefs) = do+ tellSeq $ printf "spine toc: %s, itemrefs:\n" toc+ mapM_ tellSpineItemref itemRefs
+ src/Codec/Epub/Opf/Format/Util.hs view
@@ -0,0 +1,26 @@+-- Copyright: 2010, 2011 Dino Morelli+-- License: BSD3 (see LICENSE)+-- Author: Dino Morelli <dino@ui3.info>++{-# LANGUAGE FlexibleContexts #-}++-- | Functions shared by several formatting modules+module Codec.Epub.Opf.Format.Util+ ( formatSubline+ , tellSeq+ , Seq+ )+ where++import Control.Monad.Writer.Lazy+import Data.Sequence ( Seq, fromList )+import Text.Printf+++formatSubline :: String -> Maybe String -> String+formatSubline _ Nothing = ""+formatSubline key (Just value) = printf " %s: %s\n" key value+++tellSeq :: MonadWriter (Seq a) m => [a] -> m ()+tellSeq = tell . fromList
− src/Codec/Epub/Opf/Metadata.hs
@@ -1,92 +0,0 @@--- Copyright: 2010 Dino Morelli--- License: BSD3 (see LICENSE)--- Author: Dino Morelli <dino@ui3.info>--{- | Data types for working with the metadata of ePub documents-- These data types were constructed by studying the IDPF OPF - specification for ePub documents found here:-- <http://www.idpf.org/2007/opf/OPF_2.0_final_spec.html>--}-module Codec.Epub.Opf.Metadata- ( OPFPackage (..)- , EMTitle (..)- , EMCreator (..)- , EMDate (..)- , EMId (..)- , EpubMeta (..)- , emptyEpubMeta- )- where---{- | opf:package tag-- Note that we are not yet storing the data that comes after- \/package\/metadata in an OPF Package Document. But that may- be added at a later time.--}-data OPFPackage = OPFPackage- { opVersion :: String -- ^ version attr- , opUniqueId :: String -- ^ unique-identifier attr- , opMeta :: EpubMeta -- ^ metadata child element contents- }- deriving (Eq, Show)----- | dc:title tag, xml:lang attr, content-data EMTitle = EMTitle (Maybe String) String- deriving (Eq, Show)---- | dc:creator tag, opf:role attr, opf:file-as attr, content-data EMCreator = EMCreator (Maybe String) (Maybe String) String- deriving (Eq, Show)---- | dc:date tag, opf:event attr, content-data EMDate = EMDate (Maybe String) String- deriving (Eq, Show)---- | dc:identifier tag, id attr, opf:scheme attr, content-data EMId = EMId String (Maybe String) String- deriving (Eq, Show)---- | opf:metadata tag-data EpubMeta = EpubMeta- { emTitles :: [EMTitle] -- ^ at least one required- , emCreators :: [EMCreator]- , emContributors :: [EMCreator]- , emSubjects :: [String] -- ^ dc:subject tags- , emDescription :: Maybe String -- ^ dc:description tags- , emPublisher :: Maybe String -- ^ dc:publisher tag- , emDates :: [EMDate]- , emType :: Maybe String -- ^ dc:type tag- , emFormat :: Maybe String -- ^ dc:format tag- , emIds :: [EMId] -- ^ at least one required- , emSource :: Maybe String -- ^ dc:source tag- , emLangs :: [String] -- ^ dc:language tags, at least one required- , emRelation :: Maybe String -- ^ dc:relation tag- , emCoverage :: Maybe String -- ^ dc:coverage tag- , emRights :: Maybe String -- ^ dc:rights tag- }- deriving (Eq, Show)---- | Note: This isn't valid as-is, some required values are empty lists!-emptyEpubMeta :: EpubMeta-emptyEpubMeta = EpubMeta- { emTitles = [] -- one required- , emCreators = []- , emContributors = []- , emSubjects = []- , emDescription = Nothing- , emPublisher = Nothing- , emDates = []- , emType = Nothing- , emFormat = Nothing- , emIds = [] -- one required- , emSource = Nothing- , emLangs = [] -- one required- , emRelation = Nothing- , emCoverage = Nothing- , emRights = Nothing- }
− src/Codec/Epub/Opf/Metadata/Format.hs
@@ -1,131 +0,0 @@--- Copyright: 2010 Dino Morelli--- License: BSD3 (see LICENSE)--- Author: Dino Morelli <dino@ui3.info>---- | Module for pretty-printing ePub metadata info-module Codec.Epub.Opf.Metadata.Format- ( opfToString- )- where--import Text.Printf--import Codec.Epub.Opf.Metadata---formatSubline :: String -> Maybe String -> String-formatSubline _ Nothing = ""-formatSubline key (Just value) = printf " %s: %s\n" key value---packageToString :: (String, String) -> String-packageToString (version, uniqueId) =- "package\n" ++- (formatSubline "version" (Just version)) ++- (formatSubline "unique-identifier" (Just uniqueId))---titleToString :: EMTitle -> String-titleToString (EMTitle Nothing title) = printf "title: %s\n" title-titleToString (EMTitle lang title) =- "title\n" ++- (formatSubline "lang" lang) ++- (formatSubline "title" (Just title))---creatorToString :: EMCreator -> String-creatorToString (EMCreator Nothing Nothing creator) =- printf "creator: %s\n" creator-creatorToString (EMCreator role fileAs creator) =- "creator\n" ++- (formatSubline "role" role) ++- (formatSubline "file-as" fileAs) ++- (formatSubline "creator" (Just creator))---contributorToString :: EMCreator -> String-contributorToString (EMCreator Nothing Nothing contributor) =- printf "contributor: %s\n" contributor-contributorToString (EMCreator role fileAs contributor) =- "contributor\n" ++- (formatSubline "role" role) ++- (formatSubline "file-as" fileAs) ++- (formatSubline "creator" (Just contributor))---subjectToString :: String -> String-subjectToString = printf "subject: %s\n"---descriptionToString :: Maybe String -> String-descriptionToString = maybe "" (printf "description: %s\n")---publisherToString :: Maybe String -> String-publisherToString = maybe "" (printf "publisher: %s\n")---dateToString :: EMDate -> String-dateToString (EMDate Nothing date) =- printf "date: %s\n" date-dateToString (EMDate event date) =- "date\n" ++- (formatSubline "event" event) ++- (formatSubline "date" (Just date))---typeToString :: Maybe String -> String-typeToString = maybe "" (printf "type: %s\n")---formatToString :: Maybe String -> String-formatToString = maybe "" (printf "format: %s\n")---idToString :: EMId -> String-idToString (EMId idVal scheme content) =- "identifier\n" ++- (formatSubline "id" (Just idVal)) ++- (formatSubline "scheme" scheme) ++- (formatSubline "identifier" (Just content))---sourceToString :: Maybe String -> String-sourceToString = maybe "" (printf "source: %s\n")---langToString :: String -> String-langToString = printf "language: %s\n"---relationToString :: Maybe String -> String-relationToString = maybe "" (printf "relation: %s\n")---coverageToString :: Maybe String -> String-coverageToString = maybe "" (printf "coverage: %s\n")---rightsToString :: Maybe String -> String-rightsToString = maybe "" (printf "rights: %s\n")----- | Format an ePub metadata into a String-opfToString :: OPFPackage -> String-opfToString (OPFPackage v u em) = concat $- [packageToString (v, u)] ++- (map titleToString $ emTitles em) ++- (map creatorToString $ emCreators em) ++- (map contributorToString $ emContributors em) ++- (map dateToString $ emDates em) ++- [typeToString . emType $ em] ++- [formatToString . emFormat $ em] ++- (map idToString $ emIds em) ++- [sourceToString . emSource $ em] ++- (map subjectToString $ emSubjects em) ++- [descriptionToString . emDescription $ em] ++- [publisherToString . emPublisher $ em] ++- (map langToString $ emLangs em) ++- [relationToString . emRelation $ em] ++- [coverageToString . emCoverage $ em] ++- [rightsToString . emRights $ em]
− src/Codec/Epub/Opf/Metadata/Parse.hs
@@ -1,210 +0,0 @@--- Copyright: 2010 Dino Morelli--- License: BSD3 (see LICENSE)--- Author: Dino Morelli <dino@ui3.info>--{-# LANGUAGE Arrows #-}-{-# LANGUAGE FlexibleContexts #-}---- | Module for extracting the metadata from an ePub file-module Codec.Epub.Opf.Metadata.Parse- ( parseXmlToOpf- , parseEpubOpf- )- where--import Control.Applicative-import Control.Monad.Error-import Data.Tree.NTree.TypeDefs ( NTree )-import Prelude hiding ( cos )-import Text.XML.HXT.Arrow--import Codec.Epub.IO-import Codec.Epub.Opf.Metadata----- HXT helpers--atTag :: (ArrowXml a) => String -> a (NTree XNode) XmlTree-atTag tag = deep (isElem >>> hasName tag)--atQTag :: (ArrowXml a) => QName -> a (NTree XNode) XmlTree-atQTag tag = deep (isElem >>> hasQName tag)--text :: (ArrowXml a) => a (NTree XNode) String-text = getChildren >>> getText--notNullA :: (ArrowList a) => a [b] [b]-notNullA = isA $ not . null---mbQTagText :: (ArrowXml a) => QName -> a (NTree XNode) (Maybe String)-mbQTagText tag =- ( atQTag tag >>>- text >>> notNullA >>> arr Just )- `orElse`- (constA Nothing)---mbGetAttrValue :: (ArrowXml a) =>- String -> a XmlTree (Maybe String)-mbGetAttrValue n =- (getAttrValue n >>> notNullA >>> arr Just)- `orElse` (constA Nothing)--mbGetQAttrValue :: (ArrowXml a) =>- QName -> a XmlTree (Maybe String)-mbGetQAttrValue qn =- (getQAttrValue qn >>> notNullA >>> arr Just)- `orElse` (constA Nothing)---{- ePub parsing helpers-- Note that these URIs could conceivably change in the future- Is it ok that they're hardcoded like this?-- Well, ok, the xml namespace URI will probably never change.--}--dcName, opfName, xmlName :: String -> QName-dcName local = mkQName "dc" local "http://purl.org/dc/elements/1.1/"-opfName local = mkQName "opf" local "http://www.idpf.org/2007/opf"-xmlName local = mkQName "xml" local "http://www.w3.org/XML/1998/namespace"---getPackage :: (ArrowXml a) => a (NTree XNode) (String, String)-getPackage = atTag "package" >>>- proc x -> do- v <- getAttrValue "version" -< x- u <- getAttrValue "unique-identifier" -< x- returnA -< (v, u)---getTitle :: (ArrowXml a) => a (NTree XNode) EMTitle-getTitle = atQTag (dcName "title") >>>- proc x -> do- l <- mbGetQAttrValue (xmlName "lang") -< x- c <- text -< x- returnA -< EMTitle l c---{- Since creators and contributors have the same exact XML structure,- this arrow is used to get either of them--}-getCreator :: (ArrowXml a) => String -> a (NTree XNode) EMCreator-getCreator tag = atQTag (dcName tag) >>> ( unwrapArrow $ EMCreator- <$> (WrapArrow $ mbGetQAttrValue (opfName "role"))- <*> (WrapArrow $ mbGetQAttrValue (opfName "file-as"))- <*> (WrapArrow $ text)- )---getSubject :: (ArrowXml a) => a (NTree XNode) String-getSubject = atQTag (dcName "subject") >>> text---getDescription :: (ArrowXml a) => a (NTree XNode) (Maybe String)-getDescription = mbQTagText $ dcName "description"---getPublisher :: (ArrowXml a) => a (NTree XNode) (Maybe String)-getPublisher = mbQTagText $ dcName "publisher"---getDate :: (ArrowXml a) => a (NTree XNode) EMDate-getDate = atQTag (dcName "date") >>>- proc x -> do- e <- mbGetQAttrValue (opfName "event") -< x- c <- text -< x- returnA -< EMDate e c---getType :: (ArrowXml a) => a (NTree XNode) (Maybe String)-getType = mbQTagText $ dcName "type"---getFormat :: (ArrowXml a) => a (NTree XNode) (Maybe String)-getFormat = mbQTagText $ dcName "format"---getId :: (ArrowXml a) => a (NTree XNode) EMId-getId = atQTag (dcName "identifier") >>>- proc x -> do- mbi <- mbGetAttrValue "id" -< x- s <- mbGetQAttrValue (opfName "scheme") -< x- c <- text -< x- let i = maybe "[WARNING: missing required id attribute]" id mbi- returnA -< EMId i s c---getSource :: (ArrowXml a) => a (NTree XNode) (Maybe String)-getSource = mbQTagText $ dcName "source"---getLang :: (ArrowXml a) => a (NTree XNode) String-getLang = atQTag (dcName "language") >>> text---getRelation :: (ArrowXml a) => a (NTree XNode) (Maybe String)-getRelation = mbQTagText $ dcName "relation"---getCoverage :: (ArrowXml a) => a (NTree XNode) (Maybe String)-getCoverage = mbQTagText $ dcName "coverage"---getRights :: (ArrowXml a) => a (NTree XNode) (Maybe String)-getRights = mbQTagText $ dcName "rights"---getMeta :: (ArrowXml a) => a (NTree XNode) EpubMeta-getMeta = atTag "metadata" >>> ( unwrapArrow $ EpubMeta- <$> (WrapArrow $ listA getTitle)- <*> (WrapArrow $ listA $ getCreator "creator")- <*> (WrapArrow $ listA $ getCreator "contributor")- <*> (WrapArrow $ listA getSubject)- <*> (WrapArrow $ getDescription)- <*> (WrapArrow $ getPublisher)- <*> (WrapArrow $ listA getDate)- <*> (WrapArrow $ getType)- <*> (WrapArrow $ getFormat)- <*> (WrapArrow $ listA getId)- <*> (WrapArrow $ getSource)- <*> (WrapArrow $ listA getLang)- <*> (WrapArrow $ getRelation)- <*> (WrapArrow $ getCoverage)- <*> (WrapArrow $ getRights)- )---getBookData :: (ArrowXml a) => a (NTree XNode) OPFPackage-getBookData = - proc x -> do- (v, u) <- getPackage -< x- m <- getMeta -< x- returnA -< OPFPackage v u m---{- | Extract the ePub metadata contained in the OPF Package Document - contained in the supplied string--}-parseXmlToOpf :: (MonadIO m) => String -> m [OPFPackage]-parseXmlToOpf opfContents =- liftIO $ runX (- readString [(a_validate, v_0)] opfContents- >>> propagateNamespaces- >>> getBookData- )----- | Given the path to an ePub file, extract the metadata-parseEpubOpf :: (MonadIO m, MonadError String m) =>- FilePath -> m OPFPackage-parseEpubOpf zipPath = do- opfContents <- extractFileFromZip zipPath =<< opfPath zipPath- result <- parseXmlToOpf opfContents-- case result of- (em : []) -> return em- _ -> throwError- "ERROR: we didn't come up with a single EpubMeta"
+ src/Codec/Epub/Opf/Package.hs view
@@ -0,0 +1,43 @@+-- Copyright: 2010, 2011 Dino Morelli+-- License: BSD3 (see LICENSE)+-- Author: Dino Morelli <dino@ui3.info>++{- | Data types for working with the metadata of ePub documents++ These data types were constructed by studying the IDPF OPF + specification for ePub documents found here:++ <http://www.idpf.org/2007/opf/OPF_2.0_final_spec.html>+-}+module Codec.Epub.Opf.Package+ ( Package (..)+ , MetaTitle (..)+ , MetaCreator (..)+ , MetaDate (..)+ , MetaId (..)+ , Metadata (..)+ , ManifestItem (..)+ , SpineItemref (..)+ , Spine (..)+ , GuideRef (..)+ , emptyMetadata+ )+ where++import Codec.Epub.Opf.Package.Guide+import Codec.Epub.Opf.Package.Manifest+import Codec.Epub.Opf.Package.Metadata+import Codec.Epub.Opf.Package.Spine+++{- | package tag+-}+data Package = Package+ { opVersion :: String -- ^ version attr+ , opUniqueId :: String -- ^ unique-identifier attr+ , opMeta :: Metadata -- ^ metadata child element contents+ , opManifest :: [ManifestItem] -- ^ manifest child element contents. One required+ , opSpine :: Spine -- ^ spine child element contents+ , opGuide :: [GuideRef] -- ^ guide child element contents+ }+ deriving (Eq, Show)
+ src/Codec/Epub/Opf/Package/Guide.hs view
@@ -0,0 +1,24 @@+-- Copyright: 2010, 2011 Dino Morelli+-- License: BSD3 (see LICENSE)+-- Author: Dino Morelli <dino@ui3.info>++{- | Data types for working with the metadata of ePub documents++ These data types were constructed by studying the IDPF OPF + specification for ePub documents found here:++ <http://www.idpf.org/2007/opf/OPF_2.0_final_spec.html>+-}+module Codec.Epub.Opf.Package.Guide+ ( GuideRef (..)+ )+ where+++-- | package\/guide\/reference tag+data GuideRef = GuideRef+ { grType :: String -- ^ type attr. Must follow 13th edition of the Chicago Manual of Style+ , grTitle :: Maybe String -- ^ title attr+ , grHref :: String -- ^ href attr. Must reference item in manifest+ }+ deriving (Eq, Show)
+ src/Codec/Epub/Opf/Package/Manifest.hs view
@@ -0,0 +1,31 @@+-- Copyright: 2010, 2011 Dino Morelli+-- License: BSD3 (see LICENSE)+-- Author: Dino Morelli <dino@ui3.info>++{- | Data types for working with the metadata of ePub documents++ These data types were constructed by studying the IDPF OPF + specification for ePub documents found here:++ <http://www.idpf.org/2007/opf/OPF_2.0_final_spec.html>+-}+module Codec.Epub.Opf.Package.Manifest+ ( ManifestItem (..)+ )+ where++import Codec.Epub.Opf.Common+++-- | manifest attribute values+type MFItemHref = String+type MFItemMediaType = String+++-- | package\/manifest\/item tag+data ManifestItem = ManifestItem+ { mfiId :: MFItemId -- ^ id attr+ , mfiHref :: MFItemHref -- ^ href attr+ , mfiMediaType :: MFItemMediaType -- ^ media-type attr+ }+ deriving (Eq, Show)
+ src/Codec/Epub/Opf/Package/Metadata.hs view
@@ -0,0 +1,81 @@+-- Copyright: 2010, 2011 Dino Morelli+-- License: BSD3 (see LICENSE)+-- Author: Dino Morelli <dino@ui3.info>++{- | Data types for working with the metadata of ePub documents++ These data types were constructed by studying the IDPF OPF + specification for ePub documents found here:++ <http://www.idpf.org/2007/opf/OPF_2.0_final_spec.html>+-}+module Codec.Epub.Opf.Package.Metadata+ ( MetaTitle (..)+ , MetaCreator (..)+ , MetaDate (..)+ , MetaId (..)+ , Metadata (..)+ , emptyMetadata+ )+ where+++-- | package\/metadata\/dc:title tag, xml:lang attr, content+data MetaTitle = MetaTitle (Maybe String) String+ deriving (Eq, Show)++{- | package\/metadata\/dc:creator tag, opf:role attr, opf:file-as attr,+ content+-}+data MetaCreator = MetaCreator (Maybe String) (Maybe String) String+ deriving (Eq, Show)++-- | package\/metadata\/dc:date tag, opf:event attr, content+data MetaDate = MetaDate (Maybe String) String+ deriving (Eq, Show)++{- | package\/metadata\/dc:identifier tag, id attr, opf:scheme attr,+ content+-}+data MetaId = MetaId String (Maybe String) String+ deriving (Eq, Show)++-- | package\/metadata tag+data Metadata = Metadata+ { metaTitles :: [MetaTitle] -- ^ at least one required+ , metaCreators :: [MetaCreator]+ , metaContributors :: [MetaCreator]+ , metaSubjects :: [String] -- ^ dc:subject tags+ , metaDescription :: Maybe String -- ^ dc:description tags+ , metaPublisher :: Maybe String -- ^ dc:publisher tag+ , metaDates :: [MetaDate]+ , metaType :: Maybe String -- ^ dc:type tag+ , metaFormat :: Maybe String -- ^ dc:format tag+ , metaIds :: [MetaId] -- ^ at least one required+ , metaSource :: Maybe String -- ^ dc:source tag+ , metaLangs :: [String] -- ^ dc:language tags, at least one required+ , metaRelation :: Maybe String -- ^ dc:relation tag+ , metaCoverage :: Maybe String -- ^ dc:coverage tag+ , metaRights :: Maybe String -- ^ dc:rights tag+ }+ deriving (Eq, Show)++-- | Note: This isn't valid as-is, some required values are empty lists!+emptyMetadata :: Metadata+emptyMetadata = Metadata+ { metaTitles = [] -- one required+ , metaCreators = []+ , metaContributors = []+ , metaSubjects = []+ , metaDescription = Nothing+ , metaPublisher = Nothing+ , metaDates = []+ , metaType = Nothing+ , metaFormat = Nothing+ , metaIds = [] -- one required+ , metaSource = Nothing+ , metaLangs = [] -- one required+ , metaRelation = Nothing+ , metaCoverage = Nothing+ , metaRights = Nothing+ }
+ src/Codec/Epub/Opf/Package/Spine.hs view
@@ -0,0 +1,34 @@+-- Copyright: 2010, 2011 Dino Morelli+-- License: BSD3 (see LICENSE)+-- Author: Dino Morelli <dino@ui3.info>++{- | Data types for working with the metadata of ePub documents++ These data types were constructed by studying the IDPF OPF + specification for ePub documents found here:++ <http://www.idpf.org/2007/opf/OPF_2.0_final_spec.html>+-}+module Codec.Epub.Opf.Package.Spine+ ( Spine (..)+ , SpineItemref (..)+ )+ where++import Codec.Epub.Opf.Common+++-- | package\/spine\/itemref tag+data SpineItemref = SpineItemref+ { siIdRef :: MFItemId -- ^ idref attr. Must reference item in manifest+ , siLinear :: Maybe Bool -- ^ linear attr+ }+ deriving (Eq, Show)+++-- | package\/spine tag+data Spine = Spine+ { spineToc :: MFItemId -- ^ toc attr. Must reference the NCX in the manifest+ , spineItemrefs :: [ SpineItemref ] -- one required+ }+ deriving (Eq, Show)
+ src/Codec/Epub/Opf/Parse.hs view
@@ -0,0 +1,270 @@+-- Copyright: 2010, 2011 Dino Morelli+-- License: BSD3 (see LICENSE)+-- Author: Dino Morelli <dino@ui3.info>++{-# LANGUAGE Arrows #-}+{-# LANGUAGE FlexibleContexts #-}++-- | Module for extracting the metadata from an ePub file+module Codec.Epub.Opf.Parse+ ( parseXmlToOpf+ , parseEpubOpf+ )+ where++import Control.Applicative+import Control.Arrow.ListArrows+import Control.Monad.Error+import Data.Tree.NTree.TypeDefs ( NTree )+import Text.XML.HXT.Arrow.Namespace ( propagateNamespaces )+import Text.XML.HXT.Arrow.XmlArrow+import Text.XML.HXT.Arrow.XmlState ( no, runX, withValidate )+import Text.XML.HXT.Arrow.ReadDocument ( readString )+import Text.XML.HXT.DOM.TypeDefs++import Codec.Epub.IO+import Codec.Epub.Opf.Package+++-- HXT helpers++atTag :: (ArrowXml a) => String -> a (NTree XNode) XmlTree+atTag tag = deep (isElem >>> hasName tag)++atQTag :: (ArrowXml a) => QName -> a (NTree XNode) XmlTree+atQTag tag = deep (isElem >>> hasQName tag)++text :: (ArrowXml a) => a (NTree XNode) String+text = getChildren >>> getText++notNullA :: (ArrowList a) => a [b] [b]+notNullA = isA $ not . null+++mbQTagText :: (ArrowXml a) => QName -> a (NTree XNode) (Maybe String)+mbQTagText tag =+ ( atQTag tag >>>+ text >>> notNullA >>> arr Just )+ `orElse`+ (constA Nothing)+++mbGetAttrValue :: (ArrowXml a) =>+ String -> a XmlTree (Maybe String)+mbGetAttrValue n =+ (getAttrValue n >>> notNullA >>> arr Just)+ `orElse` (constA Nothing)++mbGetQAttrValue :: (ArrowXml a) =>+ QName -> a XmlTree (Maybe String)+mbGetQAttrValue qn =+ (getQAttrValue qn >>> notNullA >>> arr Just)+ `orElse` (constA Nothing)+++{- ePub parsing helpers++ Note that these URIs could conceivably change in the future+ Is it ok that they're hardcoded like this?++ Well, ok, the xml namespace URI will probably never change.+-}++dcName, opfName, xmlName :: String -> QName+dcName local = mkQName "dc" local "http://purl.org/dc/elements/1.1/"+opfName local = mkQName "opf" local "http://www.idpf.org/2007/opf"+xmlName local = mkQName "xml" local "http://www.w3.org/XML/1998/namespace"+++getPackage :: (ArrowXml a) => a (NTree XNode) (String, String)+getPackage = atTag "package" >>>+ proc x -> do+ v <- getAttrValue "version" -< x+ u <- getAttrValue "unique-identifier" -< x+ returnA -< (v, u)+++getTitle :: (ArrowXml a) => a (NTree XNode) MetaTitle+getTitle = atQTag (dcName "title") >>>+ proc x -> do+ l <- mbGetQAttrValue (xmlName "lang") -< x+ c <- text -< x+ returnA -< MetaTitle l c+++{- Since creators and contributors have the same exact XML structure,+ this arrow is used to get either of them+-}+getCreator :: (ArrowXml a) => String -> a (NTree XNode) MetaCreator+getCreator tag = atQTag (dcName tag) >>> ( unwrapArrow $ MetaCreator+ <$> (WrapArrow $ mbGetQAttrValue (opfName "role"))+ <*> (WrapArrow $ mbGetQAttrValue (opfName "file-as"))+ <*> (WrapArrow $ text)+ )+++getSubject :: (ArrowXml a) => a (NTree XNode) String+getSubject = atQTag (dcName "subject") >>> text+++getDescription :: (ArrowXml a) => a (NTree XNode) (Maybe String)+getDescription = mbQTagText $ dcName "description"+++getPublisher :: (ArrowXml a) => a (NTree XNode) (Maybe String)+getPublisher = mbQTagText $ dcName "publisher"+++getDate :: (ArrowXml a) => a (NTree XNode) MetaDate+getDate = atQTag (dcName "date") >>>+ proc x -> do+ e <- mbGetQAttrValue (opfName "event") -< x+ c <- text -< x+ returnA -< MetaDate e c+++getType :: (ArrowXml a) => a (NTree XNode) (Maybe String)+getType = mbQTagText $ dcName "type"+++getFormat :: (ArrowXml a) => a (NTree XNode) (Maybe String)+getFormat = mbQTagText $ dcName "format"+++getId :: (ArrowXml a) => a (NTree XNode) MetaId+getId = atQTag (dcName "identifier") >>>+ proc x -> do+ mbi <- mbGetAttrValue "id" -< x+ s <- mbGetQAttrValue (opfName "scheme") -< x+ c <- text -< x+ let i = maybe "[WARNING: missing required id attribute]" id mbi+ returnA -< MetaId i s c+++getSource :: (ArrowXml a) => a (NTree XNode) (Maybe String)+getSource = mbQTagText $ dcName "source"+++getLang :: (ArrowXml a) => a (NTree XNode) String+getLang = atQTag (dcName "language") >>> text+++getRelation :: (ArrowXml a) => a (NTree XNode) (Maybe String)+getRelation = mbQTagText $ dcName "relation"+++getCoverage :: (ArrowXml a) => a (NTree XNode) (Maybe String)+getCoverage = mbQTagText $ dcName "coverage"+++getRights :: (ArrowXml a) => a (NTree XNode) (Maybe String)+getRights = mbQTagText $ dcName "rights"+++getMeta :: (ArrowXml a) => a (NTree XNode) Metadata+getMeta = atTag "metadata" >>> ( unwrapArrow $ Metadata+ <$> (WrapArrow $ listA getTitle)+ <*> (WrapArrow $ listA $ getCreator "creator")+ <*> (WrapArrow $ listA $ getCreator "contributor")+ <*> (WrapArrow $ listA getSubject)+ <*> (WrapArrow $ getDescription)+ <*> (WrapArrow $ getPublisher)+ <*> (WrapArrow $ listA getDate)+ <*> (WrapArrow $ getType)+ <*> (WrapArrow $ getFormat)+ <*> (WrapArrow $ listA getId)+ <*> (WrapArrow $ getSource)+ <*> (WrapArrow $ listA getLang)+ <*> (WrapArrow $ getRelation)+ <*> (WrapArrow $ getCoverage)+ <*> (WrapArrow $ getRights)+ )+++getManifestItem :: (ArrowXml a) => a (NTree XNode) ManifestItem+getManifestItem = atTag "item" >>>+ proc x -> do+ i <- getAttrValue "id" -< x+ h <- getAttrValue "href" -< x+ m <- getAttrValue "media-type" -< x+ returnA -< ManifestItem i h m+++getManifest :: (ArrowXml a) => a (NTree XNode) [ManifestItem]+getManifest = atTag "manifest" >>>+ proc x -> do+ l <- listA getManifestItem -< x+ returnA -< l+++getSpineItemref :: (ArrowXml a) => a (NTree XNode) SpineItemref+getSpineItemref = atTag "itemref" >>>+ proc x -> do+ i <- getAttrValue "idref" -< x+ ml <- mbGetAttrValue "linear" -< x+ let l = maybe Nothing (\v -> if v == "no" then Just False else Just True) ml+ returnA -< SpineItemref i l+++getSpine :: (ArrowXml a) => a (NTree XNode) Spine+getSpine = atTag "spine" >>>+ proc x -> do+ i <- getAttrValue "toc" -< x+ l <- listA getSpineItemref -< x+ returnA -< (Spine i l)+++getGuideRef :: (ArrowXml a) => a (NTree XNode) GuideRef+getGuideRef = atTag "reference" >>>+ proc x -> do+ t <- getAttrValue "type" -< x+ mt <- mbGetAttrValue "title" -< x+ h <- getAttrValue "href" -< x+ returnA -< GuideRef t mt h+++getGuide :: (ArrowXml a) => a (NTree XNode) [GuideRef]+getGuide = atTag "guide" >>>+ proc x -> do+ l <- listA getGuideRef -< x+ returnA -< l+++getBookData :: (ArrowXml a) => a (NTree XNode) Package+getBookData = + proc x -> do+ (v, u) <- getPackage -< x+ m <- getMeta -< x+ mf <- getManifest -< x+ sp <- getSpine -< x+ gl <- listA getGuide -< x+ let g = case gl of+ [] -> []+ [e] -> e+ _ -> error "ERROR: more than one guide entries" + returnA -< (Package v u m mf sp g)+++{- | Extract the ePub OPF Package data contained in the supplied + XML string+-}+parseXmlToOpf :: (MonadIO m) => String -> m [Package]+parseXmlToOpf opfContents =+ liftIO $ runX (+ readString [withValidate no] opfContents+ >>> propagateNamespaces+ >>> getBookData+ )+++-- | Given the path to an ePub file, extract the OPF Package data+parseEpubOpf :: (MonadIO m, MonadError String m) =>+ FilePath -> m Package+parseEpubOpf zipPath = do+ opfContents <- extractFileFromZip zipPath =<< opfPath zipPath+ result <- parseXmlToOpf opfContents++ case result of+ (em : []) -> return em+ _ -> throwError+ "ERROR: Parse didn't result in a single document metadata"
− src/Codec/Epub/Opf/epub-meta.hs
@@ -1,24 +0,0 @@--- Copyright: 2010 Dino Morelli--- License: BSD3 (see LICENSE)--- Author: Dino Morelli <dino@ui3.info>--import Control.Monad.Error-import System.Environment ( getArgs )-import System.Exit--import Codec.Epub.Opf.Metadata.Format-import Codec.Epub.Opf.Metadata.Parse---main :: IO ()-main = do- as <- getArgs-- when (length as /= 1) $ do- putStrLn "usage: epub-meta EPUBFILE"- exitWith $ ExitFailure 1-- let zipPath = head as- result <- runErrorT $ parseEpubOpf zipPath-- putStr $ either (++ "\n") opfToString result
testsuite/runtests.hs view
@@ -1,4 +1,4 @@--- Copyright: 2010 Dino Morelli+-- Copyright: 2010, 2011 Dino Morelli -- License: BSD3 (see LICENSE) -- Author: Dino Morelli <dino@ui3.info> @@ -6,8 +6,8 @@ import Test.HUnit ( Counts, Test (..), assertEqual, runTestTT ) import Test.HUnit.Base ( Assertion ) -import Codec.Epub.Opf.Metadata-import Codec.Epub.Opf.Metadata.Parse+import Codec.Epub.Opf.Package+import Codec.Epub.Opf.Parse main = runTestTT tests >> return ()@@ -28,55 +28,97 @@ testFull = TestCase $ do xmlString <- readFile $ "testsuite" </> "testFull.opf" actual <- parseXmlToOpf xmlString- let expected = [ OPFPackage "2.0" "isbn" ( EpubMeta- { emTitles =- [ EMTitle Nothing "Title Of This Book"- , EMTitle (Just "fr") "Titre De Ce Livre"- ]- , emCreators =- [ EMCreator- (Just "aut")- (Just "Wiggins, Josephine B.")- "Josephine B. Wiggins"- , EMCreator- (Just "aut")- Nothing- "Horatio Cromwell"- , EMCreator- Nothing- Nothing- "Natalia Jenkins"- ]- , emContributors =- [ EMCreator- (Just "ill")- (Just "Knickerbocker, Reginald Q.")- "Reginald Q. Knickerbocker"- , EMCreator- (Just "edt")- Nothing- "Beverly Abercrombie"- ]- , emSubjects = ["Fiction", "Science Fiction"]- , emDescription = Just "This document is a stub used for unit testing. It is missing the rest of the tags that normally occur after metadata."- , emPublisher = Just "Fictional Books Ltd."- , emDates =- [ EMDate (Just "published") "2010"- , EMDate (Just "created") "2010-05-07"- , EMDate (Just "modified") "2010-05-08T10:20:57"- , EMDate Nothing "2009-08-03T16:22:20"- ]- , emType = Just "test OPF Package Document"- , emFormat = Just "ePub publication"- , emIds =- [ EMId "isbn" (Just "ISBN") "1-82057-821-9"- , EMId "other" Nothing "1386506873266"]- , emSource = Just "document source"- , emLangs = ["en-us"]- , emRelation = Just "document relation"- , emCoverage = Just "coverage information"- , emRights = Just "Copyright: 2010 Dino Morelli, License: BSD3"- } ) ]+ let expected =+ [ Package+ { opVersion = "2.0"+ , opUniqueId = "isbn"+ , opMeta = Metadata+ { metaTitles =+ [ MetaTitle Nothing "Title Of This Book"+ , MetaTitle (Just "fr") "Titre De Ce Livre"+ ]+ , metaCreators = + [ MetaCreator+ (Just "aut")+ (Just "Wiggins, Josephine B.")+ "Josephine B. Wiggins"+ , MetaCreator+ (Just "aut")+ Nothing+ "Horatio Cromwell"+ , MetaCreator+ Nothing+ Nothing+ "Natalia Jenkins"+ ]+ , metaContributors = + [ MetaCreator + (Just "ill") + (Just "Knickerbocker, Reginald Q.") + "Reginald Q. Knickerbocker"+ , MetaCreator + (Just "edt") + Nothing "Beverly Abercrombie"+ ]+ , metaSubjects = ["Fiction","Science Fiction"]+ , metaDescription = Just "This document is a stub used for unit testing. It is missing the rest of the tags that normally occur after metadata."+ , metaPublisher = Just "Fictional Books Ltd."+ , metaDates = + [ MetaDate (Just "published") "2010"+ , MetaDate (Just "created") "2010-05-07"+ , MetaDate (Just "modified") "2010-05-08T10:20:57"+ , MetaDate Nothing "2009"+ ]+ , metaType = Just "test OPF Package Document"+ , metaFormat = Just "ePub publication"+ , metaIds = + [ MetaId "isbn" (Just "ISBN") "1-82057-821-9"+ , MetaId "other" Nothing "1386506873266"+ ]+ , metaSource = Just "document source"+ , metaLangs = ["en-us"]+ , metaRelation = Just "document relation"+ , metaCoverage = Just "coverage information"+ , metaRights = Just "Copyright: 2010 Dino Morelli, License: BSD3"+ }+ , opManifest = + [ ManifestItem + { mfiId = "ncx"+ , mfiHref = "toc.ncx"+ , mfiMediaType = "application/x-dtbncx+xml"+ }+ , ManifestItem + { mfiId = "titlePage"+ , mfiHref = "content/titlePage.html"+ , mfiMediaType = "application/xhtml+xml"+ }+ , ManifestItem + { mfiId = "someContent"+ , mfiHref = "content/someContent.html"+ , mfiMediaType = "application/xhtml+xml"+ }+ ]+ , opSpine = Spine+ { spineToc = "ncx"+ , spineItemrefs = + [ SpineItemref {siIdRef = "titlePage", siLinear = Nothing}+ , SpineItemref {siIdRef = "someContent", siLinear = Nothing}+ ]+ }+ , opGuide = + [ GuideRef + { grType = "title-page"+ , grTitle = Just "Title page"+ , grHref = "content/titlePage.html"+ }+ , GuideRef + { grType = "text"+ , grTitle = Just "Title Of This Book"+ , grHref = "content/someContent.html"+ }+ ]+ }+ ] assertEqual "very full" expected actual @@ -87,23 +129,38 @@ testMinimal = TestCase $ do xmlString <- readFile $ "testsuite" </> "testMinimal.opf" actual <- parseXmlToOpf xmlString- let expected = [ OPFPackage "2.0" "isbn" ( EpubMeta- { emTitles = [EMTitle Nothing "Title Of This Book"]- , emCreators = []- , emContributors = []- , emSubjects = []- , emDescription = Nothing- , emPublisher = Nothing- , emDates = []- , emType = Nothing- , emFormat = Nothing- , emIds = [EMId "isbn" (Just "ISBN") "1-82057-821-9"]- , emSource = Nothing- , emLangs = ["en-us"]- , emRelation = Nothing- , emCoverage = Nothing- , emRights = Nothing- } ) ]+ let expected = + [ Package + { opVersion = "2.0"+ , opUniqueId = "isbn"+ , opMeta = Metadata + { metaTitles = [MetaTitle Nothing "Title Of This Book"]+ , metaCreators = []+ , metaContributors = []+ , metaSubjects = []+ , metaDescription = Nothing+ , metaPublisher = Nothing+ , metaDates = []+ , metaType = Nothing+ , metaFormat = Nothing+ , metaIds = [MetaId "isbn" (Just "ISBN") "1-82057-821-9"]+ , metaSource = Nothing+ , metaLangs = ["en-us"]+ , metaRelation = Nothing+ , metaCoverage = Nothing+ , metaRights = Nothing+ }+ , opManifest = + [ ManifestItem + { mfiId = "ncx"+ , mfiHref = "toc.ncx"+ , mfiMediaType = "application/x-dtbncx+xml"+ }+ ]+ , opSpine = Spine {spineToc = "ncx", spineItemrefs = []}+ , opGuide = []+ }+ ] assertEqual "minimal" expected actual @@ -114,5 +171,14 @@ testMissingAll = TestCase $ do xmlString <- readFile $ "testsuite" </> "testMissingAll.opf" actual <- parseXmlToOpf xmlString- let expected = [ OPFPackage "" "" emptyEpubMeta ]+ let expected =+ [ Package + { opVersion = ""+ , opUniqueId = ""+ , opMeta = emptyMetadata+ , opManifest = []+ , opSpine = Spine {spineToc = "", spineItemrefs = []}+ , opGuide = []+ }+ ] assertEqual "missing all" expected actual
testsuite/testFull.opf view
@@ -19,7 +19,7 @@ <dc:date opf:event="published">2010</dc:date> <dc:date opf:event="created">2010-05-07</dc:date> <dc:date opf:event="modified">2010-05-08T10:20:57</dc:date>- <dc:date>2009-08-03T16:22:20</dc:date>+ <dc:date>2009</dc:date> <dc:language>en-us</dc:language> <dc:publisher>Fictional Books Ltd.</dc:publisher> <dc:identifier id="other">1386506873266</dc:identifier>@@ -31,9 +31,30 @@ <dc:relation>document relation</dc:relation> <dc:coverage>coverage information</dc:coverage> <dc:rights>Copyright: 2010 Dino Morelli, License: BSD3</dc:rights>- <meta name="series_index" content="1"/> </metadata> - <!-- This document is a stub used for unit testing. It is missing - the rest of the tags that normally occur after metadata -->+ <manifest>+ <item id="ncx"+ href="toc.ncx"+ media-type="application/x-dtbncx+xml" />+ <item id="titlePage"+ href="content/titlePage.html"+ media-type="application/xhtml+xml" />+ <item id="someContent"+ href="content/someContent.html"+ media-type="application/xhtml+xml" />+ </manifest>++ <spine toc="ncx">+ <itemref idref="titlePage" />+ <itemref idref="someContent" />+ </spine>++ <guide>+ <reference type="title-page" title="Title page"+ href="content/titlePage.html" />+ <reference type="text" title="Title Of This Book"+ href="content/someContent.html" />+ </guide>+ </package>
testsuite/testMinimal.opf view
@@ -12,6 +12,13 @@ <dc:language>en-us</dc:language> </metadata> - <!-- This document is a stub used for unit testing. It is missing - the rest of the tags that normally occur after metadata -->+ <manifest>+ <item id="ncx"+ href="toc.ncx"+ media-type="application/x-dtbncx+xml" />+ </manifest>++ <spine toc="ncx">+ </spine>+ </package>
testsuite/testMissingAll.opf view
@@ -6,6 +6,10 @@ xmlns:xml="http://www.w3.org/XML/1998/namespace"> </metadata> - <!-- This document is a stub used for unit testing. It is missing - the rest of the tags that normally occur after metadata -->+ <manifest>+ </manifest>++ <spine>+ </spine>+ </package>
+ util/show-opf.hs view
@@ -0,0 +1,13 @@+#! /usr/bin/runhaskell -isrc++-- Copyright: 2010, 2011 Dino Morelli+-- License: BSD3 (see LICENSE)+-- Author: Dino Morelli <dino@ui3.info>++import System.Environment ( getArgs )++import Codec.Epub.Opf.Parse+++main :: IO ()+main = (fmap head) getArgs >>= readFile >>= parseXmlToOpf >>= print