{-# LANGUAGE TypeSynonymInstances, FlexibleInstances, PatternGuards #-}
module Text.HTML.TagSoup(
Tag(..), Row, Column, Attribute,
module Text.HTML.TagSoup.Parser,
module Text.HTML.TagSoup.Render,
canonicalizeTags,
isTagOpen, isTagClose, isTagText, isTagWarning, isTagPosition,
isTagOpenName, isTagCloseName, isTagComment,
fromTagText, fromAttrib,
maybeTagText, maybeTagWarning,
innerText,
sections, partitions,
TagRep(..), (~==),(~/=)
) where
import Text.HTML.TagSoup.Type
import Text.HTML.TagSoup.Parser
import Text.HTML.TagSoup.Render
import Data.Char
import Data.List (groupBy, tails)
import Text.StringLike
canonicalizeTags :: StringLike str => [Tag str] -> [Tag str]
canonicalizeTags = map f
where
f (TagOpen tag attrs) | Just ('!',name) <- uncons tag = TagOpen ('!' `cons` ucase name) attrs
f (TagOpen name attrs) = TagOpen (lcase name) [(lcase k, v) | (k,v) <- attrs]
f (TagClose name) = TagClose (lcase name)
f a = a
ucase = fromString . map toUpper . toString
lcase = fromString . map toLower . toString
class TagRep a where
toTagRep :: StringLike str => a -> Tag str
instance StringLike str => TagRep (Tag str) where toTagRep = fmap castString
instance TagRep String where
toTagRep x = case parseTags x of
[a] -> toTagRep a
_ -> error $ "When using a TagRep it must be exactly one tag, you gave: " ++ x
(~==) :: (StringLike str, TagRep t) => Tag str -> t -> Bool
(~==) a b = f a (toTagRep b)
where
f (TagText y) (TagText x) = strNull x || x == y
f (TagClose y) (TagClose x) = strNull x || x == y
f (TagOpen y ys) (TagOpen x xs) = (strNull x || x == y) && all g xs
where
g (name,val) | strNull name = val `elem` map snd ys
| strNull val = name `elem` map fst ys
g nameval = nameval `elem` ys
f (TagComment x) (TagComment y) = strNull x || x == y
f (TagWarning x) (TagWarning y) = strNull x || x == y
f (TagPosition x1 x2) (TagPosition y1 y2) = x1 == y1 && x2 == y2
f _ _ = False
(~/=) :: (StringLike str, TagRep t) => Tag str -> t -> Bool
(~/=) a b = not (a ~== b)
sections :: (a -> Bool) -> [a] -> [[a]]
sections p = filter (p . head) . init . tails
partitions :: (a -> Bool) -> [a] -> [[a]]
partitions p =
let notp = not . p
in groupBy (const notp) . dropWhile notp