{-# LANGUAGE OverloadedStrings #-} -- | Bindings from `xml-conduit` to `haskell-stylist`. module Data.HTML2CSS( html2css, -- parsing el2styletree, els2stylist, el2stylist -- application ) where import qualified Data.List as L import qualified Data.Map as M import qualified Data.Text as Txt import Data.Maybe import qualified Text.XML as XML import Stylist.Parse import Stylist import Stylist.Tree import Data.CSS.Syntax.Tokens import Network.URI ---- Parsing -- | Converts a parsed XML or HTML file to a `ConditionalStyles` `StyleSheet`. html2css :: StyleSheet s => XML.Document -> URI -> s -> s html2css xml url self = html2css' (XML.documentRoot xml) url self html2css' :: StyleSheet s => XML.Element -> URI -> s -> s html2css' (XML.Element (XML.Name "style" _ _) attrs children) url self | M.lookup "type" attrs `notElem` [Nothing, Just "text/css"] = self -- Unsupported stylesheet. | Just media <- "media" `M.lookup` attrs = fst $ addAtRule self "media" (tokenize media ++ LeftCurlyBracket : tokContent url children ++ [RightCurlyBracket]) | otherwise = parseForURL self url $ strContent children html2css' (XML.Element (XML.Name "link" _ _) attrs _) baseURL self | M.lookup "type" attrs `elem` [Nothing, Just "text/css"], Just "stylesheet" <- "rel" `M.lookup` attrs, Just link <- "href" `M.lookup` attrs, Just url <- parseURIReference $ Txt.unpack link = fst $ addAtRule self "import" ( Url (Txt.pack $ uriToString' $ relativeTo url baseURL) : fromMaybe [] (tokenize <$> M.lookup "media" attrs) ++ [Semicolon]) html2css' (XML.Element _ _ children) url self = L.foldl' (\s el -> html2css' el url s) self [el | XML.NodeElement el <- children] strContent :: [XML.Node] -> Txt.Text strContent (XML.NodeContent text : rest) = text `Txt.append` strContent rest -- We do want to read in comments for CSS, just not for display. strContent (XML.NodeComment text : rest) = text `Txt.append` strContent rest strContent (XML.NodeElement (XML.Element _ _ children):rest) = strContent children `Txt.append` strContent rest strContent (_:rest) = strContent rest strContent [] = "" tokContent :: URI -> [XML.Node] -> [Token] tokContent baseURL = map absolutizeUrl . tokenize . strContent where absolutizeUrl (Url link) | Just url <- parseURIReference $ Txt.unpack link = Url $ Txt.pack $ uriToString' $ relativeTo url baseURL uriToString' uri = uriToString id uri "" ---- Styling el2styletree el = StyleTree (Left el) $ mapMaybe node2styletree $ XML.elementNodes el node2styletree (XML.NodeElement el) = Just $ el2styletree el node2styletree (XML.NodeContent txt) = Just $ StyleTree (Right [("content", [String txt])]) [] node2styletree _ = Nothing previous' (Just ElementNode {name = "", previous = prev'}) = previous' prev' previous' prev' = prev' els2stylist = preorder els2stylist' els2stylist' parent previous (Left (XML.Element (XML.Name name ns _) attrs _)) = ElementNode { name = name, namespace = fromMaybe "" ns, attributes = L.sort [ Attribute n (fromMaybe "" ns) $ Txt.unpack v | (XML.Name n ns _, v) <- M.toList attrs ], parent = parent, previous = previous' previous } els2stylist' parent previous (Right attrs) = ElementNode { name = "", namespace = "", attributes = [Attribute "style" "" $ Txt.unpack $ Txt.concat style], parent = parent, previous = previous' previous } where style = concat [[prop, ": ", serialize v, "; "] | (prop, v) <- attrs] el2stylist = els2stylist . el2styletree