9
9
"unicode"
10
10
)
11
11
12
- type decoder struct {
12
+ type lineDecoder struct {
13
13
sep byte // usually a |
14
14
repeat byte // usually a ~
15
15
dividers [3 ]byte // usually |, ^, &
@@ -18,26 +18,53 @@ type decoder struct {
18
18
readSep bool
19
19
20
20
unescaper * strings.Replacer
21
+
22
+ opt DecodeOption
21
23
}
22
24
23
- func (d * decoder ) setupUnescaper () {
24
- d .unescaper = strings .NewReplacer (
25
- string ([]byte {d .escape , 'F' , d .escape }), string (d .sep ),
26
- string ([]byte {d .escape , 'S' , d .escape }), string (d .chars [0 ]),
27
- string ([]byte {d .escape , 'R' , d .escape }), string (d .chars [1 ]),
28
- string ([]byte {d .escape , 'E' , d .escape }), string (d .chars [2 ]),
29
- string ([]byte {d .escape , 'T' , d .escape }), string (d .chars [3 ]),
30
- )
25
+ // Decode bytes into HL7 structures.
26
+ type Decoder struct {
27
+ registry Registry
28
+ opt DecodeOption
31
29
}
32
30
33
- var timeType reflect.Type = reflect .TypeOf (time.Time {})
31
+ // Decode options for the HL7 decoder.
32
+ type DecodeOption struct {
33
+ ErrorZSegment bool // Error on an unknown Zxx segment when true.
34
+ }
35
+
36
+ // Create a new Decoder. A registry must be provided. Option is optional.
37
+ func NewDecoder (registry Registry , opt * DecodeOption ) * Decoder {
38
+ d := & Decoder {
39
+ registry : registry ,
40
+ }
41
+ if opt != nil {
42
+ d .opt = * opt
43
+ }
34
44
35
- type UnmarshalOption struct {
36
- Registry Registry
37
- ErrorZSegment bool // Error on an unknown Zxx segment.
45
+ return d
38
46
}
39
47
40
- func Unmarshal (data []byte , opt UnmarshalOption ) ([]any , error ) {
48
+ // Decode takes an hl7 message and returns a final trigger with all segments grouped.
49
+ func (d * Decoder ) Decode (data []byte ) (any , error ) {
50
+ list , err := d .DecodeList (data )
51
+ if err != nil {
52
+ return nil , fmt .Errorf ("segment list: %w" , err )
53
+ }
54
+ g , err := d .DecodeGroup (list )
55
+ if err != nil {
56
+ return nil , fmt .Errorf ("trigger group: %w" , err )
57
+ }
58
+ return g , nil
59
+ }
60
+
61
+ // Group a list of elements into trigger groupings.
62
+ func (d * Decoder ) DecodeGroup (list []any ) (any , error ) {
63
+ return group (list , d .registry )
64
+ }
65
+
66
+ // Decode returns a list of segments without any grouping applied.
67
+ func (d * Decoder ) DecodeList (data []byte ) ([]any , error ) {
41
68
// Explicitly accept both CR and LF as new lines. Some systems do use \n, despite the spec.
42
69
lines := bytes .FieldsFunc (data , func (r rune ) bool {
43
70
switch r {
@@ -57,15 +84,15 @@ func Unmarshal(data []byte, opt UnmarshalOption) ([]any, error) {
57
84
58
85
ret := []any {}
59
86
60
- d := & decoder {}
61
- segmentRegistry := opt . Registry .Segment ()
87
+ ld := & lineDecoder {}
88
+ segmentRegistry := d . registry .Segment ()
62
89
for index , line := range lines {
63
90
lineNumber := index + 1
64
91
if len (line ) == 0 {
65
92
continue
66
93
}
67
94
68
- segTypeName , n := d .getID (line )
95
+ segTypeName , n := ld .getID (line )
69
96
remain := line [n :]
70
97
if len (segTypeName ) == 0 {
71
98
return nil , fmt .Errorf ("line %d: missing segment type" , lineNumber )
@@ -74,7 +101,7 @@ func Unmarshal(data []byte, opt UnmarshalOption) ([]any, error) {
74
101
seg , ok := segmentRegistry [segTypeName ]
75
102
if ! ok {
76
103
isZ := len (segTypeName ) > 0 && segTypeName [0 ] == 'Z'
77
- if isZ && ! opt .ErrorZSegment {
104
+ if isZ && ! d . opt .ErrorZSegment {
78
105
continue
79
106
}
80
107
return nil , fmt .Errorf ("line %d: unknown segment type %q" , lineNumber , segTypeName )
@@ -139,33 +166,33 @@ func Unmarshal(data []byte, opt UnmarshalOption) ([]any, error) {
139
166
if len (remain ) < 5 {
140
167
return nil , fmt .Errorf ("missing format delims" )
141
168
}
142
- d .sep = remain [0 ]
143
- copy (d .chars [:], remain [1 :5 ])
169
+ ld .sep = remain [0 ]
170
+ copy (ld .chars [:], remain [1 :5 ])
144
171
145
- d .dividers = [3 ]byte {d .sep , d .chars [0 ], d .chars [3 ]}
146
- d .repeat = d .chars [1 ]
147
- d .escape = d .chars [2 ]
148
- d .setupUnescaper ()
149
- d .readSep = true
172
+ ld .dividers = [3 ]byte {ld .sep , ld .chars [0 ], ld .chars [3 ]}
173
+ ld .repeat = ld .chars [1 ]
174
+ ld .escape = ld .chars [2 ]
175
+ ld .setupUnescaper ()
176
+ ld .readSep = true
150
177
151
178
remain = remain [5 :]
152
179
offset = 2
153
180
}
154
181
155
- if d .sep == 0 {
182
+ if ld .sep == 0 {
156
183
return nil , fmt .Errorf ("missing sep prior to field" )
157
184
}
158
185
159
- parts := bytes .Split (remain , []byte {d .sep })
186
+ parts := bytes .Split (remain , []byte {ld .sep })
160
187
161
188
ff := make ([]field , SegmentSize )
162
189
for _ , f := range fieldList {
163
190
if f .tag .FieldSep {
164
- f .field .SetString (string (d .sep ))
191
+ f .field .SetString (string (ld .sep ))
165
192
continue
166
193
}
167
194
if f .tag .FieldChars {
168
- f .field .SetString (string (d .chars [:]))
195
+ f .field .SetString (string (ld .chars [:]))
169
196
continue
170
197
}
171
198
index := int (f .tag .Order ) - offset
@@ -189,19 +216,30 @@ func Unmarshal(data []byte, opt UnmarshalOption) ([]any, error) {
189
216
if f .tag .Child {
190
217
continue
191
218
}
192
- err := d .decodeSegmentList (p , f .tag , f .field )
219
+ err := ld .decodeSegmentList (p , f .tag , f .field )
193
220
if err != nil {
194
221
return ret , fmt .Errorf ("line %d, %s.%s: %w" , lineNumber , SegmentName , f .name , err )
195
222
}
196
223
}
197
224
198
225
ret = append (ret , rv .Interface ())
199
226
}
200
-
201
227
return ret , nil
202
228
}
203
229
204
- func (d * decoder ) decodeSegmentList (data []byte , t tag , rv reflect.Value ) error {
230
+ func (d * lineDecoder ) setupUnescaper () {
231
+ d .unescaper = strings .NewReplacer (
232
+ string ([]byte {d .escape , 'F' , d .escape }), string (d .sep ),
233
+ string ([]byte {d .escape , 'S' , d .escape }), string (d .chars [0 ]),
234
+ string ([]byte {d .escape , 'R' , d .escape }), string (d .chars [1 ]),
235
+ string ([]byte {d .escape , 'E' , d .escape }), string (d .chars [2 ]),
236
+ string ([]byte {d .escape , 'T' , d .escape }), string (d .chars [3 ]),
237
+ )
238
+ }
239
+
240
+ var timeType reflect.Type = reflect .TypeOf (time.Time {})
241
+
242
+ func (d * lineDecoder ) decodeSegmentList (data []byte , t tag , rv reflect.Value ) error {
205
243
if len (data ) == 0 {
206
244
return nil
207
245
}
@@ -217,7 +255,7 @@ func (d *decoder) decodeSegmentList(data []byte, t tag, rv reflect.Value) error
217
255
}
218
256
return nil
219
257
}
220
- func (d * decoder ) decodeSegment (data []byte , t tag , rv reflect.Value , level int , mustBeSlice bool ) error {
258
+ func (d * lineDecoder ) decodeSegment (data []byte , t tag , rv reflect.Value , level int , mustBeSlice bool ) error {
221
259
type field struct {
222
260
tag tag
223
261
field reflect.Value
@@ -331,7 +369,7 @@ func (d *decoder) decodeSegment(data []byte, t tag, rv reflect.Value, level int,
331
369
return nil
332
370
case timeType :
333
371
v := d .decodeByte (data , t )
334
- t , err := parseDateTime (v )
372
+ t , err := d . parseDateTime (v )
335
373
if err != nil {
336
374
return err
337
375
}
@@ -351,20 +389,20 @@ func (d *decoder) decodeSegment(data []byte, t tag, rv reflect.Value, level int,
351
389
}
352
390
}
353
391
354
- func (d * decoder ) decodeByte (v []byte , t tag ) string {
392
+ func (d * lineDecoder ) decodeByte (v []byte , t tag ) string {
355
393
if t .NoEscape {
356
394
return string (v )
357
395
}
358
396
return d .unescaper .Replace (string (v ))
359
397
}
360
- func (d * decoder ) decodeString (v string , t tag ) string {
398
+ func (d * lineDecoder ) decodeString (v string , t tag ) string {
361
399
if t .NoEscape {
362
400
return v
363
401
}
364
402
return d .unescaper .Replace (v )
365
403
}
366
404
367
- func (d * decoder ) getID (data []byte ) (string , int ) {
405
+ func (d * lineDecoder ) getID (data []byte ) (string , int ) {
368
406
if d .readSep {
369
407
v , _ , _ := bytes .Cut (data , []byte {d .sep })
370
408
return string (v ), len (v )
@@ -378,7 +416,7 @@ func (d *decoder) getID(data []byte) (string, int) {
378
416
return string (data ), len (data )
379
417
}
380
418
381
- func parseDateTime (dt string ) (time.Time , error ) {
419
+ func ( d * lineDecoder ) parseDateTime (dt string ) (time.Time , error ) {
382
420
var zoneIndex int
383
421
for i , r := range dt {
384
422
switch {
0 commit comments