escapechars.go 2.5 KB

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