1package mxj
2
3import (
4	"fmt"
5	"io"
6	"os"
7)
8
9type Maps []Map
10
11func NewMaps() Maps {
12	return make(Maps, 0)
13}
14
15type MapRaw struct {
16	M Map
17	R []byte
18}
19
20// NewMapsFromXmlFile - creates an array from a file of JSON values.
21func NewMapsFromJsonFile(name string) (Maps, error) {
22	fi, err := os.Stat(name)
23	if err != nil {
24		return nil, err
25	}
26	if !fi.Mode().IsRegular() {
27		return nil, fmt.Errorf("file %s is not a regular file", name)
28	}
29
30	fh, err := os.Open(name)
31	if err != nil {
32		return nil, err
33	}
34	defer fh.Close()
35
36	am := make([]Map, 0)
37	for {
38		m, raw, err := NewMapJsonReaderRaw(fh)
39		if err != nil && err != io.EOF {
40			return am, fmt.Errorf("error: %s - reading: %s", err.Error(), string(raw))
41		}
42		if len(m) > 0 {
43			am = append(am, m)
44		}
45		if err == io.EOF {
46			break
47		}
48	}
49	return am, nil
50}
51
52// ReadMapsFromJsonFileRaw - creates an array of MapRaw from a file of JSON values.
53func NewMapsFromJsonFileRaw(name string) ([]MapRaw, error) {
54	fi, err := os.Stat(name)
55	if err != nil {
56		return nil, err
57	}
58	if !fi.Mode().IsRegular() {
59		return nil, fmt.Errorf("file %s is not a regular file", name)
60	}
61
62	fh, err := os.Open(name)
63	if err != nil {
64		return nil, err
65	}
66	defer fh.Close()
67
68	am := make([]MapRaw, 0)
69	for {
70		mr := new(MapRaw)
71		mr.M, mr.R, err = NewMapJsonReaderRaw(fh)
72		if err != nil && err != io.EOF {
73			return am, fmt.Errorf("error: %s - reading: %s", err.Error(), string(mr.R))
74		}
75		if len(mr.M) > 0 {
76			am = append(am, *mr)
77		}
78		if err == io.EOF {
79			break
80		}
81	}
82	return am, nil
83}
84
85// NewMapsFromXmlFile - creates an array from a file of XML values.
86func NewMapsFromXmlFile(name string) (Maps, error) {
87	fi, err := os.Stat(name)
88	if err != nil {
89		return nil, err
90	}
91	if !fi.Mode().IsRegular() {
92		return nil, fmt.Errorf("file %s is not a regular file", name)
93	}
94
95	fh, err := os.Open(name)
96	if err != nil {
97		return nil, err
98	}
99	defer fh.Close()
100
101	am := make([]Map, 0)
102	for {
103		m, raw, err := NewMapXmlReaderRaw(fh)
104		if err != nil && err != io.EOF {
105			return am, fmt.Errorf("error: %s - reading: %s", err.Error(), string(raw))
106		}
107		if len(m) > 0 {
108			am = append(am, m)
109		}
110		if err == io.EOF {
111			break
112		}
113	}
114	return am, nil
115}
116
117// NewMapsFromXmlFileRaw - creates an array of MapRaw from a file of XML values.
118// NOTE: the slice with the raw XML is clean with no extra capacity - unlike NewMapXmlReaderRaw().
119// It is slow at parsing a file from disk and is intended for relatively small utility files.
120func NewMapsFromXmlFileRaw(name string) ([]MapRaw, error) {
121	fi, err := os.Stat(name)
122	if err != nil {
123		return nil, err
124	}
125	if !fi.Mode().IsRegular() {
126		return nil, fmt.Errorf("file %s is not a regular file", name)
127	}
128
129	fh, err := os.Open(name)
130	if err != nil {
131		return nil, err
132	}
133	defer fh.Close()
134
135	am := make([]MapRaw, 0)
136	for {
137		mr := new(MapRaw)
138		mr.M, mr.R, err = NewMapXmlReaderRaw(fh)
139		if err != nil && err != io.EOF {
140			return am, fmt.Errorf("error: %s - reading: %s", err.Error(), string(mr.R))
141		}
142		if len(mr.M) > 0 {
143			am = append(am, *mr)
144		}
145		if err == io.EOF {
146			break
147		}
148	}
149	return am, nil
150}
151
152// ------------------------ Maps writing -------------------------
153// These are handy-dandy methods for dumping configuration data, etc.
154
155// JsonString - analogous to mv.Json()
156func (mvs Maps) JsonString(safeEncoding ...bool) (string, error) {
157	var s string
158	for _, v := range mvs {
159		j, err := v.Json()
160		if err != nil {
161			return s, err
162		}
163		s += string(j)
164	}
165	return s, nil
166}
167
168// JsonStringIndent - analogous to mv.JsonIndent()
169func (mvs Maps) JsonStringIndent(prefix, indent string, safeEncoding ...bool) (string, error) {
170	var s string
171	var haveFirst bool
172	for _, v := range mvs {
173		j, err := v.JsonIndent(prefix, indent)
174		if err != nil {
175			return s, err
176		}
177		if haveFirst {
178			s += "\n"
179		} else {
180			haveFirst = true
181		}
182		s += string(j)
183	}
184	return s, nil
185}
186
187// XmlString - analogous to mv.Xml()
188func (mvs Maps) XmlString() (string, error) {
189	var s string
190	for _, v := range mvs {
191		x, err := v.Xml()
192		if err != nil {
193			return s, err
194		}
195		s += string(x)
196	}
197	return s, nil
198}
199
200// XmlStringIndent - analogous to mv.XmlIndent()
201func (mvs Maps) XmlStringIndent(prefix, indent string) (string, error) {
202	var s string
203	for _, v := range mvs {
204		x, err := v.XmlIndent(prefix, indent)
205		if err != nil {
206			return s, err
207		}
208		s += string(x)
209	}
210	return s, nil
211}
212
213// JsonFile - write Maps to named file as JSON
214// Note: the file will be created, if necessary; if it exists it will be truncated.
215// If you need to append to a file, open it and use JsonWriter method.
216func (mvs Maps) JsonFile(file string, safeEncoding ...bool) error {
217	var encoding bool
218	if len(safeEncoding) == 1 {
219		encoding = safeEncoding[0]
220	}
221	s, err := mvs.JsonString(encoding)
222	if err != nil {
223		return err
224	}
225	fh, err := os.Create(file)
226	if err != nil {
227		return err
228	}
229	defer fh.Close()
230	fh.WriteString(s)
231	return nil
232}
233
234// JsonFileIndent - write Maps to named file as pretty JSON
235// Note: the file will be created, if necessary; if it exists it will be truncated.
236// If you need to append to a file, open it and use JsonIndentWriter method.
237func (mvs Maps) JsonFileIndent(file, prefix, indent string, safeEncoding ...bool) error {
238	var encoding bool
239	if len(safeEncoding) == 1 {
240		encoding = safeEncoding[0]
241	}
242	s, err := mvs.JsonStringIndent(prefix, indent, encoding)
243	if err != nil {
244		return err
245	}
246	fh, err := os.Create(file)
247	if err != nil {
248		return err
249	}
250	defer fh.Close()
251	fh.WriteString(s)
252	return nil
253}
254
255// XmlFile - write Maps to named file as XML
256// Note: the file will be created, if necessary; if it exists it will be truncated.
257// If you need to append to a file, open it and use XmlWriter method.
258func (mvs Maps) XmlFile(file string) error {
259	s, err := mvs.XmlString()
260	if err != nil {
261		return err
262	}
263	fh, err := os.Create(file)
264	if err != nil {
265		return err
266	}
267	defer fh.Close()
268	fh.WriteString(s)
269	return nil
270}
271
272// XmlFileIndent - write Maps to named file as pretty XML
273// Note: the file will be created,if necessary; if it exists it will be truncated.
274// If you need to append to a file, open it and use XmlIndentWriter method.
275func (mvs Maps) XmlFileIndent(file, prefix, indent string) error {
276	s, err := mvs.XmlStringIndent(prefix, indent)
277	if err != nil {
278		return err
279	}
280	fh, err := os.Create(file)
281	if err != nil {
282		return err
283	}
284	defer fh.Close()
285	fh.WriteString(s)
286	return nil
287}
288