+92
src/xmleam/xml_builder.gleam
+92
src/xmleam/xml_builder.gleam
···
1
+
////Goals for this module:
2
+
//// 1. make xml like the string_builder
3
+
//// ie. xml_builder.new()
4
+
//// |> xml_builder.block_tag("name", {
5
+
//// xml_builder.new()
6
+
//// |> xml_builder.tag("hello", "world")
7
+
//// |> xml_builder.tag("maybe", "here")})
8
+
//// |> xml_builder.option_tag("link", Opt.("href", "https://example.com"))
9
+
//// To:
10
+
//// <?xml version="1.0" encoding="UTF-8" xml?>
11
+
//// <name>
12
+
//// <hello> world </hello>
13
+
//// </name>
14
+
15
+
import gleam/string_builder
16
+
import gleam/string
17
+
import gleam/result
18
+
import gleam/bool
19
+
20
+
pub type BuilderError {
21
+
ContentsEmpty
22
+
TagNameEmpty
23
+
OptionsEmpty
24
+
VersionEmpty
25
+
EncodingEmpty
26
+
TagPlacedBeforeNew
27
+
}
28
+
29
+
pub type XmlBuilder =
30
+
Result(string_builder.StringBuilder, BuilderError)
31
+
32
+
/// this function starts the builder and
33
+
/// this function assumes version 1.0 and encoding UTF-8 if you need specific verisons or encoding
34
+
/// use new_advanced_document(version, encoding)
35
+
pub fn new_document() -> XmlBuilder {
36
+
string_builder.new()
37
+
|> string_builder.append("<?xml version=\"1.0\" encoding=\"UTF-8\"?>")
38
+
|> Ok
39
+
}
40
+
41
+
/// this funcion starts the builder and
42
+
/// allows you to put in your own version and encoding
43
+
pub fn new_advanced_document(version: String, encoding: String) -> XmlBuilder {
44
+
let version_empty = string.is_empty(version)
45
+
use <- bool.guard(when: version_empty, return: Error(VersionEmpty))
46
+
let encoding_empty = string.is_empty(encoding)
47
+
use <- bool.guard(when: encoding_empty, return: Error(EncodingEmpty))
48
+
49
+
string_builder.new()
50
+
|> string_builder.append("<?xml version=\"")
51
+
|> string_builder.append(version)
52
+
|> string_builder.append("\" encoding=\"")
53
+
|> string_builder.append(encoding)
54
+
|> string_builder.append("\"?> \n")
55
+
|> Ok
56
+
}
57
+
58
+
/// this function starts the blocks inside of tags
59
+
pub fn new() -> XmlBuilder {
60
+
string_builder.new()
61
+
|> Ok
62
+
}
63
+
64
+
/// this is a basic tag that takes in a label and contents and a
65
+
/// document in the form of an XmlBuilder
66
+
/// this is intended to be used in a pipe chain
67
+
/// ie. new_document()
68
+
/// |> tag("hello", "world")
69
+
/// Throws an error if anything is left blank
70
+
pub fn tag(label: String, contents: String, document: XmlBuilder) -> XmlBuilder {
71
+
let label_empty = string.is_empty(label)
72
+
use <- bool.guard(when: label_empty, return: Error(TagNameEmpty))
73
+
let contents_empty = string.is_empty(contents)
74
+
use <- bool.guard(when: contents_empty, return: Error(ContentsEmpty))
75
+
let documents_empty =
76
+
string_builder.is_empty(result.unwrap(document, string_builder.new()))
77
+
use <- bool.guard(when: documents_empty, return: Error(TagPlacedBeforeNew))
78
+
79
+
string_builder.new()
80
+
|> string_builder.append("<")
81
+
|> string_builder.append(label)
82
+
|> string_builder.append("> ")
83
+
|> string_builder.append(contents)
84
+
|> string_builder.append(" </")
85
+
|> string_builder.append(label)
86
+
|> string_builder.append("> \n")
87
+
|> string_builder.append_builder(to: result.unwrap(
88
+
document,
89
+
string_builder.new(),
90
+
))
91
+
|> Ok
92
+
}