{-# LANGUAGE MultiParamTypeClasses, TypeSynonymInstances, FlexibleInstances #-}
import Text.XML.Expat.Tree
import Text.XML.Expat.Pickle
import Text.XML.Expat.Format
import Data.Tree
import qualified Data.ByteString as B
import qualified Data.ByteString.Lazy as L
import Data.ByteString.Internal (w2c, c2w)
import Control.Monad
import Data.Maybe
import Data.Either
import Data.List
import Data.Char
import Debug.Trace
import Data.Time.Clock
import Numeric
import System.IO
import Data.Monoid
class Key k where
keyValue :: k -> String
class Key k => LanguageKey k where
isoOf :: k -> String
makeLanguageKey :: String -> k
data MnemonicKey = MnemonicKey String
deriving Show
instance Key MnemonicKey where
keyValue (MnemonicKey str) = str
data LanguageKey k => MultiText k = MultiText {
lang :: k,
languageText :: String,
timestamp :: Integer
}
deriving (Eq, Show)
instance LanguageKey k => XmlPickler (UNodes String) (MultiText k) where
xpickle = xpMultiText "text"
data SiteLanguageKey = SiteLanguageKey String
deriving Show
instance Key SiteLanguageKey where
keyValue (SiteLanguageKey a) = a
instance LanguageKey SiteLanguageKey where
isoOf = keyValue
makeLanguageKey str = SiteLanguageKey str
maybeRead :: Read a => String -> Maybe a
maybeRead s = case reads s of
[(x, "")] -> Just x
_ -> Nothing
xpMultiText :: LanguageKey k => String -> PU (UNodes String) (MultiText k)
xpMultiText tagName =
xpWrap (
(\((lan, tex1, tim), tex2) -> MultiText
(makeLanguageKey lan)
(if tex2 /= "" then tex2 else fromMaybe "" tex1)
(truncate $ fromMaybe 0 ((maybeRead (fromMaybe "0" tim))::Maybe Float))),
(\(MultiText lan tex tim) -> ((isoOf lan, Nothing, Just $ show tim), tex))
) $
xpElem tagName
(xpTriple
(xpAttr "lang" xpText0)
(xpOption $ xpAttr "text" xpText0)
(xpOption $ xpAttr "time" xpText0))
(xpContent xpText0)
data LanguageKey k => MultiLanguage k = MultiLanguage {
texts :: [MultiText k]
}
deriving (Eq, Show)
nullMultiLanguage :: LanguageKey k => MultiLanguage k
nullMultiLanguage = MultiLanguage []
instance XmlPickler (UNodes String) (MultiLanguage SiteLanguageKey) where
xpickle = xpMultiLanguage "text"
xpMultiLanguage :: LanguageKey k => String -> PU (UNodes String) (MultiLanguage k)
xpMultiLanguage childTagName =
xpWrap (
(\ts -> MultiLanguage ts),
(\(MultiLanguage ts) -> ts)
) $
xpList (xpMultiText childTagName)
data Mnemonic = Mnemonic {
mnemonicKey :: MnemonicKey,
category :: String,
comment :: String,
multiLanguage :: MultiLanguage SiteLanguageKey,
linkTo :: Maybe MnemonicKey
}
deriving (Show)
instance XmlPickler (UNodes String) Mnemonic where
xpickle = xpMnemonic
xpMnemonic :: PU (UNodes String) Mnemonic
xpMnemonic =
xpWrap (
(\((mne, cat, com, lin), tex) ->
Mnemonic (MnemonicKey mne) cat (fromMaybe "" com) tex
(liftM (MnemonicKey . ("category."++)) lin)),
(\(Mnemonic (MnemonicKey mne) cat com tex lin) ->
((mne, cat, if com == "" then Nothing else Just com,
liftM ((fromMaybe "" . stripPrefix "category.") . keyValue) lin), tex))
) $
xpElem "mnemonic"
(xp4Tuple
(xpAttr "name" xpText0)
(xpAttr "category" xpText0)
(xpOption $ xpAttr "comment" $ xpText0)
(xpOption $ xpAttr "link" $ xpText))
(xpMultiLanguage "text")
main_tree doc = do
start <- getCurrentTime
let pickler = xpRoot $ xpElemNodes "mnemonics" $ xpList xpMnemonic
case unpickleXML' Nothing pickler doc of
Right mnems -> do
let xml = mconcat . L.toChunks $ pickleXML pickler mnems `mappend` L.pack (map c2w "\n")
if xml == doc
then do
let mnems = unpickleXML Nothing pickler $ L.fromChunks [doc]
xml = mconcat . L.toChunks $ pickleXML pickler mnems `mappend` L.pack (map c2w "\n")
if xml == doc
then do
end <- getCurrentTime
let took = end `diffUTCTime` start
hPutStrLn stderr $ "passed"
hPutStrLn stderr $ "took "++showFFloat (Just 3) (realToFrac took) ""++" sec"
else do
hPutStrLn stderr $ "Failed test 2 - mismatch:"
B.putStr xml
else do
hPutStrLn stderr $ "Failed test 1 - mismatch:"
B.putStr xml
Left error -> do
hPutStrLn stderr $ "FAILED: "++error
main = do
xml <- B.readFile "test.xml"
main_tree xml