{-# LANGUAGE OverloadedStrings #-}
module Main(main) where
import Text.XML.Hexml as X
import qualified Data.ByteString.Char8 as BS
import Control.Monad
import Data.Monoid
import Data.Char
examples :: [(Bool, BS.ByteString)]
examples =
[(True, "herethere")
,(True, "")
,(True, "")
,(True, "here more text at the end")
,(False, "")
,(False, "\nHello, world!")
]
main :: IO ()
main = do
forM_ examples $ \(parses, src) -> do
print src
case parse src of
Left err -> when parses $ fail $ "Unexpected parse failure, " ++ show err
Right doc -> do
unless parses $ fail "Unexpected parse success"
let r = render doc
print r
print $ rerender doc
when (r /= rerender doc) $ fail "Different rerender"
let Right d = parse r
when (r /= render d) $ fail "Different after rerendering"
let Right doc = parse ""
map name (children doc) === ["test","test","b","test","test"]
length (childrenBy doc "test") === 4
length (childrenBy doc "b") === 1
length (childrenBy doc "extra") === 0
attributes (head $ children doc) === [Attribute "id" "1", Attribute "extra" "2"]
map (`attributeBy` "id") (childrenBy doc "test") === map (fmap (Attribute "id")) [Just "1", Just "2", Just "4", Nothing]
Right _ <- return $ parse $ " BS.unwords [BS.pack $ "x" ++ show i ++ "='value'" | i <- [1..10000]] <> " />"
return ()
a === b = if a == b then putStrLn "success" else fail "mismatch"
rerender :: Node -> BS.ByteString
rerender = inside
where
inside x = BS.concat $ map (either validStr node) $ contents x
node x = "<" <> BS.unwords (validName (name x) : map attr (attributes x)) <> ">" <>
inside x <>
"" <> name x <> ">"
attr (Attribute a b) = validName a <> "=\"" <> validAttr b <> "\""
validName x | BS.all (\x -> isAlphaNum x || x `elem` ("-:_" :: String)) x = x
| otherwise = error "Invalid name"
validAttr x | BS.notElem '\"' x = x
| otherwise = error "Invalid attribute"
validStr x | BS.notElem '<' x || BS.isInfixOf "