forked from paulmach/osm
-
Notifications
You must be signed in to change notification settings - Fork 2
/
diff.go
119 lines (103 loc) · 2.73 KB
/
diff.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
package osm
import "encoding/xml"
// Diff represents a difference of osm data with old and new data.
type Diff struct {
XMLName xml.Name `xml:"osm"`
Actions Actions `xml:"action"`
Changesets Changesets `xml:"changeset"`
}
// Actions is a set of diff actions.
type Actions []Action
// Action is an explicit create, modify or delete action with
// old and new data if applicable. Different properties of this
// struct will be populated depending on the action.
// Create: da.OSM will contain the new element
// Modify: da.Old and da.New will contain the old and new elements.
// Delete: da.Old and da.New will contain the old and new elements.
type Action struct {
Type ActionType `xml:"type,attr"`
*OSM `xml:",omitempty"`
Old *OSM `xml:"old,omitempty"`
New *OSM `xml:"new,omitempty"`
}
// UnmarshalXML converts xml into a diff action.
func (a *Action) UnmarshalXML(d *xml.Decoder, start xml.StartElement) error {
for _, attr := range start.Attr {
if attr.Name.Local == "type" {
a.Type = ActionType(attr.Value)
break
}
}
for {
token, err := d.Token()
if err != nil {
break
}
start, ok := token.(xml.StartElement)
if !ok {
continue
}
switch start.Name.Local {
case "old":
a.Old = &OSM{}
if err := d.DecodeElement(a.Old, &start); err != nil {
return err
}
case "new":
a.New = &OSM{}
if err := d.DecodeElement(a.New, &start); err != nil {
return err
}
case "node":
n := &Node{}
if err := d.DecodeElement(&n, &start); err != nil {
return err
}
a.OSM = &OSM{Nodes: Nodes{n}}
case "way":
w := &Way{}
if err := d.DecodeElement(&w, &start); err != nil {
return err
}
a.OSM = &OSM{Ways: Ways{w}}
case "relation":
r := &Relation{}
if err := d.DecodeElement(&r, &start); err != nil {
return err
}
a.OSM = &OSM{Relations: Relations{r}}
}
}
return nil
}
// MarshalXML converts a diff action to xml creating the proper structures.
func (a Action) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
start.Attr = append(start.Attr, xml.Attr{Name: xml.Name{Local: "type"}, Value: string(a.Type)})
if err := e.EncodeToken(start); err != nil {
return err
}
if a.OSM != nil {
if err := a.OSM.marshalInnerElementsXML(e); err != nil {
return err
}
}
if a.Old != nil {
if err := marshalInnerChange(e, "old", a.Old); err != nil {
return err
}
}
if a.New != nil {
if err := marshalInnerChange(e, "new", a.New); err != nil {
return err
}
}
return e.EncodeToken(start.End())
}
// ActionType is a strong type for the different diff actions.
type ActionType string
// The different types of diff actions.
const (
ActionCreate ActionType = "create"
ActionModify ActionType = "modify"
ActionDelete ActionType = "delete"
)