v2 / vlib / encoding / xml / entity.v
82 lines · 72 sloc · 1.94 KB · 8e35f4d9848f7ad35d857a187dddbfd2eca5e19d
Raw
1module xml
2
3import strings
4
5pub const default_entities = {
6 'lt': '<'
7 'gt': '>'
8 'amp': '&'
9 'apos': "'"
10 'quot': '"'
11}
12
13pub const default_entities_reverse = {
14 '<': 'lt'
15 '>': 'gt'
16 '&': 'amp'
17 "'": 'apos'
18 '"': 'quot'
19}
20
21@[params]
22pub struct EscapeConfig {
23pub:
24 reverse_entities map[string]string = default_entities_reverse
25}
26
27// escape_text replaces all entities in the given string with their respective
28// XML entity strings. See default_entities, which can be overridden.
29pub fn escape_text(content string, config EscapeConfig) string {
30 mut flattened_entities := []string{cap: 2 * config.reverse_entities.len}
31
32 for target, replacement in config.reverse_entities {
33 flattened_entities << target
34 flattened_entities << '&' + replacement + ';'
35 }
36
37 return content.replace_each(flattened_entities)
38}
39
40@[params]
41pub struct UnescapeConfig {
42pub:
43 entities map[string]string = default_entities
44}
45
46// unescape_text replaces all entities in the given string with their respective
47// original characters or strings. See default_entities_reverse, which can be overridden.
48pub fn unescape_text(content string, config UnescapeConfig) !string {
49 mut buffer := strings.new_builder(content.len)
50 mut index := 0
51 runes := content.runes()
52 for index < runes.len {
53 match runes[index] {
54 `&` {
55 mut offset := 1
56 mut entity_buf := strings.new_builder(8)
57 for index + offset < runes.len && runes[index + offset] != `;` {
58 entity_buf.write_rune(runes[index + offset])
59 offset++
60 }
61 // Did we reach the end of the string?
62 if index + offset == runes.len {
63 return error('Unexpected end of string while parsing entity.')
64 }
65 // Did we find a valid entity?
66 entity := entity_buf.str()
67 if entity in config.entities {
68 buffer.write_string(config.entities[entity])
69 index += offset
70 } else {
71 return error('Unknown entity: ' + entity)
72 }
73 }
74 else {
75 buffer.write_rune(runes[index])
76 }
77 }
78
79 index++
80 }
81 return buffer.str()
82}
83