-
Notifications
You must be signed in to change notification settings - Fork 0
/
XML.hs
95 lines (84 loc) · 1.89 KB
/
XML.hs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
{-# LANGUAGE InstanceSigs #-}
module XML
( parseXML,
xToString,
XValue (..),
)
where
import qualified Control.Applicative as A
import qualified Data.Char as C
import qualified Shared as S
data XValue
= XTag String [(String, String)] [XValue]
| XText String
deriving (Eq, Ord)
xToString :: XValue -> String
xToString (XTag n [] []) =
"<"
++ n
++ ">"
++ "</"
++ n
++ ">"
xToString (XTag n a []) =
"<"
++ n
++ " "
++ showAttributes a
++ ">"
++ "</"
++ n
++ ">"
xToString (XTag n [] c) =
"<"
++ n
++ ">"
++ showChildren c
++ "</"
++ n
++ ">"
xToString (XTag n a c) =
"<"
++ n
++ " "
++ showAttributes a
++ ">"
++ showChildren c
++ "</"
++ n
++ ">"
xToString (XText t) = t
instance Show XValue where
show :: XValue -> String
show = xToString
showAttributes :: [(String, String)] -> String
showAttributes [] = ""
showAttributes [(k, v)] = k ++ "=\"" ++ v ++ "\""
showAttributes ((k, v) : xs) = k ++ "=\"" ++ v ++ "\" " ++ showAttributes xs
showChildren :: [XValue] -> String
showChildren [] = ""
showChildren [x] = show x
showChildren (x : xs) = show x ++ showChildren xs
xTag :: S.Parser String XValue
xTag = do
_ <- S.char '<'
n <- A.some (S.matches C.isAlphaNum)
a <- A.many $ do
k <- S.spaces *> A.some (S.matches C.isAlphaNum)
_ <- S.spaces *> S.char '='
_ <- S.spaces *> S.char '"'
v <- A.many (S.matches (/= '"'))
_ <- S.char '"' <* S.spaces
pure (k, v)
_ <- S.char '>'
c <- S.tabs *> A.many (xTag A.<|> xText) <* S.tabs
_ <- S.string "</" *> S.string n <* S.char '>' <* S.tabs
pure $ XTag n a c
xText :: S.Parser String XValue
xText = XText <$> A.some (S.matches (/= '<'))
xValue :: S.Parser String XValue
xValue = xTag A.<|> xText
parseXML :: String -> Maybe XValue
parseXML s = case S.parse xValue $ S.toTab s of
Just ("", x) -> Just x
_ -> Nothing