-
Notifications
You must be signed in to change notification settings - Fork 3
/
record.go
141 lines (129 loc) · 3.21 KB
/
record.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
130
131
132
133
134
135
136
137
138
139
140
141
package marc21
import (
"encoding/xml"
"errors"
"io"
"strings"
)
// Record represents a MARC21 record, consisting of a leader and a number of
// fields.
type Record struct {
Leader *Leader `xml:"leader"`
Fields []Field
}
// ReadRecord returns a single MARC record from a reader.
func ReadRecord(reader io.Reader) (record *Record, err error) {
record = &Record{}
record.Fields = make([]Field, 0, 8)
if record.Leader, err = readLeader(reader); err != nil {
return
}
dents := make([]*dirent, 0, 8)
for {
var dent *dirent
dent, err = readDirEnt(reader)
if err == ErrFieldSeparator {
err = nil
break
}
if err != nil {
return
}
dents = append(dents, dent)
}
for _, dent := range dents {
var field Field
if strings.HasPrefix(dent.tag, "00") {
if field, err = readControl(reader, dent); err != nil {
return
}
} else {
if field, err = readData(reader, dent); err != nil {
return
}
}
record.Fields = append(record.Fields, field)
}
rtbuf := make([]byte, 1)
if _, err = reader.Read(rtbuf); err != nil {
return
}
if rtbuf[0] != RT {
err = errors.New("could not read record terminator")
}
return
}
// Identifier returns the record identifier or an empty string.
func (record *Record) Identifier() string {
for _, f := range record.Fields {
if f.GetTag() == "001" {
if v, ok := f.(*ControlField); ok {
return v.Data
}
}
}
return ""
}
// MarshalXML encodes a record as XML.
func (record *Record) MarshalXML(e *xml.Encoder, start xml.StartElement) error {
start.Name = xml.Name{Local: "record"}
if err := e.EncodeToken(start); err != nil {
return err
}
leaderTag := xml.StartElement{Name: xml.Name{Local: "leader"}}
if err := e.EncodeElement(record.Leader.String(), leaderTag); err != nil {
return err
}
if err := e.Encode(record.Fields); err != nil {
return err
}
return e.EncodeToken(xml.EndElement{Name: start.Name})
}
// WriteTo writes a MARCXML representation of the record.
func (record *Record) WriteTo(w io.Writer) (int64, error) {
b, err := xml.Marshal(record)
if err != nil {
return 0, err
}
n, err := w.Write(b)
return int64(n), err
}
// AddField adds a control or data field to a record.
func (record *Record) AddField(f Field) {
record.Fields = append(record.Fields, f)
}
// String returns the Record as a string.
func (record *Record) String() string {
estrings := make([]string, len(record.Fields))
for i, entry := range record.Fields {
estrings[i] = entry.String()
}
return strings.Join(estrings, "\n")
}
// GetFields returns a slice of fields that match the given tag.
func (record *Record) GetFields(tag string) (fields []Field) {
fields = make([]Field, 0, 4)
for _, field := range record.Fields {
if field.GetTag() == tag {
fields = append(fields, field)
}
}
return
}
// GetSubFields returns a slice of subfields that match the given tag
// and code.
func (record *Record) GetSubFields(tag string, code byte) (subfields []*SubField) {
subfields = make([]*SubField, 0, 4)
fields := record.GetFields(tag)
for _, field := range fields {
switch data := field.(type) {
case *DataField:
for _, subfield := range data.SubFields {
if subfield.Code == code {
subfields = append(subfields, subfield)
}
}
}
}
return
}