{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE DeriveGeneric #-} module Codec.Xlsx.Types.Internal.CustomProperties where import Data.Map (Map) import qualified Data.Map as M import Data.Text (Text) import GHC.Generics (Generic) import Text.XML import Text.XML.Cursor import Codec.Xlsx.Parser.Internal import Codec.Xlsx.Types.Variant import Codec.Xlsx.Writer.Internal newtype CustomProperties = CustomProperties (Map Text Variant) deriving (Eq, Show, Generic) fromList :: [(Text, Variant)] -> CustomProperties fromList = CustomProperties . M.fromList empty :: CustomProperties empty = CustomProperties M.empty {------------------------------------------------------------------------------- Parsing -------------------------------------------------------------------------------} instance FromCursor CustomProperties where fromCursor cur = do let items = cur $/ element (cpr"property") >=> parseCustomPropertyEntry return (fromList items) parseCustomPropertyEntry :: Cursor -> [(Text, Variant)] parseCustomPropertyEntry cur = do name <- attribute "name" cur value <- cur $/ anyElement >=> fromCursor return (name, value) -- | Add custom properties namespace to name cpr :: Text -> Name cpr x = Name { nameLocalName = x , nameNamespace = Just custPropNs , namePrefix = Nothing } custPropNs :: Text custPropNs = "http://schemas.openxmlformats.org/officeDocument/2006/custom-properties" {------------------------------------------------------------------------------- Rendering -------------------------------------------------------------------------------} instance ToDocument CustomProperties where toDocument = documentFromNsElement "Custom properties generated by xlsx" "http://schemas.openxmlformats.org/officeDocument/2006/custom-properties" . toElement "Properties" instance ToElement CustomProperties where toElement nm (CustomProperties m) = Element { elementName = nm , elementAttributes = M.empty , elementNodes = map (NodeElement . toElement "property" . CustomProperty) . zip [2..] $ M.toList m } newtype CustomProperty = CustomProperty (Int, (Text, Variant)) instance ToElement CustomProperty where toElement nm (CustomProperty (i, (key, val))) = Element { elementName = nm , elementAttributes = M.fromList [ "name" .= key , "fmtid" .= userDefinedFmtID , "pid" .= txti i ] , elementNodes = [ NodeElement $ variantToElement val ] } -- | FMTID_UserDefinedProperties userDefinedFmtID :: Text userDefinedFmtID = "{D5CDD505-2E9C-101B-9397-08002B2CF9AE}"