-
Notifications
You must be signed in to change notification settings - Fork 0
/
Writer.hs
211 lines (192 loc) · 7.26 KB
/
Writer.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
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
{-# LANGUAGE OverloadedStrings #-}
module Writer (toXml) where
import Prelude
import qualified Data.List
import qualified Data.Text as DT
import qualified Parser as P
xml_declaration, xml_closer :: DT.Text
xml_declaration = "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<xml>"
xml_closer = "</xml>"
{- | Turns branches into raw XML, so that from then on, we can use
XSLT instead of linear parsing.
Filters the input tree by the shape of the passed-in limitations.
See Writer.filter.
Input parameters:
1. The list of branches returned by P.toTree.
2.1 EndId specifies which person or family got targeted
by the user, and needs to be formatted to stand out.
2.2 AndThis specifies additional nodes that got targeted
by the user, and need to be formatted differently.
2.3 MaxDepth is not used.
-}
toXml :: [P.Branch] -> (P.EndId, P.AndThis, P.MaxDepth) -> [DT.Text]
toXml [] _ = [xml_declaration, xml_closer]
toXml [x] (e, a, _) = xml_declaration
: ((branchToXml e a) x)
: xml_closer : []
toXml xs (e, a, _) = xml_declaration
: xmltexts ++ [xml_closer] where
xmltexts = fmap (branchToXml e a) xs
{- | Translates a property type into a tag name. -}
tag :: P.PropertyType -> DT.Text
tag (P.UnknownPropertyType) = "unknown-type"
tag (P.NodeIdentifierProperty _) = "id"
tag (P.ValuedProperty name)
| name == "CHAR" = "charset"
| name == "CORP" = "corporation"
| name == "PROB" = "probate"
| name == "TITL" = "title"
| name == "_FREL" = "relation-to-father"
| name == "_MREL" = "relation-to-mother"
| name == "PLAC" = "place"
| name == "RESI" = "residence"
| name == "SEX" = "sexe"
| name == "VERS" = "version"
| otherwise = DT.toLower name
tag (P.PlaceCategoryProperty name)
| name == P.BirthPlace = "birth"
| name == P.DeathPlace = "death"
| name == P.BurialPlace = "burial"
| otherwise = "unknown-place-type"
tag (P.EmptyProperty name)
| name == "HEAD" = "head"
| name == "DATA" = "data"
| name == "DIV" = "division"
| name == "MARR" = "marriage"
| name == "_MILT" = "military"
| name == "OBJE" = "object"
| name == "PROB" = "prob"
| name == "TRLR" = "trailer"
| otherwise = DT.toLower name
tag (P.ReferenceProperty name)
| name == "CHIL" = "child"
| name == "FAMC" = "parents"
| name == "FAMS" = "own-family"
| name == "HUSB" = "spouse"
| name == "REPO" = "repository"
| name == "SOUR" = "source"
| name == "WIFE" = "spouse"
| otherwise = "unknown-ref-type"
{- | Converts a raw & into the html entity & -}
amp :: DT.Text -> DT.Text
amp v = DT.replace "&amp;" "&" (DT.replace "&" "&" v)
{- | Converts a raw < into the html entity < -}
lt :: DT.Text -> DT.Text
lt v = DT.replace "&lt;" "<" (DT.replace "<" "<" v)
{- | Converts a raw > into the html entity > -}
gt :: DT.Text -> DT.Text
gt v = DT.replace "&gt;" ">" (DT.replace ">" ">" v)
{- | Removes the @ from values. -}
noAt :: DT.Text -> DT.Text
noAt v = DT.replace "@" "" v
{- | Removes the / from values. -}
noSlash :: DT.Text -> DT.Text
noSlash v = DT.replace "/" "" v
{- | Substitutes common characters -}
sub :: DT.Text -> DT.Text
sub "" = ""
sub v
| "@" == (DT.take 1 v) = noAt v
| otherwise = amp $ lt $ gt v
{- | Finds the correct tag for the property type and
wraps it in < and >. -}
startTag :: P.PropertyType -> DT.Text
startTag t = DT.intercalate (tag t) ["<", ">"]
{- | Finds the correct tag for the property type and
wraps it in </ and >. -}
endTag :: P.PropertyType -> DT.Text
endTag t = DT.intercalate (tag t) ["</", ">"]
{- | Turns a single leaf into a single raw xml element -}
leafToXml :: P.Leaf -> DT.Text
leafToXml (P.Leaf t v []) = DT.intercalate (sub v) [
startTag t,
endTag t
]
leafToXml (P.Leaf t v children) = DT.intercalate "" [
startTag t,
sub v,
(DT.intercalate "" (fmap leafToXml children)),
endTag t
]
{- | Turns a single person leaf into a single raw xml element -}
personLeafToXml :: P.Leaf -> DT.Text
personLeafToXml (P.Leaf t v [])
| t == P.p_name = DT.intercalate (noSlash $ sub v) [
"<name>",
"</name>"
]
| otherwise = DT.intercalate (sub v) [
startTag t,
endTag t
]
personLeafToXml (P.Leaf t v children)
| t == P.p_name = DT.intercalate "" [
"<name>",
noSlash $ sub v,
(DT.intercalate "" (fmap personLeafToXml children)),
"</name>"
]
| otherwise = DT.intercalate "" [
startTag t,
sub v,
(DT.intercalate "" (fmap personLeafToXml children)),
endTag t
]
{- | Figure out which formatting hints to add. -}
addFormatHints :: P.EndId -> P.AndThis -> P.Branch -> DT.Text
addFormatHints _ _ (P.Branch _ []) = ""
addFormatHints e a (P.Branch P.FamilyNode l)
= DT.concat [e', a'] where
e' = case e == P.getLeafId (P.findFamilyLeaf l) of
True -> "<endNode/>"
False -> ""
a' = case Data.List.any (P.matchAndThisLeaf a) l of
True -> "<andThisNode/>"
False -> ""
addFormatHints e a (P.Branch P.PersonNode l)
= DT.concat [e', a'] where
e' = case e == P.getLeafId (P.findPersonLeaf l) of
True -> "<endNode/>"
False -> ""
a' = case Data.List.any (P.matchAndThisLeaf a) l of
True -> "<andThisNode/>"
False -> ""
addFormatHints _ a (P.Branch _ l) = a' where
a' = case Data.List.any (P.matchAndThisLeaf a) l of
True -> "<andThisNode/>"
False -> ""
{- | Turns a single branch into a single raw xml element. -}
branchToXml :: P.EndId -> P.AndThis -> P.Branch -> DT.Text
branchToXml _ _ (P.Branch P.HeaderNode leaves) = DT.intercalate (DT.concat (fmap leafToXml leaves)) [
"<header>",
"</header>\n"
]
branchToXml _ _ (P.Branch P.TrailerNode leaves) = DT.intercalate (DT.concat (fmap leafToXml leaves)) [
"<trailer>",
"</trailer>\n"
]
branchToXml e a (P.Branch P.SourceNode leaves) = DT.intercalate (DT.concat (fmap leafToXml leaves)) [
DT.concat ["<source>", f],
"</source>\n"
] where
f = addFormatHints e a (P.Branch P.SourceNode leaves)
branchToXml e a (P.Branch P.FamilyNode leaves) = DT.intercalate (DT.concat (fmap leafToXml leaves)) [
DT.concat ["<family>", f],
"</family>\n"
] where
f = addFormatHints e a (P.Branch P.FamilyNode leaves)
branchToXml e a (P.Branch P.PersonNode leaves) = DT.intercalate (DT.concat (fmap personLeafToXml leaves)) [
DT.concat ["<person>", f],
"</person>\n"
] where
f = addFormatHints e a (P.Branch P.PersonNode leaves)
branchToXml e a (P.Branch P.RepositoryNode leaves) = DT.intercalate (DT.concat (fmap leafToXml leaves)) [
DT.concat ["<repository>", f],
"</repository>\n"
] where
f = addFormatHints e a (P.Branch P.RepositoryNode leaves)
branchToXml e a (P.Branch P.UnknownNodeType leaves) = DT.intercalate (DT.concat (fmap leafToXml leaves)) [
DT.concat ["<unknown-node>", f],
"</unknown-node>\n"
] where
f = addFormatHints e a (P.Branch P.UnknownNodeType leaves)