-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathxmlformat.go
More file actions
101 lines (92 loc) · 2.29 KB
/
xmlformat.go
File metadata and controls
101 lines (92 loc) · 2.29 KB
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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
package main
// A simple streaming XML formatter.
// Not as fast and versatile as xmllint, but doesn't run into memory issues for very big files.
//
// All whitespace-only tokens are assumed to be 'ignorable'. It is not possible to use a schema.
import (
"encoding/xml"
"flag"
"fmt"
"golang.org/x/net/html/charset"
"log"
"os"
)
var indent = flag.String("indent", "tab", "the indentation string, or 'tab' for indenting with a tab character")
var outfile = flag.String("outfile", "", "the output file, leave blank to write to stdout")
func usage() {
fmt.Fprintf(os.Stderr, "Usage: xmlformat [filename]\n\n")
flag.PrintDefaults()
fmt.Fprintf(os.Stderr, "\n")
}
// all whitespace-only tokens are assumed to be ignorable
func ignorable(t xml.Token) bool {
switch ele := t.(type) {
case xml.CharData:
for _, b := range ele {
if b != 0x20 && b != 0x9 && b != 0xD && b != 0xA {
return false
}
}
return true
}
return false
}
func main() {
flag.Usage = usage
flag.Parse()
args := flag.Args()
if len(args) > 1 {
flag.Usage()
os.Exit(1)
}
xmlReader := os.Stdin
if len(args) == 1 {
inputFile := args[0]
xmlFile, err := os.Open(inputFile)
if err != nil {
log.Fatal("Error opening input file:", err)
}
defer xmlFile.Close()
xmlReader = xmlFile
}
decoder := xml.NewDecoder(xmlReader)
decoder.CharsetReader = charset.NewReaderLabel
out := os.Stdout
if *outfile != "" {
outFile, err := os.Create(*outfile)
if err != nil {
log.Fatal("Error opening output file:", err)
}
defer outFile.Close()
out = outFile
}
encoder := xml.NewEncoder(out)
if *indent == "tab" {
*indent = "\t"
}
encoder.Indent("", *indent)
for {
t, err := decoder.Token()
if t == nil {
break
}
if err != nil {
log.Fatalf("Failed to parse xml: %v", err)
}
if !ignorable(t) {
switch t.(type) {
default:
encoder.EncodeToken(t)
case xml.ProcInst:
procInst := xml.ProcInst{"xml", []byte("version=\"1.0\" encoding=\"UTF-8\"")}
encoder.EncodeToken(procInst)
// For some reason the encoder does not write a newline after the ProcInst <?xml...>
// We fix this by inserting a newline. This looks nice with go 1.5, but with 1.4
// it will write an escaped newline...
encoder.EncodeToken(xml.CharData([]byte{10}))
}
}
}
encoder.Flush()
fmt.Fprintln(out, "")
}