1 // Copyright 2016 Charles Banning. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file
4 5 package mxj
6 7 import (
8 "bytes"
9 )
10 11 var xmlEscapeChars bool
12 13 // XMLEscapeChars(true) forces escaping invalid characters in attribute and element values.
14 // NOTE: this is brute force with NO interrogation of '&' being escaped already; if it is
15 // then '&' will be re-escaped as '&'.
16 //
17 /*
18 The values are:
19 " "
20 ' '
21 < <
22 > >
23 & &
24 */
25 //
26 // Note: if XMLEscapeCharsDecoder(true) has been called - or the default, 'false,' value
27 // has been toggled to 'true' - then XMLEscapeChars(true) is ignored. If XMLEscapeChars(true)
28 // has already been called before XMLEscapeCharsDecoder(true), XMLEscapeChars(false) is called
29 // to turn escape encoding on mv.Xml, etc., to prevent double escaping ampersands, '&'.
30 func XMLEscapeChars(b ...bool) {
31 var bb bool
32 if len(b) == 0 {
33 bb = !xmlEscapeChars
34 } else {
35 bb = b[0]
36 }
37 if bb == true && xmlEscapeCharsDecoder == false {
38 xmlEscapeChars = true
39 } else {
40 xmlEscapeChars = false
41 }
42 }
43 44 // Scan for '&' first, since 's' may contain "&" that is parsed to "&amp;"
45 // - or "<" that is parsed to "&lt;".
46 var escapechars = [][2][]byte{
47 {[]byte(`&`), []byte(`&`)},
48 {[]byte(`<`), []byte(`<`)},
49 {[]byte(`>`), []byte(`>`)},
50 {[]byte(`"`), []byte(`"`)},
51 {[]byte(`'`), []byte(`'`)},
52 }
53 54 func escapeChars(s string) string {
55 if len(s) == 0 {
56 return s
57 }
58 59 b := []byte(s)
60 for _, v := range escapechars {
61 n := bytes.Count(b, v[0])
62 if n == 0 {
63 continue
64 }
65 b = bytes.Replace(b, v[0], v[1], n)
66 }
67 return string(b)
68 }
69 70 // per issue #84, escape CharData values from xml.Decoder
71 72 var xmlEscapeCharsDecoder bool
73 74 // XMLEscapeCharsDecoder(b ...bool) escapes XML characters in xml.CharData values
75 // returned by Decoder.Token. Thus, the internal Map values will contain escaped
76 // values, and you do not need to set XMLEscapeChars for proper encoding.
77 //
78 // By default, the Map values have the non-escaped values returned by Decoder.Token.
79 // XMLEscapeCharsDecoder(true) - or, XMLEscapeCharsDecoder() - will toggle escape
80 // encoding 'on.'
81 //
82 // Note: if XMLEscapeCharDecoder(true) is call then XMLEscapeChars(false) is
83 // called to prevent re-escaping the values on encoding using mv.Xml, etc.
84 func XMLEscapeCharsDecoder(b ...bool) {
85 if len(b) == 0 {
86 xmlEscapeCharsDecoder = !xmlEscapeCharsDecoder
87 } else {
88 xmlEscapeCharsDecoder = b[0]
89 }
90 if xmlEscapeCharsDecoder == true && xmlEscapeChars == true {
91 xmlEscapeChars = false
92 }
93 }
94