-
-
Notifications
You must be signed in to change notification settings - Fork 2
/
iter.go
119 lines (103 loc) · 2.41 KB
/
iter.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
// Copyright 2019 The Mellium Contributors.
// Use of this source code is governed by the BSD 2-clause
// license that can be found in the LICENSE file.
package xmlstream
import (
"encoding/xml"
"io"
)
// Iter provides a mechanism for iterating over the children of an XML element.
// Successive calls to the Next method will step through each child, returning
// its start element (if applicable) and a reader that is limited to the
// remainder of the child.
type Iter struct {
r TokenReadCloser
err error
next *xml.StartElement
cur xml.TokenReader
closed bool
discard TokenWriter
}
type nopClose struct{}
func (nopClose) Close() error { return nil }
func wrapClose(r xml.TokenReader) TokenReadCloser {
var c io.Closer
var ok bool
c, ok = r.(io.Closer)
if !ok {
c = nopClose{}
}
return struct {
xml.TokenReader
io.Closer
}{
TokenReader: Inner(r),
Closer: c,
}
}
// NewIter returns a new iterator that iterates over the children of the most
// recent start element already consumed from r.
func NewIter(r xml.TokenReader) *Iter {
iter := &Iter{
r: wrapClose(r),
discard: Discard(),
}
return iter
}
// Next returns true if there are more items to decode.
func (i *Iter) Next() bool {
if i.err != nil || i.closed {
return false
}
// Consume the previous element before moving on to the next.
if i.cur != nil {
_, i.err = Copy(i.discard, i.cur)
if i.err != nil {
return false
}
}
i.next = nil
t, err := i.r.Token()
if err != nil {
if err != io.EOF {
i.err = err
}
return false
}
switch tok := t.(type) {
case xml.StartElement:
i.next = &tok
//i.cur = MultiReader(Inner(i.r), Token(i.next.End()))
i.cur = InnerElement(i.r)
return true
case xml.EndElement:
return false
}
i.next = nil
i.cur = Token(t)
return true
}
// Current returns a reader over the most recent child.
func (i *Iter) Current() (*xml.StartElement, xml.TokenReader) {
return i.next, i.cur
}
// Err returns the last error encountered by the iterator (if any).
func (i *Iter) Err() error {
return i.err
}
// Close indicates that we are finished with the given iterator.
// Calling it multiple times has no effect.
//
// If the underlying TokenReader is also an io.Closer, Close calls the readers
// Close method.
func (i *Iter) Close() error {
if i.closed {
return nil
}
i.closed = true
_, err := Copy(i.discard, i.r)
if err != nil {
return err
}
return i.r.Close()
}