v2 / vlib / encoding / xml / encoding.v
177 lines · 158 sloc · 4.89 KB · 76579f865b6a12e0c816877c8480f4a9dae698c1
Raw
1module xml
2
3import strings
4
5fn write_indent(mut builder strings.Builder, indent string, depth int) {
6 for _ in 0 .. depth {
7 builder.write_string(indent)
8 }
9}
10
11fn write_pretty_xml_node(mut builder strings.Builder, node XMLNode, original_indent string, depth int, reverse_entities map[string]string) {
12 write_indent(mut builder, original_indent, depth)
13 builder.write_u8(`<`)
14 builder.write_string(node.name)
15
16 for key, value in node.attributes {
17 builder.write_u8(` `)
18 builder.write_string(key)
19 builder.write_string('="')
20 builder.write_string(value)
21 builder.write_u8(`"`)
22 }
23 if node.children.len > 0 {
24 builder.write_string('>\n')
25 for child in node.children {
26 match child {
27 string {
28 write_indent(mut builder, original_indent, depth + 1)
29 builder.write_string(escape_text(child, reverse_entities: reverse_entities))
30 }
31 XMLNode {
32 write_pretty_xml_node(mut builder, child, original_indent, depth + 1,
33 reverse_entities)
34 }
35 XMLComment {
36 write_indent(mut builder, original_indent, depth + 1)
37 builder.write_string('<!--')
38 builder.write_string(child.text)
39 builder.write_string('-->')
40 }
41 XMLCData {
42 write_indent(mut builder, original_indent, depth + 1)
43 builder.write_string('<![CDATA[')
44 builder.write_string(child.text)
45 builder.write_string(']]>')
46 }
47 }
48
49 builder.write_u8(`\n`)
50 }
51 write_indent(mut builder, original_indent, depth)
52 builder.write_string('</')
53 builder.write_string(node.name)
54 builder.write_u8(`>`)
55 } else {
56 builder.write_string('/>')
57 }
58}
59
60fn write_pretty_dtd_list(mut builder strings.Builder, list []DTDListItem, indent string) bool {
61 if list.len == 0 {
62 return false
63 }
64
65 builder.write_u8(`[`)
66 builder.write_u8(`\n`)
67
68 for item in list {
69 match item {
70 DTDEntity {
71 builder.write_string(indent)
72 builder.write_string('<!ENTITY ')
73 builder.write_string(item.name)
74 builder.write_string(' "')
75 builder.write_string(item.value)
76 builder.write_string('">')
77 }
78 DTDElement {
79 builder.write_string(indent)
80 builder.write_string('<!ELEMENT ')
81 builder.write_string(item.name)
82 builder.write_string(' [')
83 builder.write_string(item.definition.join(', '))
84 builder.write_string(']>')
85 }
86 }
87
88 builder.write_u8(`\n`)
89 }
90 builder.write_u8(`]`)
91 return true
92}
93
94fn write_pretty_doctype(mut builder strings.Builder, doctype DocumentType, indent string) bool {
95 match doctype.dtd {
96 string {
97 content := doctype.dtd
98 if content.len == 0 {
99 return false
100 }
101 builder.write_string('<!DOCTYPE ')
102 builder.write_string(doctype.name)
103 builder.write_string(' SYSTEM ')
104 builder.write_string(content)
105 builder.write_string('>\n')
106 return true
107 }
108 DocumentTypeDefinition {
109 if doctype.dtd.list.len == 0 {
110 return false
111 }
112
113 builder.write_string('<!DOCTYPE ')
114 builder.write_string(doctype.name)
115 builder.write_string(' ')
116 write_pretty_dtd_list(mut builder, doctype.dtd.list, indent)
117 builder.write_string('>\n')
118 return true
119 }
120 }
121}
122
123// pretty_str returns a pretty-printed version of the XML node. It requires the current indentation
124// the node is at, the depth of the node in the tree, and a map of reverse entities to use when
125// escaping text.
126pub fn (node XMLNode) pretty_str(original_indent string, depth int, reverse_entities map[string]string) string {
127 mut builder := strings.new_builder(1024)
128 write_pretty_xml_node(mut builder, node, original_indent, depth, reverse_entities)
129 return builder.str()
130}
131
132fn (list []DTDListItem) pretty_str(indent string) string {
133 mut builder := strings.new_builder(1024)
134 if !write_pretty_dtd_list(mut builder, list, indent) {
135 return ''
136 }
137 return builder.str()
138}
139
140fn (doctype DocumentType) pretty_str(indent string) string {
141 mut builder := strings.new_builder(1024)
142 if !write_pretty_doctype(mut builder, doctype, indent) {
143 return ''
144 }
145 return builder.str()
146}
147
148// pretty_str returns a pretty-printed version of the XML document. It requires the string used to
149// indent each level of the document.
150pub fn (doc XMLDocument) pretty_str(indent string) string {
151 mut document_builder := strings.new_builder(1024)
152
153 document_builder.write_string('<?xml version="')
154 document_builder.write_string(doc.version)
155 document_builder.write_string('" encoding="')
156 document_builder.write_string(doc.encoding)
157 document_builder.write_string('"?>\n')
158
159 if write_pretty_doctype(mut document_builder, doc.doctype, indent) {
160 document_builder.write_u8(`\n`)
161 }
162 for comment in doc.comments {
163 document_builder.write_string('<!--')
164 document_builder.write_string(comment.text)
165 document_builder.write_string('-->')
166 document_builder.write_u8(`\n`)
167 }
168 write_pretty_xml_node(mut document_builder, doc.root, indent, 0, doc.parsed_reverse_entities)
169
170 return document_builder.str()
171}
172
173// str returns a string representation of the XML document. It uses a 2-space indentation
174// to pretty-print the document.
175pub fn (doc XMLDocument) str() string {
176 return doc.pretty_str(' ')
177}
178