From 2bc0c777914dff525d793c8e9b174b373b27e6e8 Mon Sep 17 00:00:00 2001 From: Jesse Rosenthal Date: Wed, 2 Jul 2014 16:52:39 -0400 Subject: Docx Reader: Parse omml equations. --- src/Text/Pandoc/Readers/Docx/Parse.hs | 344 +++++++++++++++++++++++++++++++++- 1 file changed, 336 insertions(+), 8 deletions(-) (limited to 'src') diff --git a/src/Text/Pandoc/Readers/Docx/Parse.hs b/src/Text/Pandoc/Readers/Docx/Parse.hs index 537c5c272..44585b016 100644 --- a/src/Text/Pandoc/Readers/Docx/Parse.hs +++ b/src/Text/Pandoc/Readers/Docx/Parse.hs @@ -1,3 +1,5 @@ +{-# LANGUAGE PatternGuards #-} + {- Copyright (C) 2014 Jesse Rosenthal @@ -35,6 +37,15 @@ module Text.Pandoc.Readers.Docx.Parse ( Docx(..) , BodyPart(..) , TblLook(..) , ParPart(..) + , OMath(..) + , OMathElem(..) + , Base(..) + , TopBottom(..) + , AccentStyle(..) + , BarStyle(..) + , NAryStyle(..) + , DelimStyle(..) + , GroupStyle(..) , Run(..) , RunElem(..) , Notes @@ -288,15 +299,30 @@ elemToNumInfo _ _ = Nothing elemToBodyPart :: NameSpaces -> Element -> Maybe BodyPart elemToBodyPart ns element + | qName (elName element) == "p" && + qURI (elName element) == (lookup "w" ns) + , (c:_) <- findChildren (QName "oMathPara" (lookup "m" ns) (Just "m")) element = + let style = [] -- placeholder + maths = mapMaybe (elemToMath ns) + $ findChildren + (QName "oMath" (lookup "m" ns) (Just "m")) c + in + Just $ OMathPara style maths + | qName (elName element) == "p" && + qURI (elName element) == (lookup "w" ns) + , Just (numId, lvl) <- elemToNumInfo ns element = + let parstyle = elemToParagraphStyle ns element + parparts = mapMaybe (elemToParPart ns) + $ elChildren element + in + Just $ ListItem parstyle numId lvl parparts | qName (elName element) == "p" && qURI (elName element) == (lookup "w" ns) = let parstyle = elemToParagraphStyle ns element parparts = mapMaybe (elemToParPart ns) $ elChildren element in - case elemToNumInfo ns element of - Just (numId, lvl) -> Just $ ListItem parstyle numId lvl parparts - Nothing -> Just $ Paragraph parstyle parparts + Just $ Paragraph parstyle parparts | qName (elName element) == "tbl" && qURI (elName element) == (lookup "w" ns) = let @@ -392,7 +418,7 @@ elemToParagraphStyle ns element = data BodyPart = Paragraph ParagraphStyle [ParPart] | ListItem ParagraphStyle String String [ParPart] | Tbl String TblGrid TblLook [Row] - + | OMathPara OMathParaStyle [OMath] deriving Show type TblGrid = [Integer] @@ -451,6 +477,7 @@ data ParPart = PlainRun Run | InternalHyperLink Anchor [Run] | ExternalHyperLink RelId [Run] | Drawing String + | PlainOMath OMath deriving Show data Run = Run RunStyle [RunElem] @@ -458,6 +485,75 @@ data Run = Run RunStyle [RunElem] | Endnote String deriving Show +data OMath = OMath [OMathElem] + deriving Show + +data OMathElem = Accent AccentStyle Base + | Bar BarStyle Base + | Box Base + | BorderBox Base + | Delimiter DelimStyle [Base] + | EquationArray [Base] + | Fraction [OMathElem] [OMathElem] + | Function [OMathElem] Base + | Group GroupStyle Base + | LowerLimit Base [OMathElem] + | UpperLimit Base [OMathElem] + | Matrix [[Base]] + | NAry NAryStyle [OMathElem] [OMathElem] Base + | Phantom Base + | Radical [OMathElem] Base + | PreSubSuper [OMathElem] [OMathElem] Base + | Sub Base [OMathElem] + | SubSuper Base [OMathElem] [OMathElem] + | Super Base [OMathElem] + | OMathRun OMathRunStyle Run + deriving Show + +data Base = Base [OMathElem] + deriving Show + +-- placeholders +type OMathParaStyle = [String] + +data TopBottom = Top | Bottom + deriving Show + +data AccentStyle = AccentStyle { accentChar :: Maybe Char } + deriving Show + +data BarStyle = BarStyle { barPos :: TopBottom} + deriving Show + +data NAryStyle = NAryStyle { nAryChar :: Maybe Char + , nAryLimLoc :: LimLoc} + deriving Show + +defaultNAryStyle :: NAryStyle +defaultNAryStyle = NAryStyle { nAryChar = Nothing -- integral, in practice + , nAryLimLoc = SubSup } + +data LimLoc = SubSup | UnderOver deriving Show + +data DelimStyle = DelimStyle { delimBegChar :: Maybe Char + , delimSepChar :: Maybe Char + , delimEndChar :: Maybe Char} + deriving Show + +defaultDelimStyle :: DelimStyle +defaultDelimStyle = DelimStyle { delimBegChar = Nothing + , delimSepChar = Nothing + , delimEndChar = Nothing } + +data GroupStyle = GroupStyle { groupChr :: Maybe Char + , groupPos :: Maybe TopBottom } + deriving Show + +defaultGroupStyle :: GroupStyle +defaultGroupStyle = GroupStyle {groupChr = Nothing, groupPos = Nothing} + +type OMathRunStyle = [String] + data RunElem = TextRun String | LnBrk | Tab deriving Show @@ -532,13 +628,13 @@ elemToRun _ _ = Nothing elemToRunElem :: NameSpaces -> Element -> Maybe RunElem elemToRunElem ns element | (qName (elName element) == "t" || qName (elName element) == "delText") && - qURI (elName element) == (lookup "w" ns) = + qURI (elName element) `elem` [(lookup "w" ns), (lookup "m" ns)] = Just $ TextRun (strContent element) | qName (elName element) == "br" && - qURI (elName element) == (lookup "w" ns) = + qURI (elName element) `elem` [(lookup "w" ns), (lookup "m" ns)] = Just $ LnBrk | qName (elName element) == "tab" && - qURI (elName element) == (lookup "w" ns) = + qURI (elName element) `elem` [(lookup "w" ns), (lookup "m" ns)] = Just $ Tab | otherwise = Nothing @@ -546,7 +642,7 @@ elemToRunElem ns element elemToRunElems :: NameSpaces -> Element -> [RunElem] elemToRunElems ns element | qName (elName element) == "r" && - qURI (elName element) == (lookup "w" ns) = + qURI (elName element) `elem` [(lookup "w" ns), (lookup "m" ns)] = mapMaybe (elemToRunElem ns) (elChildren element) | otherwise = [] @@ -561,7 +657,233 @@ elemToDrawing ns element >>= (\s -> Just $ Drawing s) elemToDrawing _ _ = Nothing +elemToMath :: NameSpaces -> Element -> Maybe OMath +elemToMath ns element + | qName (elName element) == "oMath" && + qURI (elName element) == (lookup "m" ns) = + Just $ OMath $ mapMaybe (elemToMathElem ns) (elChildren element) +elemToMath _ _ = Nothing + + + +elemToBase :: NameSpaces -> Element -> Maybe Base +elemToBase ns element + | qName (elName element) == "e" && + qURI (elName element) == (lookup "m" ns) = + Just $ Base $ mapMaybe (elemToMathElem ns) (elChildren element) +elemToBase _ _ = Nothing + +elemToNAryStyle :: NameSpaces -> Element -> NAryStyle +elemToNAryStyle ns element + | Just narypr <- findChild (QName "naryPr" (lookup "m" ns) (Just "m")) element = + let + chr = findChild (QName "chr" (lookup "m" ns) (Just "m")) narypr >>= + findAttr (QName "val" (lookup "m" ns) (Just "m")) >>= + Just . head + limLoc = findChild (QName "limLoc" (lookup "m" ns) (Just "m")) narypr >>= + findAttr (QName "val" (lookup "m" ns) (Just "m")) + limLoc' = case limLoc of + Just "undOver" -> UnderOver + Just "subSup" -> SubSup + _ -> SubSup + in + NAryStyle { nAryChar = chr, nAryLimLoc = limLoc'} +elemToNAryStyle _ _ = defaultNAryStyle + +elemToDelimStyle :: NameSpaces -> Element -> DelimStyle +elemToDelimStyle ns element + | Just dPr <- findChild (QName "dPr" (lookup "m" ns) (Just "m")) element = + let begChr = findChild (QName "begChr" (lookup "m" ns) (Just "m")) dPr >>= + findAttr (QName "val" (lookup "m" ns) (Just "m")) >>= + (\c -> if null c then Nothing else (Just $ head c)) + sepChr = findChild (QName "sepChr" (lookup "m" ns) (Just "m")) dPr >>= + findAttr (QName "val" (lookup "m" ns) (Just "m")) >>= + (\c -> if null c then Nothing else (Just $ head c)) + endChr = findChild (QName "endChr" (lookup "m" ns) (Just "m")) dPr >>= + findAttr (QName "val" (lookup "m" ns) (Just "m")) >>= + (\c -> if null c then Nothing else (Just $ head c)) + in + DelimStyle { delimBegChar = begChr + , delimSepChar = sepChr + , delimEndChar = endChr} +elemToDelimStyle _ _ = defaultDelimStyle + +elemToGroupStyle :: NameSpaces -> Element -> GroupStyle +elemToGroupStyle ns element + | Just gPr <- findChild (QName "groupChrPr" (lookup "m" ns) (Just "m")) element = + let chr = findChild (QName "chr" (lookup "m" ns) (Just "m")) gPr >>= + findAttr (QName "val" (lookup "m" ns) (Just "m")) >>= + Just . head + pos = findChild (QName "pos" (lookup "m" ns) (Just "m")) gPr >>= + findAttr (QName "val" (lookup "m" ns) (Just "m")) >>= + (\s -> Just $ if s == "top" then Top else Bottom) + in + GroupStyle { groupChr = chr, groupPos = pos } +elemToGroupStyle _ _ = defaultGroupStyle + +elemToMathElem :: NameSpaces -> Element -> Maybe OMathElem +elemToMathElem ns element + | qName (elName element) == "acc" && + qURI (elName element) == (lookup "m" ns) = do + let accChar = + findChild (QName "accPr" (lookup "m" ns) (Just "m")) element >>= + findChild (QName "chr" (lookup "m" ns) (Just "m")) >>= + findAttr (QName "val" (lookup "m" ns) (Just "m")) >>= + Just . head + accPr = AccentStyle { accentChar = accChar} + base <-findChild (QName "e" (lookup "m" ns) (Just "m")) element >>= + elemToBase ns + return $ Accent accPr base +elemToMathElem ns element + | qName (elName element) == "bar" && + qURI (elName element) == (lookup "m" ns) = do + barPr <- findChild (QName "barPr" (lookup "m" ns) (Just "m")) element >>= + findChild (QName "pos" (lookup "m" ns) (Just "m")) >>= + findAttr (QName "val" (lookup "m" ns) (Just "m")) >>= + (\s -> + Just $ BarStyle { + barPos = (if s == "bot" then Bottom else Top) + }) + base <-findChild (QName "e" (lookup "m" ns) (Just "m")) element >>= + elemToBase ns + return $ Bar barPr base +elemToMathElem ns element + | qName (elName element) == "box" && + qURI (elName element) == (lookup "m" ns) = + findChild (QName "e" (lookup "m" ns) (Just "m")) element >>= + elemToBase ns >>= + (\b -> Just $ Box b) +elemToMathElem ns element + | qName (elName element) == "borderBox" && + qURI (elName element) == (lookup "m" ns) = + findChild (QName "e" (lookup "m" ns) (Just "m")) element >>= + elemToBase ns >>= + (\b -> Just $ BorderBox b) +elemToMathElem ns element + | qName (elName element) == "d" && + qURI (elName element) == (lookup "m" ns) = + let style = elemToDelimStyle ns element + in + Just $ Delimiter style $ mapMaybe (elemToBase ns) (elChildren element) +elemToMathElem ns element + | qName (elName element) == "eqArr" && + qURI (elName element) == (lookup "m" ns) = + Just $ EquationArray + $ mapMaybe (elemToBase ns) (elChildren element) +elemToMathElem ns element + | qName (elName element) == "f" && + qURI (elName element) == (lookup "m" ns) = do + num <- findChild (QName "num" (lookup "m" ns) (Just "m")) element + den <- findChild (QName "den" (lookup "m" ns) (Just "m")) element + let numElems = mapMaybe (elemToMathElem ns) (elChildren num) + denElems = mapMaybe (elemToMathElem ns) (elChildren den) + return $ Fraction numElems denElems +elemToMathElem ns element + | qName (elName element) == "func" && + qURI (elName element) == (lookup "m" ns) = do + fName <- findChild (QName "fName" (lookup "m" ns) (Just "m")) element + base <- findChild (QName "e" (lookup "m" ns) (Just "m")) element >>= + elemToBase ns + let fnElems = mapMaybe (elemToMathElem ns) (elChildren fName) + return $ Function fnElems base +elemToMathElem ns element + | qName (elName element) == "groupChr" && + qURI (elName element) == (lookup "m" ns) = + let style = elemToGroupStyle ns element + in + findChild (QName "e" (lookup "m" ns) (Just "m")) element >>= + elemToBase ns >>= + (\b -> Just $ Group style b) +elemToMathElem ns element + | qName (elName element) == "limLow" && + qURI (elName element) == (lookup "m" ns) = do + base <- findChild (QName "e" (lookup "m" ns) (Just "m")) element + >>= elemToBase ns + lim <- findChild (QName "lim" (lookup "m" ns) (Just "m")) element + return $ LowerLimit base (mapMaybe (elemToMathElem ns) (elChildren lim)) +elemToMathElem ns element + | qName (elName element) == "limUpp" && + qURI (elName element) == (lookup "m" ns) = do + base <- findChild (QName "e" (lookup "m" ns) (Just "m")) element + >>= elemToBase ns + lim <- findChild (QName "lim" (lookup "m" ns) (Just "m")) element + return $ UpperLimit base (mapMaybe (elemToMathElem ns) (elChildren lim)) +elemToMathElem ns element + | qName (elName element) == "m" && + qURI (elName element) == (lookup "m" ns) = + let rows = findChildren (QName "mr" (lookup "m" ns) (Just "m")) element + bases = map (\mr -> mapMaybe (elemToBase ns) (elChildren mr)) rows + in + Just $ Matrix bases +elemToMathElem ns element + | qName (elName element) == "nary" && + qURI (elName element) == (lookup "m" ns) = do + let style = elemToNAryStyle ns element + sub <- findChild (QName "sub" (lookup "m" ns) (Just "m")) element >>= + (\e -> Just $ mapMaybe (elemToMathElem ns) (elChildren e)) + sup <- findChild (QName "sup" (lookup "m" ns) (Just "m")) element >>= + (\e -> Just $ mapMaybe (elemToMathElem ns) (elChildren e)) + base <- findChild (QName "e" (lookup "m" ns) (Just "m")) element >>= + elemToBase ns + return $ NAry style sub sup base +elemToMathElem ns element + | qName (elName element) == "rad" && + qURI (elName element) == (lookup "m" ns) = do + deg <- findChild (QName "deg" (lookup "m" ns) (Just "m")) element >>= + (\e -> Just $ mapMaybe (elemToMathElem ns) (elChildren e)) + base <- findChild (QName "e" (lookup "m" ns) (Just "m")) element >>= + elemToBase ns + return $ Radical deg base +-- skipping for now: +-- phant +elemToMathElem ns element + | qName (elName element) == "sPre" && + qURI (elName element) == (lookup "m" ns) = do + sub <- findChild (QName "sub" (lookup "m" ns) (Just "m")) element >>= + (\e -> Just $ mapMaybe (elemToMathElem ns) (elChildren e)) + sup <- findChild (QName "sup" (lookup "m" ns) (Just "m")) element >>= + (\e -> Just $ mapMaybe (elemToMathElem ns) (elChildren e)) + base <- findChild (QName "e" (lookup "m" ns) (Just "m")) element >>= + elemToBase ns + return $ PreSubSuper sub sup base +elemToMathElem ns element + | qName (elName element) == "sSub" && + qURI (elName element) == (lookup "m" ns) = do + base <- findChild (QName "e" (lookup "m" ns) (Just "m")) element >>= + elemToBase ns + sub <- findChild (QName "sub" (lookup "m" ns) (Just "m")) element >>= + (\e -> Just $ mapMaybe (elemToMathElem ns) (elChildren e)) + return $ Sub base sub +elemToMathElem ns element + | qName (elName element) == "sSubSup" && + qURI (elName element) == (lookup "m" ns) = do + base <- findChild (QName "e" (lookup "m" ns) (Just "m")) element >>= + elemToBase ns + sub <- findChild (QName "sub" (lookup "m" ns) (Just "m")) element >>= + (\e -> Just $ mapMaybe (elemToMathElem ns) (elChildren e)) + sup <- findChild (QName "sup" (lookup "m" ns) (Just "m")) element >>= + (\e -> Just $ mapMaybe (elemToMathElem ns) (elChildren e)) + return $ SubSuper base sub sup +elemToMathElem ns element + | qName (elName element) == "sSup" && + qURI (elName element) == (lookup "m" ns) = do + base <- findChild (QName "e" (lookup "m" ns) (Just "m")) element >>= + elemToBase ns + sup <- findChild (QName "sup" (lookup "m" ns) (Just "m")) element >>= + (\e -> Just $ mapMaybe (elemToMathElem ns) (elChildren e)) + return $ Super base sup +elemToMathElem ns element + | qName (elName element) == "r" && + qURI (elName element) == (lookup "m" ns) = + let style = [] -- placeholder + rstyle = elemToRunStyle ns element + relems = elemToRunElems ns element + in + Just $ OMathRun style $ Run rstyle relems +elemToMathElem _ _ = Nothing + + elemToParPart :: NameSpaces -> Element -> Maybe ParPart elemToParPart ns element | qName (elName element) == "r" && @@ -606,8 +928,14 @@ elemToParPart ns element case findAttr (QName "id" (lookup "r" ns) (Just "r")) element of Just relId -> Just $ ExternalHyperLink relId runs Nothing -> Nothing +elemToParPart ns element + | qName (elName element) == "oMath" && + qURI (elName element) == (lookup "m" ns) = + elemToMath ns element >>= + (\m -> Just $ PlainOMath m) elemToParPart _ _ = Nothing + type Target = String type Anchor = String type BookMarkId = String -- cgit v1.2.3