packages feed

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 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