plugins.go 3.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161
  1. package xml2json
  2. import (
  3. "strings"
  4. )
  5. type (
  6. // an plugin is added to an encoder or/and to an decoder to allow custom functionality at runtime
  7. plugin interface {
  8. AddToEncoder(*Encoder) *Encoder
  9. AddToDecoder(*Decoder) *Decoder
  10. }
  11. // a type converter overides the default string sanitization for encoding json
  12. encoderTypeConverter interface {
  13. Convert(string) string
  14. }
  15. // customTypeConverter converts strings to JSON types using a best guess approach, only parses the JSON types given
  16. // when initialized via WithTypeConverter
  17. customTypeConverter struct {
  18. parseTypes []JSType
  19. }
  20. attrPrefixer string
  21. contentPrefixer string
  22. excluder []string
  23. nodesFormatter struct {
  24. list []nodeFormatter
  25. }
  26. nodeFormatter struct {
  27. path string
  28. plugin nodePlugin
  29. }
  30. nodePlugin interface {
  31. AddTo(*Node)
  32. }
  33. arrayFormatter struct{}
  34. )
  35. // WithTypeConverter allows customized js type conversion behavior by passing in the desired JSTypes
  36. func WithTypeConverter(ts ...JSType) *customTypeConverter {
  37. return &customTypeConverter{parseTypes: ts}
  38. }
  39. func (tc *customTypeConverter) parseAsString(t JSType) bool {
  40. if t == String {
  41. return true
  42. }
  43. for i := 0; i < len(tc.parseTypes); i++ {
  44. if tc.parseTypes[i] == t {
  45. return false
  46. }
  47. }
  48. return true
  49. }
  50. // Adds the type converter to the encoder
  51. func (tc *customTypeConverter) AddToEncoder(e *Encoder) *Encoder {
  52. e.tc = tc
  53. return e
  54. }
  55. func (tc *customTypeConverter) AddToDecoder(d *Decoder) *Decoder {
  56. return d
  57. }
  58. func (tc *customTypeConverter) Convert(s string) string {
  59. // remove quotes if they exists
  60. if strings.HasPrefix(s, `"`) && strings.HasSuffix(s, `"`) {
  61. s = s[1 : len(s)-1]
  62. }
  63. jsType := Str2JSType(s)
  64. if tc.parseAsString(jsType) {
  65. // add the quotes removed at the start of this func
  66. s = `"` + s + `"`
  67. }
  68. return s
  69. }
  70. // WithAttrPrefix appends the given prefix to the json output of xml attribute fields to preserve namespaces
  71. func WithAttrPrefix(prefix string) *attrPrefixer {
  72. ap := attrPrefixer(prefix)
  73. return &ap
  74. }
  75. func (a *attrPrefixer) AddToEncoder(e *Encoder) *Encoder {
  76. e.attributePrefix = string((*a))
  77. return e
  78. }
  79. func (a *attrPrefixer) AddToDecoder(d *Decoder) *Decoder {
  80. d.attributePrefix = string((*a))
  81. return d
  82. }
  83. // WithContentPrefix appends the given prefix to the json output of xml content fields to preserve namespaces
  84. func WithContentPrefix(prefix string) *contentPrefixer {
  85. c := contentPrefixer(prefix)
  86. return &c
  87. }
  88. func (c *contentPrefixer) AddToEncoder(e *Encoder) *Encoder {
  89. e.contentPrefix = string((*c))
  90. return e
  91. }
  92. func (c *contentPrefixer) AddToDecoder(d *Decoder) *Decoder {
  93. d.contentPrefix = string((*c))
  94. return d
  95. }
  96. // ExcludeAttributes excludes some xml attributes, for example, xmlns:xsi, xsi:noNamespaceSchemaLocation
  97. func ExcludeAttributes(attrs []string) *excluder {
  98. ex := excluder(attrs)
  99. return &ex
  100. }
  101. func (ex *excluder) AddToEncoder(e *Encoder) *Encoder {
  102. return e
  103. }
  104. func (ex *excluder) AddToDecoder(d *Decoder) *Decoder {
  105. d.ExcludeAttributes([]string((*ex)))
  106. return d
  107. }
  108. // WithNodes formats specific nodes
  109. func WithNodes(n ...nodeFormatter) *nodesFormatter {
  110. return &nodesFormatter{list: n}
  111. }
  112. func (nf *nodesFormatter) AddToEncoder(e *Encoder) *Encoder {
  113. return e
  114. }
  115. func (nf *nodesFormatter) AddToDecoder(d *Decoder) *Decoder {
  116. d.AddFormatters(nf.list)
  117. return d
  118. }
  119. func NodePlugin(path string, plugin nodePlugin) nodeFormatter {
  120. return nodeFormatter{path: path, plugin: plugin}
  121. }
  122. func (nf *nodeFormatter) Format(node *Node) {
  123. child := node.GetChild(nf.path)
  124. if child != nil {
  125. nf.plugin.AddTo(child)
  126. }
  127. }
  128. func ToArray() *arrayFormatter {
  129. return &arrayFormatter{}
  130. }
  131. func (af *arrayFormatter) AddTo(n *Node) {
  132. n.ChildrenAlwaysAsArray = true
  133. }