-
Notifications
You must be signed in to change notification settings - Fork 0
/
xml_parse.go
executable file
·129 lines (114 loc) · 2.37 KB
/
xml_parse.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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
package types
import (
"bytes"
"encoding/xml"
"fmt"
"io"
"io/ioutil"
"strings"
)
type xmlElemType string
const (
xmlTextElem xmlElemType = "text" // 静态文本节点
xmlNodeElem xmlElemType = "node" // 节点子节点
)
type xmlElement struct {
ElementType xmlElemType
Val interface{}
}
type xmlNode struct {
Id string
Name string
Attrs map[string]string
Elements []xmlElement
}
func parseXmlFile(filename string) (*xmlNode, error) {
content, err := ioutil.ReadFile(filename)
if err != nil {
return nil, err
}
r := bytes.NewReader(content)
return parseXmlNode(r)
}
func parseXmlNode(r io.Reader) (*xmlNode, error) {
parser := xml.NewDecoder(r)
var root xmlNode
st := newStack()
for {
token, err := parser.Token()
if err != nil {
break
}
switch t := token.(type) {
case xml.StartElement: //tag start
node := startElement2XmlNode(t)
st.Push(node)
case xml.EndElement: //tag end
if st.Len() > 0 {
//cur node
n := st.Pop().(xmlNode)
if st.Len() > 0 { //if the root xmlNode then append to xmlElement
e := xmlElement{
ElementType: xmlNodeElem,
Val: n,
}
pn := st.Pop().(xmlNode)
els := pn.Elements
els = append(els, e)
pn.Elements = els
st.Push(pn)
} else { //else root = n
root = n
}
}
case xml.CharData: //tag content
if st.Len() > 0 {
n := charData2XmlNode(st, t)
st.Push(n)
}
case xml.Comment:
case xml.ProcInst:
case xml.Directive:
default:
}
}
if st.Len() != 0 {
return nil, fmt.Errorf("parse xml error, there is tag no close, please check your xml config")
}
return &root, nil
}
func charData2XmlNode(st *stack, t xml.Token) xmlNode {
n := st.Pop().(xmlNode)
bts := t.(xml.CharData)
content := strings.TrimSpace(string(bts))
if content != "" {
e := xmlElement{
ElementType: xmlTextElem,
Val: content,
}
els := n.Elements
els = append(els, e)
n.Elements = els
}
return n
}
func startElement2XmlNode(t xml.Token) xmlNode {
elmt := t.(xml.StartElement)
name := elmt.Name.Local
attr := elmt.Attr
attrMap := make(map[string]string)
for _, val := range attr {
attrMap[val.Name.Local] = val.Value
}
node := xmlNode{
Name: name,
Attrs: attrMap,
Elements: make([]xmlElement, 0),
}
for _, val := range attr {
if val.Name.Local == "id" {
node.Id = val.Value
}
}
return node
}