2022-08-01 00:28:34 +00:00
|
|
|
package yqlib
|
|
|
|
|
|
|
|
import (
|
|
|
|
"encoding/csv"
|
|
|
|
"errors"
|
|
|
|
"io"
|
|
|
|
|
2022-10-08 02:12:12 +00:00
|
|
|
"github.com/dimchansky/utfbom"
|
2022-08-01 00:28:34 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type csvObjectDecoder struct {
|
|
|
|
separator rune
|
|
|
|
reader csv.Reader
|
|
|
|
finished bool
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewCSVObjectDecoder(separator rune) Decoder {
|
|
|
|
return &csvObjectDecoder{separator: separator}
|
|
|
|
}
|
|
|
|
|
2022-10-28 03:16:46 +00:00
|
|
|
func (dec *csvObjectDecoder) Init(reader io.Reader) error {
|
2022-10-08 02:12:12 +00:00
|
|
|
cleanReader, enc := utfbom.Skip(reader)
|
|
|
|
log.Debugf("Detected encoding: %s\n", enc)
|
|
|
|
dec.reader = *csv.NewReader(cleanReader)
|
2022-08-01 00:28:34 +00:00
|
|
|
dec.reader.Comma = dec.separator
|
|
|
|
dec.finished = false
|
2022-10-28 03:16:46 +00:00
|
|
|
return nil
|
2022-08-01 00:28:34 +00:00
|
|
|
}
|
|
|
|
|
2023-04-03 07:27:41 +00:00
|
|
|
func (dec *csvObjectDecoder) convertToNode(content string) *CandidateNode {
|
2022-08-01 00:28:34 +00:00
|
|
|
node, err := parseSnippet(content)
|
|
|
|
if err != nil {
|
|
|
|
return createScalarNode(content, content)
|
|
|
|
}
|
|
|
|
return node
|
|
|
|
}
|
|
|
|
|
2023-04-03 07:27:41 +00:00
|
|
|
func (dec *csvObjectDecoder) createObject(headerRow []string, contentRow []string) *CandidateNode {
|
|
|
|
objectNode := &CandidateNode{Kind: MappingNode, Tag: "!!map"}
|
2022-08-01 00:28:34 +00:00
|
|
|
|
|
|
|
for i, header := range headerRow {
|
2023-05-09 03:51:21 +00:00
|
|
|
objectNode.AddKeyValueChild(createScalarNode(header, header), dec.convertToNode(contentRow[i]))
|
2022-08-01 00:28:34 +00:00
|
|
|
}
|
|
|
|
return objectNode
|
|
|
|
}
|
|
|
|
|
2022-10-28 03:16:46 +00:00
|
|
|
func (dec *csvObjectDecoder) Decode() (*CandidateNode, error) {
|
2022-08-01 00:28:34 +00:00
|
|
|
if dec.finished {
|
2022-10-28 03:16:46 +00:00
|
|
|
return nil, io.EOF
|
2022-08-01 00:28:34 +00:00
|
|
|
}
|
|
|
|
headerRow, err := dec.reader.Read()
|
|
|
|
log.Debugf(": headerRow%v", headerRow)
|
|
|
|
if err != nil {
|
2022-10-28 03:16:46 +00:00
|
|
|
return nil, err
|
2022-08-01 00:28:34 +00:00
|
|
|
}
|
|
|
|
|
2023-04-03 07:27:41 +00:00
|
|
|
rootArray := &CandidateNode{Kind: SequenceNode, Tag: "!!seq"}
|
2022-08-01 00:28:34 +00:00
|
|
|
|
|
|
|
contentRow, err := dec.reader.Read()
|
|
|
|
|
|
|
|
for err == nil && len(contentRow) > 0 {
|
|
|
|
log.Debugf("Adding contentRow: %v", contentRow)
|
2023-05-09 03:51:21 +00:00
|
|
|
rootArray.AddChild(dec.createObject(headerRow, contentRow))
|
2022-08-01 00:28:34 +00:00
|
|
|
contentRow, err = dec.reader.Read()
|
|
|
|
log.Debugf("Read next contentRow: %v, %v", contentRow, err)
|
|
|
|
}
|
|
|
|
if !errors.Is(err, io.EOF) {
|
2022-10-28 03:16:46 +00:00
|
|
|
return nil, err
|
2022-08-01 00:28:34 +00:00
|
|
|
}
|
|
|
|
|
2022-10-28 03:16:46 +00:00
|
|
|
return &CandidateNode{
|
2023-04-03 07:27:41 +00:00
|
|
|
Kind: DocumentNode,
|
|
|
|
Content: []*CandidateNode{rootArray},
|
2022-10-28 03:16:46 +00:00
|
|
|
}, nil
|
2022-08-01 00:28:34 +00:00
|
|
|
}
|