forked from go-xmlfmt/xmlfmt
-
Notifications
You must be signed in to change notification settings - Fork 1
/
xmlfmt.go
83 lines (73 loc) · 2.34 KB
/
xmlfmt.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
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
////////////////////////////////////////////////////////////////////////////
// Porgram: xmlfmt.go
// Purpose: Go XML Beautify from XML string using pure string manipulation
// Authors: Antonio Sun (c) 2016-2019, All rights reserved
////////////////////////////////////////////////////////////////////////////
package xmlfmt
import (
"regexp"
"strings"
)
var (
reg = regexp.MustCompile(`<([/!]?)([^>]+?)(/?)>`)
// NL is the newline string used in XML output
NL = "\n"
)
// FormatXML will (purly) reformat the XML string in a readable way, without any rewriting/altering the structure
func FormatXML(xmls, prefix, indent string) string {
// replace all whitespace between tags
src := regexp.MustCompile(`(?s)>\s+<`).ReplaceAllString(xmls, "><")
src = regexp.MustCompile(`\n\s+<`).ReplaceAllString(xmls, "<")
rf := replaceTag(prefix, indent)
formatted := (prefix + reg.ReplaceAllStringFunc(src, rf))
formatted = regexp.MustCompile(`\n\s+\n`).ReplaceAllString(formatted, "\n")
return regexp.MustCompile(`\n+`).ReplaceAllString(formatted, "\n")
}
// replaceTag returns a closure function to do 's/(?<=>)\s+(?=<)//g; s(<(/?)([^>]+?)(/?)>)($indent+=$3?0:$1?-1:1;"<$1$2$3>"."\n".(" "x$indent))ge' as in Perl
// and deal with comments as well
func replaceTag(prefix, indent string) func(string) string {
indentLevel := 0
justOpened := false
return func(m string) string {
// head elem
if strings.HasPrefix(m, "<?xml") {
justOpened = false
return prefix + strings.Repeat(indent, indentLevel) + m + NL
}
// empty elem
if strings.HasSuffix(m, "/>") {
if justOpened {
justOpened = false
}
return NL + prefix + strings.Repeat(indent, indentLevel) + m + NL
// } else {
// return prefix + strings.Repeat(indent, indentLevel) + m + NL
// }
}
// comment elem
if strings.HasPrefix(m, "<!") {
justOpened = false
return NL + prefix + strings.Repeat(indent, indentLevel) + m
}
// end elem
if strings.HasPrefix(m, "</") {
defer func() {
justOpened = false
}()
indentLevel--
if justOpened {
return m + NL
}
return NL + prefix + strings.Repeat(indent, indentLevel) + m + NL
}
defer func() {
indentLevel++
}()
// if justOpened {
// indentLevel++
justOpened = true
return NL + prefix + strings.Repeat(indent, indentLevel) + m
// }
return prefix + strings.Repeat(indent, indentLevel) + m
}
}