@@ -4,18 +4,20 @@ import (
4
4
"bytes"
5
5
"fmt"
6
6
"reflect"
7
+ "strconv"
7
8
"strings"
8
9
"time"
9
10
"unicode"
10
11
)
11
12
12
13
type lineDecoder struct {
13
- sep byte // usually a |
14
- repeat byte // usually a ~
15
- dividers [3 ]byte // usually |, ^, &
16
- chars [4 ]byte // usually ^!\&
17
- escape byte // usually a \
18
- readSep bool
14
+ sep byte // usually a |
15
+ repeat byte // usually a ~
16
+ dividers [3 ]byte // usually |, ^, &
17
+ chars [4 ]byte // usually ^!\&
18
+ escape byte // usually a \
19
+ readSep bool
20
+ ignoreSep bool
19
21
20
22
unescaper * strings.Replacer
21
23
}
@@ -28,8 +30,9 @@ type Decoder struct {
28
30
29
31
// Decode options for the HL7 decoder.
30
32
type DecodeOption struct {
31
- ErrorZSegment bool // Error on an unknown Zxx segment when true.
32
- HeaderOnly bool // Only decode first segment, usually the header.
33
+ ErrorZSegment bool // Error on an unknown Zxx segment when true.
34
+ HeaderOnly bool // Only decode first segment, usually the header.
35
+ IgnoreFieldSep bool // Ignore field separator values in text fields.
33
36
}
34
37
35
38
// Create a new Decoder. A registry must be provided. Option is optional.
@@ -73,7 +76,7 @@ type variesFunc func() (reflect.Value, error)
73
76
74
77
var variesType = reflect .TypeFor [Varies ]()
75
78
76
- // SgmentError may be returned as part of the DecodeList result.
79
+ // SegmentError may be returned as part of the DecodeList result.
77
80
// This allows a single segment to be decoded poorly with error, while
78
81
// still decoding the rest of the message.
79
82
// This will not be returned as an error.
@@ -82,6 +85,21 @@ type SegmentError struct {
82
85
Segment any
83
86
}
84
87
88
+ func (e SegmentError ) Error () string {
89
+ sb := & strings.Builder {}
90
+ fmt .Fprintf (sb , "errors in segment %[1]T=%[1]v:" , e .Segment )
91
+ for _ , err := range e .ErrorList {
92
+ sb .WriteRune ('\n' )
93
+ sb .WriteRune ('\t' )
94
+ sb .WriteString (err .Error ())
95
+ }
96
+ return sb .String ()
97
+ }
98
+
99
+ func (e SegmentError ) Unwrap () []error {
100
+ return e .ErrorList
101
+ }
102
+
85
103
// Decode returns a list of segments without any grouping applied.
86
104
func (d * Decoder ) DecodeList (data []byte ) ([]any , error ) {
87
105
// Explicitly accept both CR and LF as new lines. Some systems do use \n, despite the spec.
@@ -103,7 +121,9 @@ func (d *Decoder) DecodeList(data []byte) ([]any, error) {
103
121
104
122
ret := []any {}
105
123
106
- ld := & lineDecoder {}
124
+ ld := & lineDecoder {
125
+ ignoreSep : d .opt .IgnoreFieldSep ,
126
+ }
107
127
for index , line := range lines {
108
128
lineNumber := index + 1
109
129
if len (line ) == 0 {
@@ -243,7 +263,18 @@ func (d *Decoder) DecodeList(data []byte) ([]any, error) {
243
263
}
244
264
err := ld .decodeSegmentList (p , f .tag , f .field , vfc )
245
265
if err != nil {
246
- err = fmt .Errorf ("line %d, %s.%s: %w" , lineNumber , SegmentName , f .name , err )
266
+ if v , ok := err .(* DecodeSegmentError ); ok && v .Line == 0 && len (v .SegmentName ) == 0 && len (v .FieldName ) == 0 {
267
+ v .Line = lineNumber
268
+ v .SegmentName = SegmentName
269
+ v .FieldName = f .name
270
+ } else {
271
+ err = & DecodeSegmentError {
272
+ Line : lineNumber ,
273
+ SegmentName : SegmentName ,
274
+ FieldName : f .name ,
275
+ Inner : err ,
276
+ }
277
+ }
247
278
segmentErrorList = append (segmentErrorList , err )
248
279
}
249
280
}
@@ -285,11 +316,68 @@ func (d *lineDecoder) decodeSegmentList(data []byte, t tag, rv reflect.Value, vf
285
316
}
286
317
err := d .decodeSegment (p , t , rv , 1 , len (parts ) > 1 , vfc )
287
318
if err != nil {
288
- return fmt .Errorf ("%s.%d: %w" , rv .Type ().String (), t .Order , err )
319
+ return & DecodeSegmentError {
320
+ FieldType : rv .Type ().String (),
321
+ Ordinal : t .Order ,
322
+ Inner : err ,
323
+ }
289
324
}
290
325
}
291
326
return nil
292
327
}
328
+
329
+ type DecodeSegmentError struct {
330
+ Line int
331
+ SegmentName string
332
+ FieldName string
333
+ FieldType string
334
+ Ordinal int32
335
+ Inner error
336
+ }
337
+
338
+ func (e * DecodeSegmentError ) Error () string {
339
+ sb := & strings.Builder {}
340
+ if e .Line > 0 {
341
+ sb .WriteString ("line " )
342
+ sb .WriteString (strconv .FormatInt (int64 (e .Line ), 10 ))
343
+ sb .WriteString (", " )
344
+ }
345
+ if len (e .SegmentName ) > 0 {
346
+ sb .WriteString (e .SegmentName )
347
+ sb .WriteString ("." )
348
+ }
349
+ if len (e .FieldName ) > 0 {
350
+ sb .WriteString (e .FieldName )
351
+ }
352
+ if len (e .FieldType ) > 0 {
353
+ sb .WriteRune ('(' )
354
+ sb .WriteString (e .FieldType )
355
+ sb .WriteRune (')' )
356
+ }
357
+ if e .Ordinal > 0 {
358
+ sb .WriteRune ('[' )
359
+ sb .WriteString (strconv .FormatInt (int64 (e .Ordinal ), 10 ))
360
+ sb .WriteRune (']' )
361
+ }
362
+ if e .Inner != nil {
363
+ sb .WriteString (": " )
364
+ sb .WriteString (e .Inner .Error ())
365
+ }
366
+ return sb .String ()
367
+ }
368
+ func (e * DecodeSegmentError ) Unwrap () error {
369
+ return e .Inner
370
+ }
371
+
372
+ type DecodeDataError struct {
373
+ Tag string
374
+ Value string
375
+ }
376
+
377
+ func (e * DecodeDataError ) Error () string {
378
+ return fmt .Sprintf ("%s contains an escape character %s; data may be malformed, invalid type, or contain a bug" , e .Tag , e .Value )
379
+ }
380
+
293
381
func (d * lineDecoder ) decodeSegment (data []byte , t tag , rv reflect.Value , level int , mustBeSlice bool , vfc variesFunc ) error {
294
382
type field struct {
295
383
tag tag
@@ -407,7 +495,13 @@ func (d *lineDecoder) decodeSegment(data []byte, t tag, rv reflect.Value, level
407
495
f := ff [i ]
408
496
err := d .decodeSegment (p , f .tag , f .field , level + 1 , false , vfc )
409
497
if err != nil {
410
- return fmt .Errorf ("%s-%s.%d: %w" , SegmentName , f .field .Type ().String (), f .tag .Order , err )
498
+ return & DecodeSegmentError {
499
+ SegmentName : SegmentName ,
500
+ FieldType : f .field .Type ().String (),
501
+ FieldName : f .tag .Name ,
502
+ Ordinal : f .tag .Order ,
503
+ Inner : err ,
504
+ }
411
505
}
412
506
}
413
507
return nil
@@ -422,17 +516,21 @@ func (d *lineDecoder) decodeSegment(data []byte, t tag, rv reflect.Value, level
422
516
}
423
517
case reflect .String :
424
518
c1 , c2 , c3 := d .dividers [0 ], d .dividers [1 ], d .dividers [2 ]
425
- for _ , b := range data {
426
- switch b {
427
- case c1 , c2 , c3 :
428
- return fmt .Errorf ("%s contains an escape character %s; data may be malformed, invalid type, or contain a bug" , t .Name , data )
519
+ if ! d .ignoreSep {
520
+ for _ , b := range data {
521
+ switch b {
522
+ case c1 , c2 , c3 :
523
+ return & DecodeDataError {
524
+ Tag : t .Name ,
525
+ Value : string (data ),
526
+ }
527
+ }
429
528
}
430
529
}
431
530
rv .SetString (d .decodeByte (data , t ))
432
531
return nil
433
532
}
434
533
}
435
-
436
534
func (d * lineDecoder ) decodeByte (v []byte , t tag ) string {
437
535
if t .NoEscape {
438
536
return string (v )
@@ -549,8 +647,5 @@ loop:
549
647
in = dt [:14 ]
550
648
t , err = time .Parse ("20060102150405" , in )
551
649
}
552
- if err != nil {
553
- err = fmt .Errorf ("field %q : %w" , dt , err )
554
- }
555
650
return t , err
556
651
}
0 commit comments