{-# LANGUAGE Rank2Types, FlexibleInstances, TypeSynonymInstances, MultiParamTypeClasses #-} import qualified Text.XML.Expat.IO as EIO import Text.XML.Expat.Tree as ETree import Text.XML.Expat.Pickle import Text.XML.Expat.Format import Data.Tree import qualified Data.ByteString.Lazy as B import qualified Data.ByteString.Internal as B (w2c) 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 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 Node (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 (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 $ xp4Tuple (xpAttr "lang" xpText0) (xpOption $ xpAttr "text" xpText0) (xpOption $ xpAttr "time" xpText0) xpText0 data LanguageKey k => MultiLanguage k = MultiLanguage { texts :: [MultiText k] } deriving (Eq, Show) nullMultiLanguage :: LanguageKey k => MultiLanguage k nullMultiLanguage = MultiLanguage [] instance XmlPickler Node (MultiLanguage SiteLanguageKey) where xpickle = xpMultiLanguage "text" xpMultiLanguage :: LanguageKey k => String -> PU (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 Node Mnemonic where xpickle = xpMnemonic xpMnemonic :: PU Mnemonic xpMnemonic = xpElem "mnemonic" $ xpMnemonicAttrs xpMnemonicAttrs :: PU Mnemonic xpMnemonicAttrs = xpWrap ( (\(mne, cat, com, tex, lin) -> 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, tex, liftM ((fromMaybe "" . stripPrefix "category.") . keyValue) lin)) ) $ xp5Tuple (xpAttr "name" xpText0) (xpAttr "category" xpText0) (xpOption $ xpAttr "comment" $ xpText0) (xpMultiLanguage "text") (xpOption $ xpAttr "link" $ xpText) main_eio doc = do parser <- EIO.newParser Nothing EIO.setStartElementHandler parser startElement EIO.parse parser doc -- True putStrLn "ok" where startElement name attrs = putStrLn $ show name ++ " " ++ show attrs main_tree doc = do start <- getCurrentTime let mTree = ETree.parse Nothing doc --putStrLn $ show mTree case mTree of Just tree -> do let pickler = xpElem "mnemonics" $ xpList xpMnemonic let eMnems = unpickleTree pickler tree case eMnems of Right mnems -> do --putStrLn $ show mnems let pickled = pickleTree pickler mnems out = formatDocS (Just UTF8) pickled "\n" --putStrLn $ show pickled --putStrLn $ out let xml = map B.w2c (B.unpack doc) if out == xml 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 - mismatch:" putStr out Left error -> do hPutStrLn stderr $ "FAILED: "++error Nothing -> return () main = do xml <- B.readFile "test.xml" main_tree xml