forked from bytbox/obsidian
/
tidy.go
77 lines (72 loc) · 1.86 KB
/
tidy.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
package tidy
import (
"bytes"
"fmt"
"os"
"strings"
"xml"
)
// String returns a string form of the xml.Name object.
func String(name xml.Name) string {
if len(name.Space) > 0 {
return fmt.Sprintf("%s:%s", name.Space, name.Local)
}
return name.Local
}
// indentation is the string to use as a single indentation level
var indentation = " "
// Tidy takes an HTML string and tidys it up.
func Tidy(str string) (html string, err os.Error) {
parser := xml.NewParser(strings.NewReader(str))
// read str, token by token, and spit it out
//
// xml.Parser does most of the work for us here - we do a small
// bit by indenting
indent := 0 // the current indent level
token, err := parser.Token()
for err == nil {
switch token.(type) {
case xml.StartElement:
elem := token.(xml.StartElement)
for i := 0; i < indent; i++ { html += indentation }
html += "<"+String(elem.Name)
for _, attr := range elem.Attr {
html += fmt.Sprintf(" %s=\"%s\"",
String(attr.Name),
attr.Value)
}
html += ">\n"
indent++
case xml.EndElement:
elem := token.(xml.EndElement)
indent--
for i := 0; i < indent; i++ { html += indentation }
html += fmt.Sprintf("</%s>\n", String(elem.Name))
case xml.CharData:
data := token.(xml.CharData)
str := bytes.NewBuffer(data).String()
str = strings.Trim(str, " \r\n\t")
if len(str) > 0 {
for i := 0; i < indent; i++ { html += indentation }
html += str+"\n"
}
case xml.Comment:
// don't print comments
case xml.ProcInst:
// TODO handle these somehow (server-side xslt?)
case xml.Directive:
// just spit it out
directive := token.(xml.Directive)
html += "<!"+bytes.NewBuffer(directive).String()+">"
default:
// yikes! Not much to do about this...
}
token, err = parser.Token()
}
if err != os.EOF {
// return the original string
return str, err
}
err = nil
return
}