module Ideas.Text.MathML
( MathML(..), xml2mathml, mathml2xml
) where
import Data.Either
import Data.Maybe
import Ideas.Text.XML
import Ideas.Utils.Uniplate hiding (children)
data MathML = MRow [MathML]
| MId String
| MNumber String
| MOperator String
| MString String
| MText String
| MSqrt MathML
| MRoot MathML MathML
| MSup MathML MathML
| MSub MathML MathML
| MSubSup MathML MathML MathML
| MFrac MathML MathML
| MFenced String String MathML
| MSpace
| MStyle
| MPadded
| MPhantom
| MError
| MEnclose
| MUnder
| MOver
| MUnderOver
| MTable
| MTableRow
| MLabeledTableRow
| MTableData
deriving (Show, Eq)
instance InXML MathML where
toXML = mathml2xml
fromXML = either fail return . xml2mathml
instance Uniplate MathML where
uniplate math =
case math of
MRow xs -> plate MRow ||* xs
_ -> plate math
xml2mathml :: XML -> Either String MathML
xml2mathml = rec
where
rec xml = case xml of
Element "mrow" _ _ -> MRow <$> mapM rec (children xml)
Element "mi" _ [Left s] -> return (MId s)
Element "mn" _ [Left s] -> return (MNumber s)
Element "mo" _ [Left s] -> return (MOperator s)
Element "ms" _ [Left s] -> return (MString s)
Element "mtext" _ [] -> return (MText "")
Element "mtext" _ [Left s] -> return (MText s)
Element "mroot" _ [Right c, Right d] -> MRoot <$> rec c <*> rec d
Element "msup" _ [Right c, Right d] -> MSup <$> rec c <*> rec d
Element "msub" _ [Right c, Right d] -> MSub <$> rec c <*> rec d
Element "msubsup" _ [Right c, Right d, Right e] -> MSubSup <$> rec c <*> rec d <*> rec e
Element "mfrac" _ [Right c, Right d] -> MFrac <$> rec c <*> rec d
Element "mfenced" _ [Right c] -> MFenced (fromMaybe "(" (findAttribute "open" xml)) (fromMaybe ")" (findAttribute "close" xml)) <$> rec c
Element "mspace" _ _ -> return MSpace
Element "mtable" _ _ -> return MTable
Element "mtr" _ _ -> return MTableRow
Element "mlabeledtr" _ _ -> return MLabeledTableRow
Element "munder" _ _ -> return MUnder
Element "mover" _ _ -> return MOver
Element "munderover" _ _ -> return MUnderOver
Element "math" _ xs -> impliedMRow xs
Element "msqrt" _ xs -> MSqrt <$> impliedMRow xs
Element "mphantom" _ _ -> return MPhantom
Element "mpadded" _ _ -> return MPadded
Element "mstyle" _ _ -> return MStyle
Element "merror" _ _ -> return MError
Element "mtd" _ _ -> return MTableData
Element "menclose" _ _ -> return MEnclose
_ -> fail ("unsupported MathML: " ++ show xml)
impliedMRow :: [Either String Element] -> Either String MathML
impliedMRow [Right r] = rec r
impliedMRow xs = MRow <$> mapM rec (rights xs)
mathml2xml :: MathML -> XML
mathml2xml = makeXML "math" . rec
where
rec :: MathML -> XMLBuilder
rec math =
case math of
MRow ms -> element "mrow" (map rec ms)
MId s -> element "mi" [string s]
MNumber s -> element "mn" [string s]
MOperator s -> element "mo" [string s]
MString s -> element "ms" [string s]
MText s -> element "mtext" [string s]
MSqrt m -> element "msqrt" [rec m]
MRoot m1 m2 -> element "mroot" [rec m1, rec m2]
MSup m1 m2 -> element "msup" [rec m1, rec m2]
MSub m1 m2 -> element "msub" [rec m1, rec m2]
MSubSup m1 m2 m3 -> element "msubsup" [rec m1, rec m2, rec m3]
MFrac m1 m2 -> element "mfrac" [rec m1, rec m2]
MFenced s1 s2 m -> element "mfenced" ["open" .=. s1, "close" .=. s2, rec m]
MSpace -> element "mspace" []
MStyle -> element "mstyle" []
MPadded -> element "mpadded" []
MPhantom -> element "mphantom" []
MError -> element "merror" []
MEnclose -> element "menclose" []
MUnder -> element "munder" []
MOver -> element "mover" []
MUnderOver -> element "munderover" []
MTable -> element "mtable" []
MTableRow -> element "mtr" []
MLabeledTableRow -> element "mlabeledtr" []
MTableData -> element "mtd" []