1
2
3
4
5
6
7
8 package mxj
9
10 import (
11 "bytes"
12 "encoding/xml"
13 "errors"
14 "fmt"
15 "io"
16 "regexp"
17 "sort"
18 "strings"
19 )
20
21
22
23
24
25
26 type MapSeq map[string]interface{}
27
28
29
30 var NoRoot = errors.New("no root key")
31 var NO_ROOT = NoRoot
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87 func NewMapXmlSeq(xmlVal []byte, cast ...bool) (MapSeq, error) {
88 var r bool
89 if len(cast) == 1 {
90 r = cast[0]
91 }
92 return xmlSeqToMap(xmlVal, r)
93 }
94
95
96
97
98
99
100
101
102
103 func NewMapFormattedXmlSeq(xmlVal []byte, cast ...bool) (MapSeq, error) {
104 var c bool
105 if len(cast) == 1 {
106 c = cast[0]
107 }
108
109
110
111
112 r := regexp.MustCompile(`>[\n\t\r ]*<`)
113 xmlVal = r.ReplaceAll(xmlVal, []byte("><"))
114 return xmlSeqToMap(xmlVal, c)
115 }
116
117
118
119
120
121
122
123
124
125
126
127
128 func NewMapXmlSeqReader(xmlReader io.Reader, cast ...bool) (MapSeq, error) {
129 var r bool
130 if len(cast) == 1 {
131 r = cast[0]
132 }
133
134
135
136
137 if _, ok := xmlReader.(io.ByteReader); !ok {
138 xmlReader = myByteReader(xmlReader)
139 }
140
141
142 return xmlSeqReaderToMap(xmlReader, r)
143 }
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163 func NewMapXmlSeqReaderRaw(xmlReader io.Reader, cast ...bool) (MapSeq, []byte, error) {
164 var r bool
165 if len(cast) == 1 {
166 r = cast[0]
167 }
168
169 buf := make([]byte, 0)
170 wb := bytes.NewBuffer(buf)
171 trdr := myTeeReader(xmlReader, wb)
172
173 m, err := xmlSeqReaderToMap(trdr, r)
174
175
176 b := wb.Bytes()
177
178
179 return m, b, err
180 }
181
182
183 func xmlSeqReaderToMap(rdr io.Reader, r bool) (map[string]interface{}, error) {
184
185 p := xml.NewDecoder(rdr)
186 if CustomDecoder != nil {
187 useCustomDecoder(p)
188 } else {
189 p.CharsetReader = XmlCharsetReader
190 }
191 return xmlSeqToMapParser("", nil, p, r)
192 }
193
194
195 func xmlSeqToMap(doc []byte, r bool) (map[string]interface{}, error) {
196 b := bytes.NewReader(doc)
197 p := xml.NewDecoder(b)
198 if CustomDecoder != nil {
199 useCustomDecoder(p)
200 } else {
201 p.CharsetReader = XmlCharsetReader
202 }
203 return xmlSeqToMapParser("", nil, p, r)
204 }
205
206
207
208
209
210 func xmlSeqToMapParser(skey string, a []xml.Attr, p *xml.Decoder, r bool) (map[string]interface{}, error) {
211 if snakeCaseKeys {
212 skey = strings.Replace(skey, "-", "_", -1)
213 }
214
215
216 var n, na map[string]interface{}
217 var seq int
218
219
220
221
222
223 if skey != "" {
224
225
226 n = make(map[string]interface{}, 1)
227 na = make(map[string]interface{})
228 if len(a) > 0 {
229
230
231 aa := make(map[string]interface{}, len(a))
232 for i, v := range a {
233 if snakeCaseKeys {
234 v.Name.Local = strings.Replace(v.Name.Local, "-", "_", -1)
235 }
236 if xmlEscapeCharsDecoder {
237 v.Value = escapeChars(v.Value)
238 }
239 if len(v.Name.Space) > 0 {
240 aa[v.Name.Space+`:`+v.Name.Local] = map[string]interface{}{textK: cast(v.Value, r, ""), seqK: i}
241 } else {
242 aa[v.Name.Local] = map[string]interface{}{textK: cast(v.Value, r, ""), seqK: i}
243 }
244 }
245 na[attrK] = aa
246 }
247 }
248
249
250 if handleXMPPStreamTag && skey == "stream:stream" {
251 n[skey] = na
252 return n, nil
253 }
254
255 for {
256 t, err := p.RawToken()
257 if err != nil {
258 if err != io.EOF {
259 return nil, errors.New("xml.Decoder.Token() - " + err.Error())
260 }
261 return nil, err
262 }
263 switch t.(type) {
264 case xml.StartElement:
265 tt := t.(xml.StartElement)
266
267
268
269
270
271
272
273
274 if skey == "" {
275 if len(tt.Name.Space) > 0 {
276 return xmlSeqToMapParser(tt.Name.Space+`:`+tt.Name.Local, tt.Attr, p, r)
277 } else {
278 return xmlSeqToMapParser(tt.Name.Local, tt.Attr, p, r)
279 }
280 }
281
282
283
284 var nn map[string]interface{}
285 if len(tt.Name.Space) > 0 {
286 nn, err = xmlSeqToMapParser(tt.Name.Space+`:`+tt.Name.Local, tt.Attr, p, r)
287 } else {
288 nn, err = xmlSeqToMapParser(tt.Name.Local, tt.Attr, p, r)
289 }
290 if err != nil {
291 return nil, err
292 }
293
294
295
296
297
298 var key string
299 var val interface{}
300 for key, val = range nn {
301 break
302 }
303
304
305
306
307
308
309
310
311 switch val.(type) {
312 case map[string]interface{}:
313 val.(map[string]interface{})[seqK] = seq
314 seq++
315 case interface{}:
316 v := map[string]interface{}{textK: val, seqK: seq}
317 seq++
318 val = v
319 }
320
321
322
323
324 if v, ok := na[key]; ok {
325 var a []interface{}
326 switch v.(type) {
327 case []interface{}:
328 a = v.([]interface{})
329 default:
330 a = []interface{}{v}
331 }
332 a = append(a, val)
333 na[key] = a
334 } else {
335 na[key] = val
336 }
337 case xml.EndElement:
338 if skey != "" {
339 tt := t.(xml.EndElement)
340 if snakeCaseKeys {
341 tt.Name.Local = strings.Replace(tt.Name.Local, "-", "_", -1)
342 }
343 var name string
344 if len(tt.Name.Space) > 0 {
345 name = tt.Name.Space + `:` + tt.Name.Local
346 } else {
347 name = tt.Name.Local
348 }
349 if skey != name {
350 return nil, fmt.Errorf("element %s not properly terminated, got %s at #%d",
351 skey, name, p.InputOffset())
352 }
353 }
354
355 if len(n) == 0 {
356
357
358
359
360 if len(na) > 0 {
361 n[skey] = na
362 } else {
363 n[skey] = ""
364 }
365 }
366 return n, nil
367 case xml.CharData:
368
369 tt := strings.Trim(string(t.(xml.CharData)), trimRunes)
370 if xmlEscapeCharsDecoder {
371 tt = escapeChars(tt)
372 }
373 if skey == "" {
374
375
376
377
378
379 continue
380 }
381 if len(tt) > 0 {
382
383 na[textK] = cast(tt, r, "")
384 na[seqK] = seq
385 seq++
386 }
387 case xml.Comment:
388 if n == nil {
389 n = map[string]interface{}{commentK: string(t.(xml.Comment))}
390 return n, NoRoot
391 }
392 cm := make(map[string]interface{}, 2)
393 cm[textK] = string(t.(xml.Comment))
394 cm[seqK] = seq
395 seq++
396 na[commentK] = cm
397 case xml.Directive:
398 if n == nil {
399 n = map[string]interface{}{directiveK: string(t.(xml.Directive))}
400 return n, NoRoot
401 }
402 dm := make(map[string]interface{}, 2)
403 dm[textK] = string(t.(xml.Directive))
404 dm[seqK] = seq
405 seq++
406 na[directiveK] = dm
407 case xml.ProcInst:
408 if n == nil {
409 na = map[string]interface{}{targetK: t.(xml.ProcInst).Target, instK: string(t.(xml.ProcInst).Inst)}
410 n = map[string]interface{}{procinstK: na}
411 return n, NoRoot
412 }
413 pm := make(map[string]interface{}, 3)
414 pm[targetK] = t.(xml.ProcInst).Target
415 pm[instK] = string(t.(xml.ProcInst).Inst)
416 pm[seqK] = seq
417 seq++
418 na[procinstK] = pm
419 default:
420
421 }
422 }
423 }
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445 func (mv MapSeq) Xml(rootTag ...string) ([]byte, error) {
446 m := map[string]interface{}(mv)
447 var err error
448 s := new(string)
449 p := new(pretty)
450
451 if len(m) == 1 && len(rootTag) == 0 {
452 for key, value := range m {
453
454
455
456 switch value.(type) {
457 case []interface{}:
458 for _, v := range value.([]interface{}) {
459 switch v.(type) {
460 case map[string]interface{}:
461 default:
462 err = mapToXmlSeqIndent(false, s, DefaultRootTag, m, p)
463 goto done
464 }
465 }
466 }
467 err = mapToXmlSeqIndent(false, s, key, value, p)
468 }
469 } else if len(rootTag) == 1 {
470 err = mapToXmlSeqIndent(false, s, rootTag[0], m, p)
471 } else {
472 err = mapToXmlSeqIndent(false, s, DefaultRootTag, m, p)
473 }
474 done:
475 if xmlCheckIsValid {
476 d := xml.NewDecoder(bytes.NewReader([]byte(*s)))
477 for {
478 _, err = d.Token()
479 if err == io.EOF {
480 err = nil
481 break
482 } else if err != nil {
483 return nil, err
484 }
485 }
486 }
487 return []byte(*s), err
488 }
489
490
491
492
493
494
495 func (mv MapSeq) XmlWriter(xmlWriter io.Writer, rootTag ...string) error {
496 x, err := mv.Xml(rootTag...)
497 if err != nil {
498 return err
499 }
500
501 _, err = xmlWriter.Write(x)
502 return err
503 }
504
505
506
507
518
519
520
521 func (mv MapSeq) XmlIndentWriter(xmlWriter io.Writer, prefix, indent string, rootTag ...string) error {
522 x, err := mv.XmlIndent(prefix, indent, rootTag...)
523 if err != nil {
524 return err
525 }
526
527 _, err = xmlWriter.Write(x)
528 return err
529 }
530
531
532
533
544
545
546
547
548
549
550
551 func (mv MapSeq) XmlIndent(prefix, indent string, rootTag ...string) ([]byte, error) {
552 m := map[string]interface{}(mv)
553
554 var err error
555 s := new(string)
556 p := new(pretty)
557 p.indent = indent
558 p.padding = prefix
559
560 if len(m) == 1 && len(rootTag) == 0 {
561
562
563 for key, value := range m {
564 if _, ok := value.([]interface{}); ok {
565 err = mapToXmlSeqIndent(true, s, DefaultRootTag, m, p)
566 } else {
567 err = mapToXmlSeqIndent(true, s, key, value, p)
568 }
569 }
570 } else if len(rootTag) == 1 {
571 err = mapToXmlSeqIndent(true, s, rootTag[0], m, p)
572 } else {
573 err = mapToXmlSeqIndent(true, s, DefaultRootTag, m, p)
574 }
575 if xmlCheckIsValid {
576 if _, err = NewMapXml([]byte(*s)); err != nil {
577 return nil, err
578 }
579 d := xml.NewDecoder(bytes.NewReader([]byte(*s)))
580 for {
581 _, err = d.Token()
582 if err == io.EOF {
583 err = nil
584 break
585 } else if err != nil {
586 return nil, err
587 }
588 }
589 }
590 return []byte(*s), err
591 }
592
593
594
595 func mapToXmlSeqIndent(doIndent bool, s *string, key string, value interface{}, pp *pretty) error {
596 var endTag bool
597 var isSimple bool
598 var noEndTag bool
599 var elen int
600 var ss string
601 p := &pretty{pp.indent, pp.cnt, pp.padding, pp.mapDepth, pp.start}
602
603 switch value.(type) {
604 case map[string]interface{}, []byte, string, float64, bool, int, int32, int64, float32:
605 if doIndent {
606 *s += p.padding
607 }
608 if key != commentK && key != directiveK && key != procinstK {
609 *s += `<` + key
610 }
611 }
612 switch value.(type) {
613 case map[string]interface{}:
614 val := value.(map[string]interface{})
615
616 if key == commentK {
617 *s += `<!--` + val[textK].(string) + `-->`
618 noEndTag = true
619 break
620 }
621
622 if key == directiveK {
623 *s += `<!` + val[textK].(string) + `>`
624 noEndTag = true
625 break
626 }
627
628 if key == procinstK {
629 *s += `<?` + val[targetK].(string) + ` ` + val[instK].(string) + `?>`
630 noEndTag = true
631 break
632 }
633
634 haveAttrs := false
635
636 if v, ok := val[attrK].(map[string]interface{}); ok {
637
638
639 kv := make([]keyval, len(v))
640 n := 0
641 for ak, av := range v {
642 kv[n] = keyval{ak, av}
643 n++
644 }
645 sort.Sort(elemListSeq(kv))
646
647 for _, a := range kv {
648 vv := a.v.(map[string]interface{})
649 switch vv[textK].(type) {
650 case string:
651 if xmlEscapeChars {
652 ss = escapeChars(vv[textK].(string))
653 } else {
654 ss = vv[textK].(string)
655 }
656 *s += ` ` + a.k + `="` + ss + `"`
657 case float64, bool, int, int32, int64, float32:
658 *s += ` ` + a.k + `="` + fmt.Sprintf("%v", vv[textK]) + `"`
659 case []byte:
660 if xmlEscapeChars {
661 ss = escapeChars(string(vv[textK].([]byte)))
662 } else {
663 ss = string(vv[textK].([]byte))
664 }
665 *s += ` ` + a.k + `="` + ss + `"`
666 default:
667 return fmt.Errorf("invalid attribute value for: %s", a.k)
668 }
669 }
670 haveAttrs = true
671 }
672
673
674
675 _, seqOK := val[seqK]
676 if v, ok := val[textK]; ok && ((len(val) == 3 && haveAttrs) || (len(val) == 2 && !haveAttrs)) && seqOK {
677 if stmp, ok := v.(string); ok && stmp != "" {
678 if xmlEscapeChars {
679 stmp = escapeChars(stmp)
680 }
681 *s += ">" + stmp
682 endTag = true
683 elen = 1
684 }
685 isSimple = true
686 break
687 } else if !ok && ((len(val) == 2 && haveAttrs) || (len(val) == 1 && !haveAttrs)) && seqOK {
688
689 endTag = false
690 break
691 }
692
693
694
695 kv := make([]keyval, 0)
696 for k, v := range val {
697 if k == attrK {
698 continue
699 }
700 if k == seqK {
701 continue
702 }
703 switch v.(type) {
704 case []interface{}:
705
706 for _, vv := range v.([]interface{}) {
707 kv = append(kv, keyval{k, vv})
708 }
709 default:
710 kv = append(kv, keyval{k, v})
711 }
712 }
713
714
715 *s += ">"
716 if doIndent {
717 *s += "\n"
718 }
719
720 p.mapDepth++
721 sort.Sort(elemListSeq(kv))
722 i := 0
723 for _, v := range kv {
724 switch v.v.(type) {
725 case []interface{}:
726 default:
727 if i == 0 && doIndent {
728 p.Indent()
729 }
730 }
731 i++
732 if err := mapToXmlSeqIndent(doIndent, s, v.k, v.v, p); err != nil {
733 return err
734 }
735 switch v.v.(type) {
736 case []interface{}:
737 default:
738 if doIndent {
739 p.Outdent()
740 }
741 }
742 i--
743 }
744 p.mapDepth--
745 endTag = true
746 elen = 1
747 case []interface{}:
748 for _, v := range value.([]interface{}) {
749 if doIndent {
750 p.Indent()
751 }
752 if err := mapToXmlSeqIndent(doIndent, s, key, v, p); err != nil {
753 return err
754 }
755 if doIndent {
756 p.Outdent()
757 }
758 }
759 return nil
760 case nil:
761
762 if doIndent {
763 *s += p.padding
764 }
765 *s += "<" + key
766 endTag, isSimple = true, true
767 break
768 default:
769 elen = 0
770 switch value.(type) {
771 case string:
772 if xmlEscapeChars {
773 ss = escapeChars(value.(string))
774 } else {
775 ss = value.(string)
776 }
777 elen = len(ss)
778 if elen > 0 {
779 *s += ">" + ss
780 }
781 case float64, bool, int, int32, int64, float32:
782 v := fmt.Sprintf("%v", value)
783 elen = len(v)
784 if elen > 0 {
785 *s += ">" + v
786 }
787 case []byte:
788
789 if xmlEscapeChars {
790 ss = escapeChars(string(value.([]byte)))
791 } else {
792 ss = string(value.([]byte))
793 }
794 elen = len(ss)
795 if elen > 0 {
796 *s += ">" + ss
797 }
798 default:
799 var v []byte
800 var err error
801 if doIndent {
802 v, err = xml.MarshalIndent(value, p.padding, p.indent)
803 } else {
804 v, err = xml.Marshal(value)
805 }
806 if err != nil {
807 *s += ">UNKNOWN"
808 } else {
809 elen = len(v)
810 if elen > 0 {
811 *s += string(v)
812 }
813 }
814 }
815 isSimple = true
816 endTag = true
817 }
818 if endTag && !noEndTag {
819 if doIndent {
820 if !isSimple {
821 *s += p.padding
822 }
823 }
824 switch value.(type) {
825 case map[string]interface{}, []byte, string, float64, bool, int, int32, int64, float32:
826 if elen > 0 || useGoXmlEmptyElemSyntax {
827 if elen == 0 {
828 *s += ">"
829 }
830 *s += `</` + key + ">"
831 } else {
832 *s += `/>`
833 }
834 }
835 } else if !noEndTag {
836 if useGoXmlEmptyElemSyntax {
837 *s += `</` + key + ">"
838
839 } else {
840 *s += "/>"
841 }
842 }
843 if doIndent {
844 if p.cnt > p.start {
845 *s += "\n"
846 }
847 p.Outdent()
848 }
849
850 return nil
851 }
852
853
854
855 type keyval struct {
856 k string
857 v interface{}
858 }
859 type elemListSeq []keyval
860
861 func (e elemListSeq) Len() int {
862 return len(e)
863 }
864
865 func (e elemListSeq) Swap(i, j int) {
866 e[i], e[j] = e[j], e[i]
867 }
868
869 func (e elemListSeq) Less(i, j int) bool {
870 var iseq, jseq int
871 var fiseq, fjseq float64
872 var ok bool
873 if iseq, ok = e[i].v.(map[string]interface{})[seqK].(int); !ok {
874 if fiseq, ok = e[i].v.(map[string]interface{})[seqK].(float64); ok {
875 iseq = int(fiseq)
876 } else {
877 iseq = 9999999
878 }
879 }
880
881 if jseq, ok = e[j].v.(map[string]interface{})[seqK].(int); !ok {
882 if fjseq, ok = e[j].v.(map[string]interface{})[seqK].(float64); ok {
883 jseq = int(fjseq)
884 } else {
885 jseq = 9999999
886 }
887 }
888
889 return iseq <= jseq
890 }
891
892
893
894
895
896 func BeautifyXml(b []byte, prefix, indent string) ([]byte, error) {
897 x, err := NewMapXmlSeq(b)
898 if err != nil {
899 return nil, err
900 }
901 return x.XmlIndent(prefix, indent)
902 }
903
View as plain text